RailsアプリとnginxのDockerイメージにalpineを使用してdocker-composeで管理する

# はじめに
Railsアプリとnginxを、docker-composeで管理する方法を紹介します。
イメージは軽量なalpineを使用してしまいます。

この方法では事前にRailsアプリを作り、後からDockerに移す必要があります。


# Railsバージョン
- 2.5.2

# 使用イメージ
- ruby:2.6.2-alpine3.9
- nginx:1.15.8-alpine

# ディレクトリ構成
```
<Railsアプリ>
 |- .env
 |- Dockerfile
 |- docker-compose.yml
 |- nginx.conf
 |- (Railsアプリの各フォルダー、各ファイル)
```

# 各ファイルの中身
## envファイル
- データベースの設定や、ポートを環境変数で指定しています。
- Railsアプリ内の設定は環境変数を使用するようにして、envファイルで管理するようにすると良いです。

``` :.env
# Rails
RAILS_ENV=development
RAILS_MASTER_KEY=<マスターキー>
# Database
DATABASE_NAME=hogehoge
DATABASE_HOST=example.com
DATABASE_PORT=5432
DATABASE_USERNAME=user
DATABASE_PASSWORD=password
# nginx
HTTP_PORT=80
```
## データベースの設定
- 環境変数から設定しています。

```:config/database.yml
# PostgreSQL. Versions 9.1 and up are supported.
#
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: <%= ENV['DATABASE_NAME'] %>
  host: <%= ENV['DATABASE_HOST'] %>
  port: <%= ENV['DATABASE_PORT'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

development:
  <<: *default
  database: hogehoge_development
  host: <%= ENV['DATABASE_HOST'] %>
  port: <%= ENV['DATABASE_PORT'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

test:
  <<: *default
  database: hogehoge_test
  host: <%= ENV['DATABASE_HOST'] %>
  port: <%= ENV['DATABASE_PORT'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

production:
  <<: *default
  database: <%= ENV['DATABASE_NAME'] %>
  host: <%= ENV['DATABASE_HOST'] %>
  port: <%= ENV['DATABASE_PORT'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
```

## Rubyのイメージ
- ホストのユーザのidによっては、railsユーザに権限がない状態になるのでidには注意してください。

```:Dockerfile
FROM ruby:2.6.2-alpine3.9

ENV TZ=Asia/Tokyo \
    RAILS_ENV=development \
    RAILS_MASTER_KEY="" \
    RAILS_SERVE_STATIC_FILES=false

RUN apk add --no-cache build-base libxml2-dev libxslt-dev tzdata postgresql-dev yarn ca-certificates

RUN mkdir -p /data
WORKDIR data

RUN adduser -D -u 1000 rails
USER rails

CMD tail -f /dev/null
```

## docker-composeの中身
```:docker-compose.yml
ersion: '3'
services:
  rails:
    build:
     context: .
     dockerfile: Dockerfile
    volumes:
      - .:/data/
    env_file: .env
    entrypoint: sh -c 'bundle install --path vendor/bundle && yarn install && bin/rails s -b 0.0.0.0'
    restart: always

  nginx:
    image: nginx:1.15.8-alpine
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - .:/data/
    ports:
      - $HTTP_PORT:80
    depends_on:
      - rails
    links:
      - rails:puma
    restart: always
```

## nginxの設定
- ログはlog/nginx-access.logとlog/nginx-error.logとして出力しています。
- アクセスログのフォーマットはltsv形式にしています。

```:nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format ltsv 'time:$time_iso8601\t'
                    'remote_addr:$remote_addr\t'
                    'request_method:$request_method\t'
                    'request_length:$request_length\t'
                    'request_uri:$request_uri\t'
                    'https:$https\t'
                    'uri:$uri\t'
                    'query_string:$query_string\t'
                    'status:$status\t'
                    'bytes_sent:$bytes_sent\t'
                    'body_bytes_sent:$body_bytes_sent\t'
                    'referer:$http_referer\t'
                    'useragent:$http_user_agent\t'
                    'forwardedfor:$http_x_forwarded_for\t'
                    'request_time:$request_time\t'
                    'upstream_response_time:$upstream_response_time';

    access_log  /var/log/nginx/access.log ltsv;

    sendfile        on;
    tcp_nopush     on;

    server_tokens off;

    keepalive_timeout  65;

    #gzip  on;

    upstream puma {
        server puma:3000;
     }

    server {
        listen 80;
        charset utf-8;

        access_log /data/log/nginx-access.log ltsv;
        error_log  /data/log/nginx-error.log;

        root      /data/public;

        try_files $uri/index.html $uri @puma;

        # puma
        location @puma {
            proxy_pass http://puma;
            proxy_redirect off;
            proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}
```

# 使い方
### 起動
```
$ docker-compose up -d
```
### 停止
```
$ docker-compose down
```

### コンテナに入る
```
# railsコンテナ
$ docker-compose exec rails sh

# nginxコンテナ
$ docker-compose exec nginx sh
```

## 最後に
Railsアプリとalpineをそれぞれalpineベースのイメージで動かし、docker-composeで管理する方法でした。