Yuki's Tech Blog

仕事で得た知見や勉強した技術を書きます。

【さわって学ぶクラウドインフラ docker 基礎からのコンテナ構築】第7章 複数コンテナをまとめて起動するDocker Composeで知らなかったことをざっくりまとめてみた

目次

概要

実際のシステムでは、複数のコンテナを組み合わせる事が多いです(Webサーバーのコンテナ + DBサーバーのコンテナ等)。コンテナを組み合わせる時、コンテナをまとめて起動したり停止したりできると便利です。その仕組みがDocker Composeです。今回はDocker Composeを使用して、複数のコンテナをひとまとめにして操作する方法を学びます。

ブログシステムをDocker Composeなしで構築する

大まかな流れ

  1. Dockerネットワークを作成する
    コンテナ同士を繋ぐのに規定のbridgeネットワークを使ってもできますが、何のネットワークを使っているか分かりにくいので、新しくDockerネットワークを作成します。
  2. ブログのデータを保存するためのボリュームを作る
    MySQLコンテナのDBのデータ永続化に用いるためのボリュームを作成します。
  3. MySQLコンテナを作る
  4. WordPressコンテナを作る

Docker Composeを使わないでブログシステムを構築したときの問題点

Dockerネットワークを作って、--netオプションで指定すれば、複数のコンテナを組み合わせて使う事は容易です。しかし、コンテナの起動や停止、オプションの指定等をコンテナの数に比例して実行しなければならないです。また、ボリュームやDockerネットワークを使う場合、あらかじめ作成する必要があります。コンテナを使い終わって削除するときは、不要になったネットワークも削除する必要があります。

このような操作を手動でやるのはとてもめんどくさいです。 こうしたコンテナの作成や停止、破棄の一連の操作をまとめて実行する仕組みがDocker Composeです。

Docker Composeの仕組み

Docekr Composeでは、あらかじめコンテナの起動方法やボリューム、ネットワークの構成などを書いた定義ファイル(docker-compose.yml)を用意しておき、その定義ファイルを読み込ませることで、まとめて実行します。

(※) 定義ファイルは「Composeファイル」と呼ばれ、既定では「docker-compose.yml」というファイル名です。

(注) Docker Composeを使う場合、定義ファイルやコピーしたいファイルなどは、一つの作業用ディレクトリにまとめておきます。

Docker Composeの4つのメリット

  1. 長い引数からの解放
    docker run(もしくはdocker create)の際、長い引数を指定する必要がなくなります。

  2. 複数コンテナの連動
    複数のコンテナをまとめて起動できます。起動順序の指定もできます。

  3. まとめて指定・破棄
    定義したコンテナをまとめて停止したり、破棄したりできます。

  4. コンテナの起動時の初期化やファイルコピー
    コンテナ起動後にコマンドを実行したりファイルをコピーしたりする初期化などの操作を行えます。

Docker Composeのインストール

Docker Composeは、Docker操作の補佐をするPython製のツールです。Docker Engineの一部ではないです。 そのため、Docker Engineとは別にインストールする必要があります。 いくつかの方法がありますが、今回はpipコマンドでインストールします。ptyhonをインストールした後に、Docker Composeをインストールします。

sudo apt install -y python3 python3-pip
sudo pip3 install docker-compose

インストールできたら、docker-compose --versionで確認します。

ubuntu@ip-10-0-12-65:~$ docker-compose --version
docker-compose version 1.29.2, build unknown

Docker Composeで複数のコンテナを一気に起動させてみる

WordPressコンテナとMySQLコンテナを起動するという行程を、Docker Composeで実現します。Docker Composeを使うには何か作業用のディレクトリを作り、そこにdocker-compose.ymlファイルを配置します。

docker-compose.ymlは「YAML形式」と呼ばれる形式のファイルです。YAML形式では、空白によるインデント(字下げ)で構造ブロックを表現します。インデントが間違っていると、正しく動作しません。インデントは「空白2つ」 or 「空白4つ」が一般的です。

↓ docker-compose.yml

version: "3"

services:
  wordpress-db:
    image: mysql:5.7
    networks:
      - wordpressnet
    volumes:
      - wordpress_db_volume:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpassword
      MYSQL_DATABASE: wordpressdb
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspass

  wordpress-app:
    depends_on:
      - wordpress-db
    image: wordpress
    networks:
      - wordpressnet
    ports:
      - 8080:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_NAME: wordpressdb
      WORDPRESS_DB_USER: wordpressuser
      WORDPRESS_DB_PASSWORD: wordpresspass

networks:
  wordpressnet:

volumes:
  wordpress_db_volume:

その後、 docker-compose.ymlを置いたディレクトリをカレントディレクトリとして、docker-composeのupコマンドを実行してコンテナを起動させます。 ちなみにdocker-composeコマンドは次の書式で実行します。

docker-compose コマンド オプション 引数
docker-compose up -d

コンテナの命名規則

docker-composeで立ち上げたコンテナの名前は、以下のような命名規則になっています。 dockerコマンドでdocker-composeで立ち上げたコンテナを操作する場合、この長い名前を指定する必要があります。docker-composeコマンドでdocker-composeで立ち上げたコンテナを操作する場合、サービス名で指定することができます。そのため、docker-composeで立ち上げたコンテナは、docker-composeコマンドで操作しましょう。

作業用ディレクトリ名_コンテナ名_1
ubuntu@ip-10-0-12-65:~/wordpress$ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                                   NAMES
bc7c7782c476   wordpress   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   wordpress_wordpress-app_1
bc29fd390a0c   mysql:5.7   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   3306/tcp, 33060/tcp                     wordpress_wordpress-db_1

(※) 1というのは「1つ目」ということを意味します。docker composeでscaleオプションを指定すると、docker-composeファイルに記述している同じコンテナを2つ、3つと複数起動できます。その場合、「_2」「_3 」といった命名規則になります。

↓ 代表的なdocker-composeのコマンドとdockerコマンドとの対応

docker-composeのコマンド 対応するdockerコマンド 説明
docker-compose exec docker exec コンテナ内でコマンドを実行する。docker execでは「-it」オプションをつけていましたが、docker-compose execには不要です。つけなくてもキーボードがコンテナとつながります。

docker-composeで管理する

docker-composeで作成したコンテナは普通のコンテナと一緒です。ネットワークやボリュームについても同様です。これらのコンテナをdocker stopしたり、docker rmすることもできます。ネットワークやボリュームも同様です。しかし、そうすると、docker-composeツールから操作した状態と反故(ほご)が生じて、管理しにくくなります。 そのため、docker-composeで作成したコンテナは、docker-composeを使った管理に一元化しましょう。

コンテナの停止と破棄

docker-composeで起動したコンテナを停止・破棄するためには、docker-compose downコマンドを使います。コンテナやネットワークを停止するだけではなく、それらを破棄します。つまりdocker-copose upする前に戻します。しかし、ボリュームに関しては、削除されたらデータが永続化されないので、docker-compose downを実行しても削除されないです。

docker-compose down
ubuntu@ip-10-0-12-65:~/wordpress$ docker-compose down
Stopping wordpress_wordpress-app_1 ... done
Stopping wordpress_wordpress-db_1  ... done
Removing wordpress_wordpress-app_1 ... done
Removing wordpress_wordpress-db_1  ... done
Removing network wordpress_wordpressnet
ubuntu@ip-10-0-12-65:~/wordpress$ docker-compose ps
Name   Command   State   Ports
------------------------------
ubuntu@ip-10-0-12-65:~/wordpress$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
49ea1ad2bf81   bridge    bridge    local
d8850b15265b   host      host      local
a8e3cb52fef7   none      null      local
ubuntu@ip-10-0-12-65:~/wordpress$ docker volume ls
DRIVER    VOLUME NAME
local     258ed8c33ff297aa10a214fd7d090579f94709ac887b01c56acfb2ec78f53337
local     8316dad9e908e23bdba6a139317e6cee834656a46e169414e9c3f25fcd2a3aec
local     wordpress_wordpress_db_volume
ubuntu@ip-10-0-12-65:~/wordpress$

(注) 起動時(docker-compose up)と破棄時(docker-compose down)で、docker-compose.ymlファイルが異なる場合、注意が必要です。docker-compose downは、実行時にカレントディレクトリに置かれているdocker-compose.ymlファイルを見て操作します。そのため、起動時の状態を把握しているわけではありません。docker-compose upをした後にdocker-compose.ymlを書き換えて、docker-compose downをしたときにコンテナやネットワークの削除残しや、意図しない削除が発生しないように注意しましょう。

YAML形式の書き方

設定値の書き方

設定値は「設定項目: 設定値」のように「:」で区切って記述します。改行は入れても入れなくても同じです。文字列を指定する場合は、「"」 または「'」で囲みます。半角スペースに関しては、おそらく入れても入れなくてもどっちでもいいと思われます。

version: "3"
image: mysql:5.7

上の表記は以下のように書くこともできます。

version: 
  "3"
image: 
  mysql:5.7

複数値の書き方

一つの設定項目に複数の値を設定したい場合、「- 設定値」のように、「-」で区切って記述します。 複数値を設定しなくても、「- 設定値」のような書き方をすることもできます。その場合は、今後、複数の値を設定する可能性があると考えられます。

ports:  
  - 8080:80
volumes:
  - ./frontend:/var/app:cached
  - node-data:/var/app/node_modules:delegated

ハッシュのネスト

半角スペースでインデントすることで、ハッシュをネストさせることができます。

    environment:
      MYSQL_ROOT_PASSWORD: myrootpassword
      MYSQL_DATABASE: wordpressdb
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspass

コメント

「#」を記述すると、それ以降から行末までがコメントとみなされ、無視されます。

docker-compose.ymlの書き方

docker-compose.ymlでは、「サービス」「ネットワーク」「ボリューム」の3つを定義します。

  1. サービス
    全体を構成する1つひとつのコンテナのことです。 Docker Composeにおいてサービスとは、ざっくり言うとコンテナのことです。

  2. ネットワーク
    サービス(つまりコンテナ)が参加するネットワークを定義します。

  3. ボリューム
    サービス(つまりコンテナ)が利用するボリュームを定義します。

docker-compose.ymlでは、これらの設定をインデントしたブロック単位で記述します。

(※) 厳密に言うと、scaleオプションを指定すると、1つのサービスに対して複数のコンテナを起動することができます。つまり、本当はサービスに対してコンテナが1対多の関係です。

バージョン番号

docker-compose.ymlの冒頭の「version」では、書式のバージョン番号を記述しています。 Docker Composeは、過去、何度かバージョンアップをしており、バージョンによってdocker-compose.ymlの書き方が少し違うので、どのバージョンなのかを指定するために「version」という項目が存在します。

version: "3"
version: "3.8"

サービス

「services」の部分では、サービス(すなわち、コンテナの定義)を記述します。

services: 
  サービスAの名前:
    サービスAの設定
 ...
  サービスBの名前:  
    サービスBの設定

代表的なサービスの設定項目を以下にまとめます。

項目 docker runの対応オプション 意味
env_file なし 環境設定情報を書いたファイルを読み込む
environment -e 環境変数を設定する
ports -p ポートのマッピングを設定する
volumes -v, --mount バインドマウントやボリュームマウントなどを設定する
depends_on なし 別のサービスに依存することを示す。docker-compose upするときやdocker-compose downするときに、指定したサービスが先に起動(もしくは終了)するようになる
image イメージ引数 利用するイメージを指定する。このイメージをもとにコンテナを作成する
networks -net 接続するネットワークを指定する。ネットワークはdocker-compose.ymlのnetworksのところで定義していなければならない。この設定配下に「ipv4_address」「ipV6_address」を記述すると、固定IPを割り当てることもできる。
restart なし docker compose upなどで起動する際、コンテナが停止した時の再試行ポリシーを設定する。no, always, on-failure, unless-stoppedなどがある。alwaysは終了ステータスに関わらず、いつも再起動する(明示的にdocker-compose stopで止めた場合は除く)

ネットワーク

ネットワークは、networksの部分で定義します。Dockerネットワークの名前だけを指定していますが、オプションでIPアドレス範囲なども指定できます。

networks:
  Dockerネットワーク名:

(注) 実はネットワークの設定を省略することができます。Docker-Composeでは明示的にネットワークを指定しなかったときは、記述しているサービス(コンテナ)がつながる新しいDockerネットワークを自動的に作成し、全てのサービスを、そのネットワークに接続するように構成します(docker-compose downすれば、そのネットワークは、もちろん、自動的に削除されます)。この場合でも、サービス名を宛先として指定して通信できます。そのため、明示的にネットワークを設定しなければならない必然性はなく、むしろ指定が省略されることの方が多いです。

↓ ネットワークを省略した場合のdocker-compose.yml

version: "3"

services:
  wordpress-db:
    image: mysql:5.7
    volumes:
      - wordpress_db_volume:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpassword
      MYSQL_DATABASE: wordpressdb
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspass

  wordpress-app:
    depends_on:
      - wordpress-db
    image: wordpress
    ports:
      - 8080:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_NAME: wordpressdb
      WORDPRESS_DB_USER: wordpressuser
      WORDPRESS_DB_PASSWORD: wordpresspass

volumes:
  wordpress_db_volume:

ボリューム

コンテナが利用するボリュームは、volumesの部分で定義します。名前だけを指定するでもOKですが、オプションでマウント方法などを指定することもできます。 既定では、ボリュームが存在しない場合は作られ、作られたボリュームはdocker-compose downしても、削除されません(そうでないと、ボリュームに永続して保存したいデータを残せません)。

volumes:
  wordpress_db_volume:

docker-composeコマンドとdockerコマンドで実行する場合の3つの違い

  1. docker-compose.ymlが必要
    docker-composeコマンドは、カレントディレクトリに置かれたdocker-compse.ymlを読み込みます。このファイルがなければ失敗します。

  2. サービス名で指定する
    dockerコマンドはコンテナ名またはコンテナIDで指定するのに対し、docker-composeではdocker-compose.ymlのservicesの部分に書かれたサービス名を指定します。

  3. 依存関係が考慮される
    docker-composeでは、depends-onで記述された依存関係が考慮されます。例えば、wordpress-appはwordpress-dbに依存しているため、「docker-compose start wordpress-app」としたときは、wordpress-dbが先に起動します。同様に、「docker-compose stop wordpress-app」としたときは、wordpress-appが終了した後、wordpress-dbも終了します。

docker-composeコマンドで立ち上げたコンテナは、docker-composeコマンドで操作した方がコンテナ名の指定が楽だったり、依存関係が考慮されるので、docker-composeコマンドで立ち上げたコンテナは、docker-composeコマンドで操作した方が良いです。

参考記事

さわって学ぶクラウドインフラ docker基礎からのコンテナ構築 | 大澤 文孝, 浅居 尚 |本 | 通販 | Amazon

コンテナを自動的に開始 — Docker-docs-ja 19.03 ドキュメント

プログラマーのための YAML 入門 (初級編)