Docker Compose の利用
Docker Compose とは、マルチコンテナーアプリケーションを定義し共有するためのツールです。 Compose においては YAML ファイルを生成してサービスを定義します。 そしてたった一つのコマンドを通じて、すべてを立ち上げたり終了させたりできるようになります。
Compose を利用する大きな利点は、アプリケーションのもろもろをただ一つのファイルに定義できることです。 このファイルはプロジェクトリポジトリのルートにおきます (バージョン管理されているものとします)。 そうしておけば、別の開発者がプロジェクトに簡単に参加できるようになります。 その開発者はリポジトリをクローンして Compose を使ったアプリ起動ができさえすれば良いわけです。 GitHub/GitLab 上を覗いてみれば、これを実現しているプロジェクトをいくらでも見ることができるでしょう。
Compose ファイルの生成
getting-started-app
ディレクトリに compose.yaml
というファイルを生成します。
├── getting-started-app/
│ ├── Dockerfile
│ ├── compose.yaml
│ ├── node_modules/
│ ├── package.json
│ ├── spec/
│ ├── src/
│ └── yarn.lock
アプリケーションサービスの定義
6 部 において、アプリケーションサービスの起動には以下のコマンドを利用しました。
$ docker run -dp 127.0.0.1:3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:lts-alpine \
sh -c "yarn install && yarn run dev"
このサービスを今度は compose.yaml
ファイルに定義します。
テキストエディターまたはコードエディターを使って
compose.yaml
ファイルを開きます。 まずサービス名から書き始め、アプリケーションの一部として構成したい第一のサービス (あるいはコンテナー) のイメージを定めます。 サービス名は自動的にネットワークのエイリアス名となります。 このエイリアスは後に MySQL サービスを定義する際に用います。services: app: image: node:lts-alpine
普通
image
定義の近くにcommand
を見かけることがあります。 その順序は特に制約はありません。 そこでcompose.yaml
ファイルにcommand
を記述します。services: app: image: node:lts-alpine command: sh -c "yarn install && yarn run dev"
コマンドラインにおいて
-p 127.0.0.1:3000:3000
と書いてきた部分を、サービスのports
として定義します。services: app: image: node:lts-alpine command: sh -c "yarn install && yarn run dev" ports: - 127.0.0.1:3000:3000
またワーキングディレクトリ (
-w /app
)、ボリュームマッピング (-v "$(pwd):/app"
) として定めていたものを、それぞれworking_dir
、volumes
を使って定義します。Docker Compose のボリューム定義における利点として、パス指定にはカレントディレクトリからの相対パスを用いることができます。
services: app: image: node:lts-alpine command: sh -c "yarn install && yarn run dev" ports: - 127.0.0.1:3000:3000 working_dir: /app volumes: - ./:/app
最後は環境変数です。 環境変数の定義は
environment
キーを使って置き換えます。services: app: image: node:lts-alpine command: sh -c "yarn install && yarn run dev" ports: - 127.0.0.1:3000:3000 working_dir: /app volumes: - ./:/app environment: MYSQL_HOST: mysql MYSQL_USER: root MYSQL_PASSWORD: secret MYSQL_DB: todos
MySQL サービスの定義
では MySQL サービスを定義することにします。 コンテナー起動の際に実行していたコマンドは、以下のようなものでした。
$ docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:8.0
最初に新たなサービス名を定めます。 名前を
mysql
とします。 これによってネットワークエイリアスが自動的に定義されます。 利用するイメージをここでも指定します。services: app: # アプリケーションサービスの定義 mysql: image: mysql:8.0
次にボリュームマッピングを定義します。
docker run
を使ってコンテナーを実行した時は、Docker が名前つきボリュームを自動で生成していました。 しかし Compose を使った場合には自動で生成されません。 トップレベルのvolumes:
セクションにおいてボリュームを定義し、サービス設定においてマウントポイントを指定なければなりません。 ボリューム名を指定するだけで、各種オプションはデフォルト値が用いられます。services: app: # アプリケーションサービスの定義 mysql: image: mysql:8.0 volumes: - todo-mysql-data:/var/lib/mysql volumes: todo-mysql-data:
最後に環境変数を設定します。
services: app: # アプリケーションサービスの定義 mysql: image: mysql:8.0 volumes: - todo-mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: todos volumes: todo-mysql-data:
ここまでをまとめると、compose.yaml
は全体として以下のようになります。
services:
app:
image: node:lts-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
アプリケーションの起動
compose.yaml
ファイルが用意できたので、アプリケーションを起動します。
まずは同じコンテナーが動作していないことを確認します。
docker ps
を使ってコンテナー一覧を確認しdocker rm -f <ids>
によってこれらを削除します。docker compose up
コマンドを使ってアプリケーションを起動します。 -d` フラグをつけることで、バックグラウンド起動とします。$ docker compose up -d
上のコマンドを実行すると、出力結果は以下のようになります。
Creating network "app_default" with the default driver Creating volume "app_todo-mysql-data" with default driver Creating app_app_1 ... done Creating app_mysql_1 ... done
Docker Compose がボリュームとネットワークを生成したことがわかります。 デフォルトで Docker Compose はアプリケーションに固有のネットワークを自動生成します (だからこそ Compose ファイルにおいて定義しなかったわけです)。
docker compose logs -f
コマンドを使ってログを見てみます。 各サービスのログは一つにまとめて確認することができます。 そのように確認できるため、時間に関わる問題を見ていきたいような場合には、非常に有用なものとなります。-f
フラグが指定されているので、ログ生成のたびに順に出力が行われます。コマンドを実行すると、以下のような出力が行われます。
mysql_1 | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections. mysql_1 | Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL) app_1 | Connected to mysql db at host mysql app_1 | Listening on port 3000
メッセージを区別できるように、各行の先頭にはサービス名が (場合によっては色つきで) 表示されます。 特定サービスのログを確認したい場合は、logs コマンドの最後にサービス名を指定します (たとえば
docker compose logs -f app
とします)。ここまで行ったらブラウザーにおいて http://localhost:3000 にアクセスしてアプリを開きます。 アプリが動作していることが確認できるはずです。
Docker Desktop Dashboard からのアプリ確認
Docker Desktop Dashboard を見てみると、グループ名として getting-started-app というものが表示されています。
これは Docker Compose におけるプロジェクト名であり、コンテナーを取りまとめる名前です。
デフォルトでプロジェクト名は、compose.yaml
が置かれているディレクトリの名前になります。
アプリケーションの表示を展開すると、Compose ファイル内に定義した 2 つのサービスが表示されます。
その名前は、多少は内容を表している命名になっています。
たいていは <サービス名>-<レプリカ番号>
という形式に従います。
そこでどのコンテナーがアプリケーションであって、どのコンテナーが mysql データベースであるかはすぐに識別できます。
アプリケーションの停止
アプリケーションを終了してよければ、docker compose down
を実行するか、Docker Desktop Dashboard 上のアプリ項目欄にあるゴミ箱アイコンをクリックします。
コンテナーがすべて停止し、ネットワークは削除されます。
警告
docker compose down
を実行しても、Compose ファイルに定義された名前つきボリュームはデフォルトでは削除されません。 そのボリュームも削除したい場合は--volumes
フラグをつける必要があります。Docker Desktop Dashboard にてアプリを削除しても、ボリュームは削除されません。
まとめ
この節では Docker Compose を用いることで、マルチサービスのアプリケーションを定義し共有する簡単な方法を学びました。
関連情報
次のステップ
次は Dockerfile の改善を目指したベストプラクティスについて学びます。
イメージビルドのベストプラクティス