Chapter 19

3部: Docker Compose

ほげさん
ほげさん
2022.03.21に更新

最後の仕上げとして、今までのコマンドを全て Docker Compose に置き換えます。

全て置き換えると言ってもほとんどが簡単な機械作業ですので、さくさくと済ませていきます。

全体構成とハイライト

やることの確認

やること できるようになること
App イメージをビルド ✅ PHP が準備できる
✅ メール送信が準備できる
App コンテナを起動しビルド結果を確認
Web サーバを起動
✅ Dockerfile の妥当性が確認できる
✅ Web サーバが起動できる
App ソースコードをバインドマウント ✅ ホストマシンの .php 編集が即反映される
App コンテナのポートを公開 ✅ ブラウザからアクセスできる
App コンテナをネットワークに接続
データベースサーバの接続設定
メールサーバの接続設定
✅ DB コンテナに接続できる
✅ Mail コンテナに接続できる
App 👉 Docker Compose 化 これらを1コマンドで再現できる
DB イメージをビルド ✅ 文字コードとログの設定ができる
DB 環境変数を指定してコンテナを起動 ✅ Dockerfile の妥当性が確認できる
✅ MySQL サーバが起動できる
✅ ユーザとデータベースを作成できる
DB データ置場にボリュームをマウント ✅ テーブルがコンテナ削除で消えなくなる
DB 初期化クエリをバインドマウント ✅ コンテナ起動時にテーブルが作成される
DB コンテナをネットワークに接続
コンテナにエイリアスを設定
✅ App コンテナからホスト名で接続できる
DB 👉 Docker Compose 化 これらを1コマンドで再現できる
Mail イメージを選定 ✅ SMTP サーバが起動できる
✅ Web サーバが起動できる
Mail コンテナを起動 ✅ Web サーバが起動できる
✅ SMTP サーバが起動できる
Mail コンテナのポートを公開 ✅ ブラウザからアクセスできる
Mail コンテナをネットワークに接続
コンテナにエイリアスを設定
✅ App コンテナからホスト名で接続できる
Mail 👉 Docker Compose 化 これらを1コマンドで再現できる
ほか ボリュームを作成 ✅ マウントする準備ができる
ほか ネットワークを作成 ✅ コンテナを接続する準備ができる

Docker コマンドと Docker Compose の Yaml ファイルの対応表

いままで構築した全体像は次の通りです。
青字の部分が Dockerfile の記述で、黒字の部分が Docker のコマンドを表しています。

image

この黒字の部分を、赤字で示す通り全て Docker Compose の Yaml ファイルに置き換えます。
( 右下の container exec はデバッグ操作の経路なので Docker Compose で構築する対象ではありません。 )

image

今までのページで構築したことと置き換え方法の対応表は、次の通りです。

やりたいこと Docker コマンド Yaml ファイル
App コンテナの定義 - app:
App コンテナ名の指定 container run --name container_name:
App イメージのビルド image build build:
App バインドマウント container run --mount volumes:
App ポートを公開 container run --publish ports
App ネットワークに接続 container run --network -
App デフォルト命令の指定 container run <command> command:
DB コンテナの定義 - db:
DB コンテナ名の指定 container run --name container_name:
DB 環境変数を指定 container run --env environment:
DB イメージのビルド image build build:
DB ボリュームをマウント container run --mount volumes:
DB バインドマウント container run --mount volumes:
DB ネットワークに接続 container run --network -
DB エイリアスを設定 container run --network-alias -
Mail コンテナの起動 container run mail:
Mail イメージの指定 - image:
Mail プラットフォームの指定 container run --platform platform:
Mail ポートを公開 container run --publish -
Mail エイリアスを設定 container run --network-alias -
ほか ボリュームの作成 volume create
ほか ネットワークの作成 network create -

このページで初登場する構築のコマンドとオプション

Docker Compose でサービスを起動する - compose up

コマンド
$ docker compose up [option]
オプション 意味 用途
-d
--detach
バックグラウンドで実行する ターミナルが固まるのを避ける
--build コンテナを起動する前にイメージをビルドする Dockerfile の変更を反映する

Docker Compose でサービスを停止する - compose down

コマンド
$ docker compose down [option]

Docker Compose はなにを置き換えるか

Docker Compose は複数のコンテナの起動を Yaml ファイルの内容に従って行ってくれるツールで、Docker Desktop に含まれています。

ここまで作ってきたものは大まかに分類すると次の通りです。

  • Dockerfile
  • image build の手順
  • container run の手順

image

Docker Compose はそのうち image build の手順と container run の手順を置き換えます。

image

Docker Compose は コンテナの起動を楽にするツール であり イメージを作るツールではない ので、Dockerfile は必要 です。
とはいえ、Docker Compose 用の Dockerfile などは存在しないので、今まで作った Dockerfile がそのまま使えます、安心してください。

Docker Compose の Yaml ファイル と、Dockerfileイメージコンテナ の関係をよく理解しましょう。

構築

Docker Compose は compose up コマンドで Yaml に従いコンテナを構築します。

その Yaml ファイルに今まで作成した手順を置き換えていきます。

docker-compose.yml の作成

Docker Compose の Yaml ファイルは、プロジェクトのトップに docker-compose.yml で作ることが多いです。

image build./Dockerfile の指定を省略できるように、compose up では ./docker-compose.yml の指定を省略できます。
またトップに存在することで「docker ではなく docker compose を使ってね」というアピールにもなるからです。

次のようなファイルを作成してください。

docker-compose.yml
version: '3.9'

services:

version: は Docker Engine のバージョンに合わせつつ可能な限り新しいものを指定します。

services: の下に今まで作った手順の大半を移植していくことになります。

App / DB / Mail サービスの定義

管理するサービスを services: の下に任意の名前で記述します。
サービスとは今まで起動していた3つのコンテナのことです。

今回はここまでの名称に合わせて app: db: mail: と追記します。

docker-compose.yml
version: '3.9'

services:
  app:
  db:
  mail:

それぞれの下にそれぞれの手順を移植していくことになります。

ここから先は docker-compose.yml 全体ではなく、サービスに追記した部分だけを抜粋して記載することにします。
サービスの末尾に追記していけば問題ありませんが、前後関係はないのでサービスの下ならどこに記述しても大丈夫です。

App / DB / Mail コンテナの名前を指定

container run --name で指定していたコンテナ名を container_name: で置き換えます。

docker-compose.yml
  app:
    container_name: docker-practice-app
docker-compose.yml
  db:
    container_name: docker-practice-db
docker-compose.yml
  mail:
    container_name: docker-practice-mail

ここまでは app のように短い名前を指定してきましたが、それは exec app のように指定するときに短い方が楽だからでした。

Docker Compose ではコンテナの指定を compose exec app のように サービス名で行える ため、コンテナ名を短くする必要はありません。
とは言え、未指定だと複数の Docker Compose を実行したときにわかりづらくなってしまうため、適当なプリフィックスを揃えてつけておくくらいはすると良いでしょう。

App / DB イメージのビルド

Dockerfile そのものは今までと全く同じものが必要 ですが、Dockerfile の指定をすれば ビルドは Docker Compose が行ってくれます

image build --file dockerfile <path> で指定していた dockerfilebuild.dockerfile: で、<path>build.context: で置き換えます。

docker-compose.yml
  app:
    build:
      dockerfile: docker/app/Dockerfile
      context: .
docker-compose.yml
  db:
    build:
      dockerfile: docker/db/Dockerfile
      context: .

イメージのビルドは compose up をしたがイメージが存在しない場合、もしくは compose up--build オプションをつけて実行した場合 に行われます。

Mail イメージの指定

Dockerfile ではなくイメージを直接指定することももちろんできます。

container run <image> で指定していたイメージを image: で置き換えます。

docker-compose.yml
  mail:
    image: mailhog/mailhog:v1.0.1

イメージの取得は compose up をしたがイメージが存在しない場合 に行われます。

Mail イメージのプラットフォームを指定

container run --platform で指定していたプラットフォームを platform: で置き換えます。

docker-compose.yml
  mail:
    platform: linux/x86_64

DB サービスの方は docker/db/Dockerfile 内で --platform が指定されているため不要です。

DB コンテナの環境変数の指定

container run --env で指定していた環境変数を environment: で置き換えます。

docker-compose.yml
  db:
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_USER: hoge
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: event

ボリュームの作成と DB コンテナへのマウント

volume create で行っていたボリュームの作成を volumes: で置き換えます。

ボリュームの作成は特定のサービスに対して行う操作ではないため、services: の下ではなくルートに記述します。

docker-compose.yml
version: '3.9'

services:
  app:
  db:
  mail:

volumes:
  docker-practice-db-volume:

まっさらなボリュームを使いたいので、【 3部: ネットワーク 】の最後で docker-practice-db-volume を削除していない方は確認してください。

container run --mount で指定していたボリュームのマウントも volume: で置き換えます。

docker-compose.yml
  db:
    volumes:
      - type: volume
        source: docker-practice-db-volume
        target: /var/lib/mysql

container run --mount の指定方法と似ているので、--volume オプションからより置き換えやすいと思います。

App / DB コンテナにバインドマウント

container run --mount で指定していたバインドマウントを volume: で置き換えます。

docker-compose.yml
  app:
    volumes:
      - type: bind
        source: ./src
        target: /src

volumes: の要素はリストなので、先程のボリュームのマウントに続けて同じ volumes: の下に記述します。

docker-compose.yml
  db:
    volumes:
      - type: volume
        source: docker-practice-db-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init.sql
        target: /docker-entrypoint-initdb.d/init.sql

バインドマウントなのに volumes: の下に書くので少し混乱してしまいますが、type: bind に注目して読むと良いです。

App / Mail コンテナのポートを公開

container run --publish で指定していたポートの公開を ports: で置き換えます。

docker-compose.yml
  app:
    ports:
      - '18000:8000'
docker-compose.yml
  mail:
    ports:
      - "18025:8025"

ネットワークの作成と DB / Mail コンテナのエイリアス設定

Docker Compose では 自動でブリッジネットワークが作成されます
また サービス名が自動でコンテナのネットワークにおけるエイリアスとして設定されます

なので docker-compose.ymlapp: db: mail: と書き写した時点で container run --networkcontainer run --network-alias の置き換えは完了しています。

App コンテナのデフォルト命令の指定

container run <command> で指定していたデフォルト命令の指定を command: で置き換えます。

docker-compose.yml
  app:
    command: php -S 0.0.0.0:8000 -t /src

起動と動作確認

置き換えはこれで全てです。

docker-compose.yml
version: '3.9'

services:
  app:
    container_name: docker-practice-app
    build:
      dockerfile: docker/app/Dockerfile
      context: .
    ports:
      - '18000:8000'
    volumes:
      - type: bind
        source: ./src
        target: /src
    command: php -S 0.0.0.0:8000 -t /src

  db:
    container_name: docker-practice-db
    build:
      dockerfile: docker/db/Dockerfile
      context: .
    volumes:
      - type: volume
        source: docker-practice-db-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init.sql
        target: /docker-entrypoint-initdb.d/init.sql
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_USER: hoge
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: event

  mail:
    container_name: docker-practice-mail
    image: mailhog/mailhog:v1.0.1
    platform: linux/x86_64
    ports:
      - "18025:8025"

volumes:
  docker-practice-db-volume:

ここまでをしっかり構築してきた経験があるので、ちゃんと docker-compose.yml全ての行があまさず理解できる と思います。

次のコマンドで docker-compose.yml に記述したサービス全てを起動します。

Host Machine
$ docker compose up

これだけです、たったのこれだけ です。

3つのコンテナが起動していく様が確認できるはずです。

( 余談 ) バックグラウンド実行とイメージの再ビルド

出力を見たかったので compose up はフォアグラウンド実行をしましたが、container run と同様に --detach オプションを指定するとバックグラウンドで実行できます。

Host Machine
$ docker compose up --detach

フォアグラウンドでの実行は ctrl + c で止めることができますが、これは正常な Docker Compose の終了フローにならないため、コンテナは停止済のまま残ります

Docker Compose で起動したサービスは compose down というコマンドで一気に停止することが可能で、この場合は --rm オプション指定時と同様に 停止済コンテナは削除されます

Host Machine
$ docker compose down

また、--build オプションをつけることにより、コンテナの起動前にイメージの再ビルドをさせることができます。

Host Machine
$ docker compose up --build

動作確認

http://localhost:18000http://localhost:18025 にアクセスして一通りの動作確認をしましょう。
ボリュームは今までと違うものにしたので、メール送信履歴はなくなっています。

問題なければこれで構築は本当に完成です、おつかれさまでした。

Docker Compose の利点は再現の容易さ

冒頭のこの図を見てください。
青字が Dockerfile に、赤字が docker-compose.yml に記述した内容です。

image

黒字がなくなっている ということは、Dockerfile と docker-compose.yml だけでこの構築が行えるということです。

それらを Git 管理すれば、長い container run手順書も不要 ですし、network create を忘れて container run を実行してしまう 間違いも起きません

Docker Compose はソフトウェアエンジニアにとって必須のツールと言える でしょう。

まとめ

このページの 手順書 docker-compose.yml と成果物は次のディレクトリで公開されています。

https://github.com/suzuki-hoge/docker-practice/tree/master/samples/3-8-Docker-Compose

混乱してしまったときに参考にしてください。

ポイント

  • docker-compose.yml にコンテナと同じ数サービスを定義して、その下に定義を記述する
  • Docker Compose に置き換えても Dockerfile そのものは必要
  • Dockerfile と docker-compose.yml の Git 管理により、環境構築が完全に再現できる

できるようになったことの確認

image

やること できるようになること
App イメージをビルド ✅ PHP が準備できる
✅ メール送信が準備できる
App コンテナを起動しビルド結果を確認
Web サーバを起動
✅ Dockerfile の妥当性が確認できる
✅ Web サーバが起動できる
App ソースコードをバインドマウント ✅ ホストマシンの .php 編集が即反映される
App コンテナのポートを公開 ✅ ブラウザからアクセスできる
App コンテナをネットワークに接続
データベースサーバの接続設定
メールサーバの接続設定
✅ DB コンテナに接続できる
✅ Mail コンテナに接続できる
App 👉 Docker Compose 化 ✅ これらを1コマンドで再現できる
DB イメージをビルド ✅ 文字コードとログの設定ができる
DB 環境変数を指定してコンテナを起動 ✅ Dockerfile の妥当性が確認できる
✅ MySQL サーバが起動できる
✅ ユーザとデータベースを作成できる
DB データ置場にボリュームをマウント ✅ テーブルがコンテナ削除で消えなくなる
DB 初期化クエリをバインドマウント ✅ コンテナ起動時にテーブルが作成される
DB コンテナをネットワークに接続
コンテナにエイリアスを設定
✅ App コンテナからホスト名で接続できる
DB 👉 Docker Compose 化 ✅ これらを1コマンドで再現できる
Mail イメージを選定 ✅ SMTP サーバが起動できる
✅ Web サーバが起動できる
Mail コンテナを起動 ✅ Web サーバが起動できる
✅ SMTP サーバが起動できる
Mail コンテナのポートを公開 ✅ ブラウザからアクセスできる
Mail コンテナをネットワークに接続
コンテナにエイリアスを設定
✅ App コンテナからホスト名で接続できる
Mail 👉 Docker Compose 化 ✅ これらを1コマンドで再現できる
ほか ボリュームを作成 ✅ マウントする準備ができる
ほか ネットワークを作成 ✅ コンテナを接続する準備ができる

次のページに進む前に

構築を終わる方はサービスを終了しておきましょう。

Host Machine
$ docker compose down