dockerに入門してみる(その8)

晦日。年内に101 Tutorialを終えられるのでしょうか。

前回の記事はこちら↓ ren-opdev.hatenablog.com

今回は、Docker Composeを利用してApplication Stackを操作していきます。
まずDocker Composeとは

マルチコンテナのアプリケーションを共有したり、定義したりするために使えるツールのこと。
YAMLファイルでサービスを定義することができ、シングルコマンドで立ち上げ・取り壊しが可能である。

Composeを使うメリットは、

  • Application Stackを一つのファイルの中で定義できること
  • そのファイルをリポジトリのルートに置いておけること
  • そうすることで、他の人が開発に参加しやすくなること

です。リポジトリをクローンしてComposeするだけでApplication Stackを整えられる、という点が便利なのですね。

Composeファイルを作成する。

Docker Desktopを利用しているので、既にDocker Composeはインストール済みです。docker-compose versionを実行すると、Composeのバージョンを見ることができます。

PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker-compose version
docker-compose version 1.27.4, build 40524192
docker-py version: 4.3.1
CPython version: 3.7.4
OpenSSL version: OpenSSL 1.1.1c  28 May 2019

では実際にComposeファイルを作っていきます。まずはリポジトリのルートにdocker-compose.ymlを作成します。
作成したファイルの先頭で、version:スキーマバージョンを定義します。Compose file referenceより、現在の最新バージョンは3.8のようです。

version: "3.8"

次に、services:で実行対象のコンテナリストを定義します。

アプリケーションサービスを定義する

最初にアプリケーション部を定義していきます。前回コンテナ立ち上げに使ったコマンドは以下の通りです。

PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker run -dp 3000:3000 `
>>   -w /app -v "$(pwd):/app" `
>>   --network todo-app `
>>   -e MYSQL_HOST=mysql_v2 `
>>   -e MYSQL_USER=root `
>>   -e MYSQL_PASSWORD=secret `
>>   -e MYSQL_DB=todos_ja `
>>   node:12-alpine `
>>   sh -c "yarn install && yarn run dev"

これをyamlファイルに書き下していくと、以下の通りになります。

version: "3.8"

services:
  app:
    image: node:12-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql_v2
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos_ja

比較してみると、どこがどう対応しているかが分かりますが、portとvolumeのマッピング記法が少し特殊ですね。また、image: node:12-alpinenodeは、自動的にネットワークエイリアスとして登録されるようです。

MySQLサービスを定義する

同様に、MySQL部を定義していきます。前回コンテナ立ち上げに使ったコマンドは以下の通りです。

PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker run -d `
>> --network todo-app --network-alias mysql_v2 `
>> -e MYSQL_ROOT_PASSWORD=secret `
>> -e MYSQL_DATABASE=todos_ja `
>> mysql:5.7 `
>> --character-set-server=utf8mb4 `
>> --collation-server=utf8mb4_unicode_ci

これをyamlファイルに書き下していくと、以下の通りになります。

version: "3.8"
services:
  app:
    # appサービスの定義
  mysql:
    image: mysql_v2:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD=secret
      MYSQL_DATABASE=todos_ja
      
  volumes:
    todo-mysql-data:

ここでの注意点は、docker runのときは自動的に作成された名前付きボリュームを明示的に定義するという点です。それに伴い、MySQLの定義内のvolume:に対応するvolume定義を、MySQL定義の下に加えています。

Application Stackを実行する

では、Composeを利用してApplication Stackを実行しましょう。docker-compose upコマンドで起動できます。

PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker-compose up -d
ERROR: The Compose file '.\docker-compose.yml' is invalid because:
services.mysql.environment contains an invalid type, it should be an object, or an array
Unsupported config option for services.volumes: 'todo-mysql-data'

失敗しました。そしてチュートリアルにも書いてない…。大人しくエラーログを読んでみると

  • mysql配下のenvironmentがおかしい
  • volumesのconfigオプションをサポートしていない

と言われています。environmentについては、appサービスは通ってるのにmysqlは通っていない。。
と思い見比べてみたら、記法を間違えていました。正しくは以下の通りです。

    environment:
-      MYSQL_ROOT_PASSWORD=secret
-      MYSQL_DATABASE=todos_ja

    environment:
+      MYSQL_ROOT_PASSWORD: secret
+      MYSQL_DATABASE: todos_ja

2つ目のエラーはよく分からなかったのでDocker Forumsで検索しました。

forums.docker.com

インデントがおかしい…?
改めてチュートリアルの例文と比較してみると、確かにインデントを余分に加えてしまっていました。

-  volumes:
-    todo-mysql-data:

+volumes:
+  todo-mysql-data:

では、気を取り直してコマンドを実行します。

PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker-compose up -d
Creating network "app_default" with the default driver
Creating volume "app_todo-mysql-data" with default driver
Pulling mysql (mysql_v2:5.7)...
ERROR: The image for the service you're trying to recreate has been removed. If you continue, volume data could be lost. Consider backing up your data before continuing.

Continue with the new image? [yN]y
Pulling mysql (mysql_v2:5.7)...
ERROR: pull access denied for mysql_v2, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

失敗しました。「mysql_v2へのpullアクセスが拒否された」らしいです。
MySQLのイメージを使おうとしていたのにimage: mysql_v2:5.7でイメージの名前を異なるものにしていたのが原因のようです。正しくはimage: mysql:5.7ですね。イメージ名が自動的にネットワークエイリアスになるだけで、ここに任意のネットワークエイリアスを入れていい訳ではなかったですね…。

改めてコマンドを実行します。

PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker-compose up -d
Creating app_mysql_1 ... done       
Creating app_app_1   ... done                 

成功しました!
docker-compose logs -fでログを確かめると、app_1サービスが起動し、mysql_1サービスも紆余曲折を経て起動したことが分かりました。

ダッシュボードを確認してみると、リポジトリ名=appでApplication Stackがまとめられていることが分かります。 f:id:renkataoka:20201231005629p:plain コンテナごとにサービス名などが記載されているため、どのコンテナが何に対応しているかが一目で分かりますね。

Application Stackを停止する

Composeによって起動したApplication Stackを停止するには、docker-compose downコマンドを実行すればよいです。このとき、デフォルトではボリュームをは削除されないため、削除したい場合は--volumesフラグを付けると良いそうです。


Docker ComposeによるApplication Stackの操作方法が分かったところで、このチャプターは終わりです。

次のチャプターでは、コンテナイメージをビルドする際のベストプラクティスを勉強します。