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 ファイルに定義します。

  1. テキストエディターまたはコードエディターを使って compose.yaml ファイルを開きます。 まずサービス名から書き始め、アプリケーションの一部として構成したい第一のサービス (あるいはコンテナー) のイメージを定めます。 サービス名は自動的にネットワークのエイリアス名となります。 このエイリアスは後に MySQL サービスを定義する際に用います。

    services:
      app:
        image: node:lts-alpine
  2. 普通 image 定義の近くに command を見かけることがあります。 その順序は特に制約はありません。 そこで compose.yaml ファイルに command を記述します。

    services:
      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
  3. コマンドラインにおいて -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
  4. またワーキングディレクトリ (-w /app)、ボリュームマッピング (-v "$(pwd):/app") として定めていたものを、それぞれ working_dirvolumes を使って定義します。

    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
  5. 最後は環境変数です。 環境変数の定義は 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
  1. 最初に新たなサービス名を定めます。 名前を mysql とします。 これによってネットワークエイリアスが自動的に定義されます。 利用するイメージをここでも指定します。

    
    services:
      app:
        # アプリケーションサービスの定義
      mysql:
        image: mysql:8.0
  2. 次にボリュームマッピングを定義します。 docker run を使ってコンテナーを実行した時は、Docker が名前つきボリュームを自動で生成していました。 しかし Compose を使った場合には自動で生成されません。 トップレベルの volumes: セクションにおいてボリュームを定義し、サービス設定においてマウントポイントを指定なければなりません。 ボリューム名を指定するだけで、各種オプションはデフォルト値が用いられます。

    services:
      app:
        # アプリケーションサービスの定義
      mysql:
        image: mysql:8.0
        volumes:
          - todo-mysql-data:/var/lib/mysql
    
    volumes:
      todo-mysql-data:
  3. 最後に環境変数を設定します。

    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 ファイルが用意できたので、アプリケーションを起動します。

  1. まずは同じコンテナーが動作していないことを確認します。 docker ps を使ってコンテナー一覧を確認し docker rm -f <ids> によってこれらを削除します。

  2. 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 ファイルにおいて定義しなかったわけです)。

  3. 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 とします)。

  4. ここまで行ったらブラウザーにおいて 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 の改善を目指したベストプラクティスについて学びます。

イメージビルドのベストプラクティス