【Docker】doceker-composeを本番環境と開発環境で分ける

# 本番環境用のdocker-compose
従来、コンテナの作成は開発環境でのみ行われることが多かったが、これを本番環境でも利用することで、開発環境と同一の環境での運用を可能とし、サービスの冗長性を高め、環境の違いによる不具合を軽減する事例が増えているそうだ。

コンテナを構築するための情報が記載されているファイルがdocker-compose.ymlである。そしてこのファイルは、本番環境と開発環境で使い分けが可能である。

今回実施する内容は、使い分けというよりは、本番環境用にファイルの内容を上書きするという言い方が正しいかも知れない。具体的にはdocker-compose.ymlとは別に、docker-compose-prod.ymlという名称のファイルを作成し、コンテナの構築時に以下のように-fオプションで参照するdocker-composeファイルを指定する方法である。
```
docker-compose -f docker-compose-prod.yml up
```
ここでは、以下の記事に書かれているコードを元に、環境ごとにdocker-composeを分けていく。尚、プロキシとしてNginxを使っているので、それも踏まえたうえで行っていきたい。

https://qiita.com/sho_U/items/a1b5e4ddf13f3c42a722


ディレクトリ構成は、アプリケーションのディレクトリ（ここではapp_nameとしている）の配下に以下のファイル、およびフォルダを作成する。

```
Dockerfile
docker-compose.yml
docker-compose-prod.yml

config
└ puma.rb

nginx_docker_prod
├ Dockerfile
└ nginx.conf

nginx_docker_dev
├ Dockerfile
└ nginx.conf
```

# Dockerfile
Dockerfileについては、今回は二つ作成する必要はなく、以下のものを開発環境と本番環境で共通して使用する。

```dockerfile:Dockerfile
FROM ruby:3.0.0

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs \
  && apt-get update -qq \
  && apt-get -y install \
  yarn \
  nodejs \
  imagemagick \
  default-mysql-server \
  default-mysql-client

WORKDIR /app_name

COPY Gemfile /app_name/Gemfile
COPY Gemfile.lock /app_name/Gemfile.lock

RUN gem install bundler
RUN bundle install

RUN mkdir -p tmp/sockets
```
# docker-compose.yml
開発時に使うdocker-compose.ymlは以下の通り設定する。本番環境との違いについてはコメントアウトで記載している。
```yml:docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
    command: bundle exec puma -C config/puma.rb
    volumes:
      - .:/app_name
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
      - log-data:/app_name/log
    networks:
      - app_name-network
    depends_on:
       - db
#　↓ mysqlでDBコンテナを立てるための情報
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: app_name_development
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - app_name-network

  web:
    build:
      context: ./nginx_docker_dev
 #　　↑ 開発環境用に作ったディレクトリでnginxによるコンテナを構築する。
    volumes:
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
    ports:
      - 80:80
    depends_on:
      - app
    networks:
      - app_name-network
volumes:
  public-data:

  tmp-data:
  log-data:
  db-data:

networks:
  app_name-network:
    external: true
```


# docker-compose-prod.yml
本番環境用のdocker-compose-prod.ymlが以下の通り。開発環境との違いについてはコメントアウトで記載している。

```yml:docker-compose-prod.yml
version: '3'
services:
  app:
    build:
      context: .
    command: bundle exec puma -C config/puma.rb -e production
    # ↑ pumaの起動時に本番環境を指定している。
    volumes:
      - .:/app_name
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
      - log-data:/app_name/log
    networks:
      - app_name-network

#　今回、本番環境について、EC2へのデプロイとRDSの使用を前提としているため、
#  本番環境用ではDBコンテナの記述は無し。

  web:
    build:
      context: ./nginx_docker_prod
    #　↑ 本番環境用に作ったディレクトリでnginxによるコンテナを構築する。
    volumes:
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
    ports:
      - 80:80
    depends_on:
      - app
    networks:
      - app_name-network
volumes:
  public-data:

  tmp-data:
  log-data:
  db-data:

networks:
  riskbuster-network:
    external: true
```

# nginx_docker_dev ディレクトリ
開発用のnginxの構築のためにnginx_docker_devディレクトリを作成する。
このディレクトリには、Dockerfileとnginx.confの二つのファイルを用意する。
内容はそれぞれ以下の通りとする。
* Dockerfile
```dockerfile:Dockerfile
FROM nginx:1.15.8

RUN rm -f /etc/nginx/conf.d/*

ADD nginx.conf /etc/nginx/conf.d/app_name.conf

CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

```

* nginx.conf
```config:nginx.conf
upstream app_name {
  server unix:///app_name/tmp/sockets/puma.sock;
}

server {
  listen 80;
    server_name localhost;
#   ↑ nginxの既定のポート番号である80番ポートを指定して、
#     server_nameをlocalhostとしている。

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /app_name/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @app_name;
  keepalive_timeout 5;

  location @app_name {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://app_name;
  }
}
```

# nginx_docker_prod ディレクトリ
また同様に、本番用のnginxコンテナを構築するためにnginx_docker_prodディレクトリを作成する。このディレクトリにも、Dockerfileとnginx.confの二つのファイルを用意する。

* Dockerfile
上記のDockerfileの内容と同様。

* nginx.conf
```config:nginx.conf
upstream app_name {
  server unix:///app_name/tmp/sockets/puma.sock;
}

server {
  listen 80;
    server_name ××.×××.×××.×××;
#　　↑ EC2の固定IPを指定
  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /app_name/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @app_name;
  keepalive_timeout 5;

  location @app_name {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://app_name;
  }
}
```
# コンテナの立ち上げ

環境に応じて以下のコマンドを使い分けて実行し、コンテナの構築を行う。

* 開発環境
```
$ docker-compose build
$ docker-compose up -d
```

* 本番環境
```
$ docker-compose -f docker-compose-prod.yml build
$ docker-compose -f docker-compose-prod.yml up -d
```
以上。

# 参考

https://qiita.com/sho_U/items/a1b5e4ddf13f3c42a722