Dockerを使いこなすのであれば、「Docker Compose」を避けて通ることはできません。
Docker Composeを使うことで、Dockerでの環境構築や管理がとっても楽になるからです。
ちなみに、前回解説した「Dockerネットワーク」も、自分でわざわざ作る必要がなくなります。
今回は、Docker Composeの使い方を覚えるためにも、「Rails」「MySQL」「Nginx」のコンテナをそれぞれ立ち上げ、コンテナ間で通信できるようにします。
「Rails」と「Nginx」をまとめて1つのコンテナにしている記事は多いのですが、別々に動かして連携させる記事は少なかったので、参考になると思いますよ!
もくじ
Docker Composeとは
Docker Composeとは、複数のDockerコンテナからなるアプリケーションを定義し、操作するためのツールです。
Dockerイメージの作成方法やコンテナ起動時の設定などを「docker-compose.yml」に記述することで、「docker compose」コマンドでまとめて操作できるようになります。
Docker Composeのメリット
- コンテナ間の通信ができる(Dockerネットワークを作成しなくていい)
- 実行コマンドが簡潔になる
- ファイルで管理するため、インフラ構成の可視化、バージョン管理が可能
Docker Composeを使うことで、Dockerネットワークを自分で作らなくても、「ディレクトリ名_default」というネットワークを自動で作成してくれます。
また、「docker run」コマンドのやたら長いオプションも「docker-compose.yml」に記述できるようになり、実行コマンド自体が簡潔になります。
これにより、イメージを作成する「docker build」や、コンテナを起動する「docker run」などのコマンドを、コンテナの数だけ実行するなんてこともなくなるのです。
また、「docker-compose.yml」はファイルなので、コンテナ構成を可視化でき、バージョン管理もできるようになります。
Docker ComposeとDockerfileの違い
「Docker Compose」と「Dockerfile」は、似ているようで少し役割が違います。
- 「Docker Compose」…Dockerイメージのビルドやコンテナの作成と起動方法、ネットワークを使った構成管理
- 「Dockerfile」…Dockerイメージの作成手順
「docker-compose.yml」にはイメージのビルド方法やコンテナ起動方法などを書き、「Dockerfile」にはイメージの作成手順を書くようになっているのです。
つまり、今後は「docker-compose.yml」と「Dockerfile」を使って、コンテナ環境を構築していくことになります。
docker-compose.ymlの書き方
「docker-compose.yml」の書き方は、そこまで難しくありません。
「YAML(ヤムル)」と呼ばれる形式を使って、誰でも簡単に記述できるようになっているからです。
基本的には、1つの項目に対して値を設定する「key:value」の関係になっています。プログラミングの連想配列(ハッシュ)とほとんど同じですね。
以下は、今回使用する「docker-compose.yml」になります。
version: '3'
services:
app:
build: rails
environment:
APP_DATABASE_HOST: db
APP_DATABASE: app_development
APP_DATABASE_USER: root
APP_DATABASE_PASSWORD: root
depends_on:
- db
db:
build: mysql
environment:
MYSQL_ROOT_PASSWORD: root
web:
build: nginx
ports:
- 80:80
volumes:
- ./nginx/log:/var/log/nginx
volumes_from:
- app
depends_on:
- app
version
「version」では、Docker Composeで使用するバージョンを指定します。
ここでは「3」を指定しています。
services
「services」では、アプリケーションを構成するためのサービスを設定します。
ここでは、「app」「db」「web」という3つの構成になっています。
これらのサービスごとにビルドされ、各設定に従ってコンテナが作成、起動する仕組みになっています。
build
「build」では、Dockerfileの場所を指定します。
ここでは、以下のような構成を想定しています。
docker
├── docker-compose.yml
├── rails
│ └── Dockerfile
├── mysql
│ └── Dockerfile
└── nginx
└── Dockerfile
environment
「environment」では、コンテナ内で利用する環境変数を設定します。
ここでは、データベースの定義に関する情報をあらかじめ設定しています。
depends_on
「depends_on」では、サービス同士の依存関係を設定します。
この設定により、コンテナの起動タイミングが変わります。
ここでは、「db」サービスが起動したあとに「app」サービスが起動するようになっています。
ports
「ports」では、ホストマシンとゲストマシンのポートフォワードを設定します。
これは「docker run -p」と同様の設定です。

volumes
「volumes」では、マウントする(利用できるように認識させる)ための設定をします。
ここでは、ホストマシンの指定されたディレクトリに、コンテナ内のNginxのログファイルをマウントしています。
volumes_from
「volumes_from」では、コンテナ間でマウントするための設定です。
ここでは、「app」サービスのコンテナを「web」サービスのコンテナにマウントするよう設定しています。
Docker Composeの使い方(Rails、MySQL、Nginxの環境構築)
さきほど紹介した「docker-compose.yml」を使って、Rails、MySQL、Nginxのコンテナを起動し、コンテナ間で通信してみます。
ここでは、以下のようなディレクトリ構成を想定して進めていきます。
docker
├── docker-compose.yml
├── rails
│ ├── Dockerfile
│ ├── Gemfile
│ ├── Gemfile.lock
│ └── config
│ ├── database.yml
│ └── puma.rb
├── mysql
│ ├── Dockerfile
│ └── app.cnf
└── nginx
├── Dockerfile
└── nginx.conf
作業の流れはこんな感じです。
- 各サービスのビルド準備
- 各サービスのビルド
- 各サービスからコンテナを起動
- Rails用のデータベース作成
MySQLビルドの準備
MySQLのビルドに必要な「Dockerfile」と「app.cnf」を準備します。
docker
└── mysql
├── Dockerfile
└── app.cnf
ここではMySQL8.0の認証方式を変更しています。詳しくはコメントを読んでください。
# MySQLをインストール
FROM mysql:8.0
# 「Authentication plugin 'caching_sha2_password' cannot be loaded:」とエラーが発生するため
# Mysqlの認証方式を「caching_sha2_password」から「mysql_native_password」に変更
COPY app.cnf /etc/mysql/conf.d/app.cnf
[mysqld]
default_authentication_plugin= mysql_native_password
Railsビルドの準備
Railsのビルドに必要な「Dockerfile」や「Gemfile」、「database.yml」などの設定ファイルを準備します。
docker
└── rails
├── Dockerfile
├── Gemfile
├── Gemfile.lock
└── config
├── database.yml
└── puma.rb
「Dockerfile」は、コメントを読んでもらえれば内容を理解できると思います。
# Rubyをインストール
FROM ruby:2.7
# Node.jsをインストール
RUN curl -sL RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && \
apt install nodejs
# 公式では以下のコマンドを推奨しているが、Node.jsのバージョンが低くてBootstrapが使えない
# RUN apt-get update -qq && apt-get install -y nodejs
# Yarnをインストール
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 && \
apt update && apt install yarn
# 環境変数を設定
ENV APP_HOME /app
# ディレクトリの作成と移動
WORKDIR $APP_HOME
# ホストのGemfileなどをコンテナへコピー
COPY Gemfile $APP_HOME/Gemfile
COPY Gemfile.lock $APP_HOME/Gemfile.lock
# BundlerでGemをインストール
RUN bundle install
# Railsアプリを作成(既存のアプリをマウントする場合は不要)
RUN rails new . -d mysql --skip-bundle || bundle update
# Webpackerをインストール
RUN rails webpacker:install
# 設定ファイル書き換え(既存のアプリをマウントする場合は不要)
COPY config $APP_HOME/config
# マウントできるように公開
VOLUME $APP_HOME/public
VOLUME $APP_HOME/tmp
# コンテナ起動時にRailsサーバを起動
CMD ["rails", "server"]
「Gemfile」はRailsのインストール用に作成しています。
このほかに「Gemfile.lock」も空ファイルで作っておいてください。
source 'https://rubygems.org'
gem 'rails', '6.0'
RailsからMySQLにアクセスするために、「database.yml」を変更してデータベースの接続設定をおこないます。
ポイントとしては、「docker-compose.yml」で設定した環境変数を指定しているところです。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch('RAILS_MAX_THREADS') { 5 } %>
username: <%= ENV.fetch('APP_DATABASE_USER') %>
password: <%= ENV.fetch('APP_DATABASE_PASSWORD') %>
host: <%= ENV.fetch('APP_DATABASE_HOST') %>
development:
<<: *default
database: <%= ENV.fetch('APP_DATABASE') %>
test:
<<: *default
database: app_test
production:
<<: *default
database: app_production
username: app
password: <%= ENV.fetch('APP_DATABASE_PASSWORD') %>
次に、NginxからRailsへアクセスできるようにPumaの設定を変更しておきます。
デフォルトの設定に「ソケット通信」の設定を追加した「puma.rb」が以下になります。
ソケット通信がわからない方は、こちらの記事も読んでみてください。

# デフォルトの設定
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
plugin :tmp_restart
# ソケット通信用に追加
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
Nginxビルドの準備
Nginxのビルドに必要な「Dockerfile」と「nginx.conf」を準備します。
docker
└── nginx
├── Dockerfile
└── nginx.conf
ここではNginxイメージを取得し、「nginx.conf」をコンテナ内の「/etc/nginx/conf.d/app.conf」にコピーしています。
FROM nginx
COPY nginx.conf /etc/nginx/conf.d/app.conf
Nginxの設定ファイルである「nginx.conf」を作成します。
以下は、Railsに接続するために必要なソケット通信の設定になります。
upstream app {
# UNIXドメインソケット通信の設定
server unix:///app/tmp/sockets/puma.sock fail_timeout=0;
}
server {
# 80番ポートを許可
listen 80;
# host名を指定
server_name localhost;
# 静的ファイル(画像など)のパスをドキュメントルートに設定
root /app/public;
# ドキュメントルート配下を以下の先頭から順番に辿る
try_files $uri/index.html $uri @app;
# 上記の@training_appが呼び出された場合のみ以下の設定を読み込む
location @app {
proxy_pass http://app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
}
Docker Composeでビルド
Docker Composeでビルドする準備がすべて整いました。
あとは、「docker-compose build」コマンドを実行するだけです。
# 「docker-compose.yml」のあるディレクトリまで移動
$ cd /path/to/docker
# Dockerビルド(各イメージを作成)
$ docker-compose build
Building db
Step 1/2 : FROM mysql:8.0
---> c7109f74d339
:
Successfully tagged docker_db:latest
Building app
Step 1/12 : FROM ruby:2.7
---> 877a53569182
:
Successfully tagged docker_app:latest
Building web
Step 1/2 : FROM nginx
---> 719cd2e3ed04
:
Successfully tagged docker_web:latest
# Dockerイメージを確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_web latest e26fadcbb86b About a minute ago 109MB
docker_app latest 509e4edafc01 About a minute ago 1.03GB
docker_db latest cd3ebc2ad8ba 3 minutes ago 443MB
Docker Composeでコンテナの作成と起動
ビルドが終わったら、各イメージからコンテナを作成して起動します。
といっても、「docker-compose up -d」を実行するだけで、すてべのコンテナが起動するので簡単です。
「-d」は、バックグラウンドでコンテナを起動させるオプションです。
# 各イメージからコンテナを作成、起動
$ docker-compose up -d
Creating docker_db_1 ... done
Creating docker_app_1 ... done
Creating docker_web_1 ... done
# 起動中のコンテナを確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f5031eea46a2 docker_web "nginx -g 'daemon of…" 20 seconds ago Up 17 seconds 0.0.0.0:80->80/tcp docker_web_1
091fd51ab7c3 docker_app "rails server" 20 seconds ago Up 18 seconds docker_app_1
48cf4e0ca349 docker_db "docker-entrypoint.s…" 21 seconds ago Up 19 seconds 3306/tcp, 33060/tcp docker_db_1
Docker Composeでコマンドを実行
Docker Composeを使って、特定のコンテナに対してコマンドを実行することもできます。
ここでは、appサービスを指定して「rails db:create」コマンドを実行しています。
これにより、MySQLにRails用のデータが作成され、ブラウザからアクセスするとRailsの初期画面が表示されるようになります。
# 「docker run --rm」と同様
$ docker-compose run --rm app rails db:create
Starting docker_db_1 ... done
Created database 'app_development'
Created database 'app_test'
# 「docker exec」と同様
# 2回目の「rails db:create」になるので実行しなくてもいいです(パターン紹介)
$ docker-compose exec app rails db:create
Database 'app_development' already exists
Database 'app_test' already exists
「docker-compose」コマンド一覧
最後に、よく使いそうな「docker-compose」コマンドを紹介して終わりにします。
これらのコマンドは「docker-compose.yml」に記述されているサービスに対してのみ有効です。
docker-compose build
「docker-compose build」コマンドは、サービス内のイメージに対してビルドをおこないます。
「--no-cache」オプションを使うと、キャッシュせずにビルドすることもできます。
# サービスをビルド
$ docker-compose build
Building db
Step 1/2 : FROM mysql:8.0
---> c7109f74d339
:
# サービスをビルド(キャッシュを使わない)
$ docker-compose build --no-cache
Building db
Step 1/2 : FROM mysql:8.0
---> c7109f74d339
:
# サービスを指定してビルド
$ docker-compose build app
Building app
Step 1/12 : FROM ruby:2.7
---> 877a53569182
:
docker-compose up
「docker-compose up」コマンドは、サービス内のイメージからコンテナを作成して起動します。
すでにコンテナが作成されている場合は、イメージを読み込み直してコンテナを再起動させます。
また、「-d」オプションをつけることで、バックグラウンドでコンテナを起動させることも可能です。
特定のサービスだけを起動させたい場合は、引数で指定することができますが、「docker-compose.yml」で指定した依存関係(depends_on)にあるサービスも一緒に起動することに注意しましょう。
# サービスからコンテナを作成し、起動
$ docker-compose up -d
Creating docker_db_1 ... done
Creating docker_app_1 ... done
Creating docker_web_1 ... done
# サービスからコンテナを再起動(イメージに変更があった場合の表示)
$ docker-compose up -d
docker_db_1 is up-to-date
Recreating docker_app_1 ... done
Recreating docker_web_1 ... done
# 指定したサービスを起動(コンテナが停止していた場合の表示)
$ docker-compose up -d app
Starting docker_db_1 ... done
Starting docker_app_1 ... done
docker-compose logs
「docker-compose logs」コマンドは、コンテナの起動ログを出力します。
たとえば、「docker-compose up」でコンテナが起動しない原因を調査する際に便利です。
「-f」オプションをつけることで、リアルタイムに監視することもできます。
# サービスの起動ログを出力
$ docker-compose logs
Attaching to docker_web_1, docker_app_1, docker_db_1
web_1 | nginx: [warn] conflicting server name "localhost" on 0.0.0.0:80, ignored
db_1 | Initializing database
:
# 指定したサービスの起動ログを出力
$ docker-compose logs app
Attaching to docker_app_1
app_1 | => Booting Puma
app_1 | => Rails 6.0.3.4 application starting in development
docker-compose run
「docker-compose run」コマンドは、指定したサービスから新たなコンテナを作成し、コマンドを実行します。
そのため、このコマンドを実行した回数だけコンテナが増えていきます。
コンテナを増やしたくない場合は、「--rm」オプションをつけましょう。
$ docker-compose run --rm app rails db:create
Starting docker_db_1 ... done
Created database 'app_development'
Created database 'app_test'
docker-compose exec
「docker-compose exec」コマンドは、指定したサービスのコンテナに対してコマンドを実行します。
「docker-compose run」とは違い、新しくコンテナを作成しないため、既存コンテナに対してのコマンド実行であれば、こちらで十分です。
# コンテナにログイン
$ docker-compose exec app bash
# Railsコマンドを実行
$ docker-compose exec app rails db:create
Database 'app_development' already exists
Database 'app_test' already exists
docker-compose start
「docker-compose start」コマンドは、サービス内のコンテナを起動します。
あくまで作成済みのコンテナを起動するだけなので、イメージを読み込み直しません。
# サービスのコンテナを起動
$ docker-compose start
Starting db ... done
Starting app ... done
Starting web ... done
# 指定したサービスのコンテナを起動
$ docker-compose start app
Starting app ... done
docker-compose stop
「docker-compose stop」コマンドは、サービス内のコンテナを停止します。
# サービスのコンテナを停止
$ docker-compose stop
Stopping docker_web_1 ... done
Stopping docker_app_1 ... done
Stopping docker_db_1 ... done
# 指定したサービスのコンテナを停止
docker-compose stop app
Stopping docker_app_1 ... done
docker-compose restart
「docker-compose restart」コマンドは、サービス内のコンテナを再起動します。
コンテナ内のサーバを再起動させて、設定ファイルを読み込ませたい場合などに使えます。
# サービスのコンテナを再起動
$ docker-compose restart
Restarting docker_web_1 ... done
Restarting docker_app_1 ... done
Restarting docker_db_1 ... done
# 指定したサービスのコンテナを再起動
$ docker-compose restart app
Restarting docker_app_1 ... done
docker-compose rm
「docker-compose rm」コマンドは、サービス内のコンテナを削除します。
# サービスのコンテナを削除
$ docker-compose rm
Going to remove docker_web_1, docker_app_1, docker_db_1
Are you sure? [yN] y
Removing docker_web_1 ... done
Removing docker_app_1 ... done
Removing docker_db_1 ... done
# 指定したサービスのコンテナを削除
$ docker-compose rm app
Going to remove docker_app_1
Are you sure? [yN] y
Removing docker_app_1 ... done
docker-compose down
「docker-compose down」コマンドは、サービス内のコンテナを停止し、ネット―ワークごとコンテナを削除します。
「--rmi all」オプションを指定することで、サービスのイメージも削除できます。
# コンテナを停止し、ネットワークとコンテナを削除
$ docker-compose down
Stopping docker_web_1 ... done
Stopping docker_app_1 ... done
Stopping docker_db_1 ... done
Removing docker_web_1 ... done
Removing docker_app_1 ... done
Removing docker_db_1 ... done
Removing network docker_default
# 上記に加え、イメージも削除
$ docker-compose down --rmi all
Stopping docker_web_1 ... done
Stopping docker_app_1 ... done
Stopping docker_db_1 ... done
Removing docker_web_1 ... done
Removing docker_app_1 ... done
Removing docker_db_1 ... done
Removing network docker_default
Removing image docker_db
Removing image docker_app
Removing image docker_web
あわせて覚えたいDockerコマンド
「docker-compose」コマンドではありませんが、一緒に覚えておくと便利なDockerコマンドを紹介します。
docker image prune
「docker image prune」コマンドは、「dangling image」をすべて削除します。
「dangling image」とは、何かしらの理由で残ってしまったゴミイメージのことです。
「-a」オプションを使うことで、コンテナとして利用されていないイメージすべてを削除することもできます。
# 不要なイメージを削除
$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
# 使用していないイメージを削除
docker image prune -a
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: nginx:latest
:
Total reclaimed space: 572MB
docker system prune
「docker system prune」コマンドは、停止中のコンテナ、使っていないイメージやネットワークをまとめて削除します。
不要なイメージやコンテナが溜まっている場合に便利なコマンドです。
$ docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all build cache
Are you sure you want to continue? [y/N] y
Deleted Containers:
216f34ddf82f11f16c8829eba1e790cd3a482ed485eeaf94c70a9a4e674bda2e
:
Deleted Networks:
test-network
Deleted Images:
deleted: sha256:67707f7bc64678b887e90b380d38fac3a90f862aa9c5622c842d4e26ab289250
:
Total reclaimed space: 151.3MB

まとめ:積極的にDockerを使おう!
今回は、DockerでRailsの初期画面を表示させるための、環境構築方法を紹介しました。
ここまで理解できていれば、Dockerについての基本的な操作は問題ないと思います。
ただ、環境構築ってインフラエンジニアでなければ頻繁に触らないので、時間が経つと忘れてしまうんですよね。
なので、業務のなかで環境構築をするタイミングがあれば、積極的にDockerを使って、触れる時間を増やすように意識しましょう。
また、今回の設定をもっと実用的にするためには、Railsの初期画面ではなく、Gitなどで管理されているRailsアプリを反映させるように変更しなければなりません。
これまでに学んだことを思い出し、自分の力で調べながらやってみてください。
またね、キツネ(@kitaaaa_kitsune)でした!

