複数のDockerコンテナを自動で立ち上げる構成管理ツール「Docker Compose」(Dockerの最新機能を使ってみよう:第7回)

複数のコンテナを組み合わせた構成でサービスを運用している場合、コンテナに対し特定のパラメータを指定したり、特定の順序での起動が必要となるケースがある。こういった作業を自動化するツールが、「Docker Compose」だ。

Dockerコンテナの管理を支援する純正ツール「Docker Compose」

Docker ComposeはDockerが開発するコマンドラインツールで、あらかじめ用意しておいた設定ファイルに従ってコンテナを起動するツールだ。設定ファイルには複数のコンテナに関する記述が可能で、コンテナの起動オプションやコンテナに与える環境変数など、さまざまな設定も同時に記述できる。

また、コンテナ同士の依存関係を設定することも可能で、これによって関連するコンテナを複数まとめて起動することも可能だ(図1)。

図1 Docker Composeによるサービスの立ち上げ
図1 Docker Composeによるサービスの立ち上げ

 この場合、設定された依存関係に応じて適切な順番でコンテナが起動されるようになっており、コマンド1つで簡単に必要なサービスを開始できるようになっている。逆にコンテナを停止させる際も、自動的に適切な順番でコンテナを停止させるようになっている。

また、以前紹介したDocker Swarmとの統合機能も提供されており、コンテナを複数実行させる(スケールさせる)操作も可能だ。コンテナの実行だけでなくビルド操作もサポートされている。

Docker Composeの利用ケース

Docker Composeを活用できるケースとしては、まずソフトウェアの開発/テスト環境が挙げられる。昨今ではデータベースやキャッシュ、フロントエンドといった役割毎に複数のサーバーを用意し、それらを組み合わせてサービスを構築する例が多い。こういった場合、開発/テスト環境でもそれらをすべて用意する必要がある。それらをコンテナの形で用意しておき、それらを起動するためのオプション設定などをDocker Composeの設定ファイルに記述しておけば、コマンドを1つ実行するだけでテスト環境を立ち上げられるようになる。

また、7月末にリリースされたDocker 1.12では「docker stack」という機能が実験的に導入された。これを利用することで、Docker Compose向けに定義したコンテナの設定等をそのまま利用してDockerクラスタ内でコンテナを稼動させられるようになる。これにより、Docker Composeを使って作ったテスト環境を、容易に実運用環境に移行させられるようになることが期待される。

Docker Composeのインストールと使い方

それでは、Docker Composeの使い方について紹介していこう。Docker Composeは現在WindowsおよびLinux、Mac OS X向けのバイナリファイルが提供されており、GitHubのdocker/composeプロジェクトのリリースページから入手が可能だ。

なお、WindowsおよびMac OS X向けのDocker関連ツール集「Docker Toolbox」にはDocker Composeが含まれているので、こちらを使ってDockerをインストールした場合は別途Docker Composeをインストールする必要はない。ただし、バージョンが古い可能性はあるので、以下の例のように「docker-compose」コマンドを「-v」オプション付きで実行してバージョンを確認しておこう。

$ docker-compose -v
docker-compose version 1.8.0, build f3628c7

なお、記事執筆時点での最新版はバージョン1.8だ。

Docker ComposeはDockerやほかのDocker関連ツールと同様にGo言語で実装されており、バイナリファイル1つで動作する。GitHubで公開されているバイナリファイルは圧縮されていないので、これをダウンロード後適当な名前にリネームし、/usr/local/binなどのパスが通ったディレクトリにコピーすれば利用が可能になる。

Docker Composeのサブコマンド

「docker-compose」コマンドでは、表1のサブコマンドが用意されている。このうち「build」や「create」、「exec」、「kill」など、dockerコマンドのサブコマンドと同じ名称のものは基本的に同様の処理を行うものと考えて良い。ただし、docker-composeではあらかじめ設定ファイルに記述しておいたコンテナのみを対象とする点が異なる。また、「down」や「up」、「scale」、「bundle」といったdocker-compose特有のコマンドもある。こちらについては後述する。

表1 docker-composeのサブコマンド
コマンド名 説明
build 設定ファイルに従ってコンテナのビルドを実行する
bundle クラスタ環境でコンテナを起動するためのbundleファイルを作成する
config 設定ファイルの内容を表示する
create 設定ファイルに従ってコンテナを作成する
down 作成したコンテナを停止し、コンテナおよび関連リリースを削除する
events コンテナから受信したイベントを表示する
exec 実行中のコンテナ内でコマンドを実行する
help ヘルプを表示する
kill コンテナにシグナルを送信して停止させる
logs コンテナが出力するログを表示する
pause コンテナを一時停止させる
port 公開ポートに関する情報を表示する
ps 管理しているコンテナの一覧を表示する
pull 管理しているコンテナをPullする
push 作成したコンテナイメージをPushする
restart 管理しているコンテナを再起動する
rm 管理しているコンテナを削除する
run 設定ファイルに記述されたコンテナを起動する
scale コンテナのインスタンス数を変更する
start 設定ファイルに従ってコンテナを起動する
stop 設定ファイルに従ってコンテナを停止される
unpause 停止させたコンテナを再開させる
up 設定ファイルに従ってコンテナを作成し実行させる
version docker-composeのバージョンを表示する

Docker Composeの設定ファイルとプロジェクト、サービス

Docker Composerでは、YAMLもしくはJSON形式で起動するコンテナなどの設定をファイルに記述する。デフォルトではカレントディレクトリ内の「docker-compose.yml」ファイルが設定ファイルとして使われるが、「-f <ファイル名>」オプションでそれ以外のファイルを設定ファイルとして使用することも可能だ。

なお、Docker Composeでは「サービス」と「プロジェクト」という単位でコンテナを管理する。コンテナとサービスは単に名前を言い換えただけで、基本的には同じものと考えて良い。また、「プロジェクト」は関連するコンテナをまとめて管理するための仕組みだ。Docker Composeの設定ファイルには複数のコンテナに関する設定が記述可能で、通常は同一の設定ファイルに記述されているコンテナは同じプロジェクトに属することになる。

デフォルトではプロジェクト名はdocker-composeコマンド実行時のカレントディレクトリが使用される。また、起動されるコンテナには次のような命名規則に従った名前が付けられて管理される。

<プロジェクト名>_<サービス名>_<インスタンス番号>

たとえば「test01」というディレクトリ内でdocker-composeコマンドを実行して「foobar」というサービスのコンテナを作成した場合、作成されたコンテナには「test01_foobar_1」という名前が付けられる。

なお、プロジェクト名は「-p <プロジェクト名>」オプションで明示的に指定することも可能だ。

Docker Composeが使用する設定ファイル

続いては、Docker Composeが使用する設定ファイルについて説明しよう。前述のとおり、Docker ComposeではYAMLもしくはJSON形式で設定ファイルを記述する。手作業で設定ファイルを記述する場合はYAMLのほうが書きやすいため、今回はYAML形式での設定ファイル記述について紹介する。

バージョン番号の記述

Docker Composeの設定ファイルにはバージョン1と2があり、バージョン2では一部の仕様が変更されていて互換性が失われている。設定ファイルのバージョンはファイル内の「version:」要素で指定でき、現在ではバージョン2の利用が推奨されている。本記事でも、原則としてバージョン2の設定ファイルを利用することにしている。

バージョン2形式で設定ファイルを記述するには、ファイル内に「version: '2'」と記述すれば良い。いっぽう「version: '1'」と記述されている、もしくはバージョンの記述がない場合はバージョン1形式の設定ファイルとして認識される。

設定ファイルの記述

設定ファイルの基本的な記述スタイルは以下のようになる。

version: '2'
services:
  <サービス名>:
    各サービスに関する設定
    

volumes:
  <ボリューム名>:
    各ボリュームに関する設定
    
    

networks:
  <ネットワーク名>:
    各ネットワークに関する設定
    
    

build:
  ビルドに関する設定
  
  

なお、「services」および「volumes」、「networks」、「build」のいずれも、設定項目がない場合は省略が可能だ。

コンテナやその起動オプションの記述

コンテナやその起動オプションに関しては、「services:」以下に記述する。ここでは「サービス名:」に続いてそのコンテナの起動時に与える環境変数やポート、ボリュームなどの設定を記述していく。もちろん、複数のサービスについて記述することも可能だ。

ここで記述できるパラメータは図2のとおりだ。それぞれの詳細については、Docker Composeのオンラインドキュメントを参照してほしい。

表2 指定できるサービスのパラメータ
パラメータ名 説明 対応する「docker run」コマンドのオプション
cap_add 指定したcapabilitiesを追加する --cap-add
cap_drop 指定したcapabilitiesを削除する --cap-drop
cgroup_parent cgroupにおけるparent groupを指定する --cgroup-parent
devices デバイスマッピングを指定する --device
depends_on 依存するサービスを指定する
dns 使用するDNSサーバーを指定する --dns
dns_search 名前解決時に使用する検索ドメインを指定する --dns-search
tmpfs コンテナにテンポラリファイルシステムをマウントする --tmpfs
entrypoint コンテナのエントリーポイントを上書きする --entrypoint
env_file 設定する環境変数とその値を指定する --env_file
environment 設定する環境変数とその値を指定する -e、--env
expose コンテナ外に公開するポートを指定する --expose
extends 別の設定ファイルを読み込む
external_links リンクを行うコンテナ名を指定する --link
extra_hosts コンテナの/etc/hostsファイルに指定したホスト名/IPアドレスの組み合わせを追加する --add-host
image コンテナの作成元イメージを指定する
labels コンテナに追加するラベルを指定する -l、--label
links リンクを行うコンテナを指定する --link
logging ログ設定をおこなう --log-driver、--log-opt
network_mode 使用するネットワークモードを指定する --net
networks 接続するネットワークを指定する --net
pid 「host」を指定することでホストとPIDを共有するようになる --pid
ports ポートを開放する -p、--publish
securty_opt セキュリティオプションを指定する --securty-opt
stop_signal コンテナを停止させる際にプロセスに送信するシグナルを指定する --stop-signal
ulimits コンテナ内で使用されるデフォルトのulimitsを指定する --ulimit
volumes コンテナ内にマウントするボリュームを指定する -v、--volume
volume_driver 使用するボリュームドライバを指定する --volume-driver
volumes_from ほかのコンテナのボリュームをマウントする --volumes-from
cpu_shares コンテナのCPU使用率制限を行う --cpu-shares
cpu_quota コンテナのCPU使用率制限を行う --cpu-quota
cpuset コンテナが使用するCPUを指定する --cpuset
domainname コンテナのドメイン名を指定する
hostname コンテナのホスト名を指定する
ipc コンテナでIPC名前空間を使用する
mac_address コンテナのMACアドレスを指定する --mac-address
mem_limit コンテナのメモリ使用量を制限する -m、--memory
memswap_limit コンテナのスワップメモリ使用量を制限する -memory-swap
privileged コンテナに拡張権限を適用する --privileged
read_only コンテナのルートファイルシステムをリードオンリーでマウントする --read-only
restart コンテナがすでに存在していた際の挙動を指定する --restart
shm_size コンテナが使用する共有メモリサイズを指定する --shm-size
stdin_open コンテナの標準入力をオープンしたままにする -i、--interactive
tty コンテナに疑似TTYを割り当てる -t、--tty
user コンテナを実行する際のユーザーを指定する -u、--user
working_dir コンテナ実行時の作業ディレクトリを指定する -w、--workdir

なお、networks設定内では各ネットワークに対し、以下のようにパラメータを指定する。

networks:
  <ネットワーク名1>:
    aliases: <そのコンテナのエイリアス(別名)>
    ipv4_address: <割り当てるIPv4アドレス>
    ipv6_address: <割り当てるIPv6アドレス>
  <ネットワーク名2>:
    aliases: <そのコンテナのエイリアス(別名)>
    ipv4_address: <割り当てるIPv4アドレス>
    ipv6_address: <割り当てるIPv6アドレス>
  
  

複数のコンテナの設定を1つの設定ファイルに記述する

前述のとおり、Docker Composerでは複数のコンテナの設定を1つの設定ファイル内に記述することができる。たとえばWordPressのテスト環境として、MySQLを実行するコンテナとHTTPサーバー、PHP、WordPresを実行するコンテナの2つを使用したい場合、次のように記述できる。

version: '2'
services:
  my_mysql:
    image: mysql:5.7
    volumes:
      - /var/test/mysql:/var/lib/mysql
      - /var/test/mysql_conf.d:/etc/mysql/conf.d
    environment:
      MYSQL_ROOT_PASSWORD: some_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress_password

  my_wordpress:
    image: wordpress:4.5-apache
    links:
      - my_mysql:mysql
    volumes:
      - /var/test/wp_plugins:/var/www/html/wp-content/plugins
    environment:
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress_password
      WORDPRESS_DB_NAME: wordpress
    ports:
      - 80:80

ここでは、「my_mysql」と「my_wordpress」という2つのサービスを定義している。前者がMySQLを実行させるサービス、後者がWordPressを実行させるサービスだ。my_mysqlサービスでは、「volumes」設定項目を使ってホスト上の/var/test/mysqlおよび/var/test/mysql_conf.dディレクトリをコンテナ内にマウントして使用している。また、いくつかの環境変数も指定している。これらの環境変数は、コンテナの起動時に自動でユーザーの作成/設定やデータベースの作成を行うためのものだ。詳細についてはDockerHubのmysqlページで解説されているので、そちらを参照して欲しい。

また、my_wordpressサービスでは、「links」設定項目を使って、先に定義している「my_mysql」サービスに対し「mysql」というホスト名でアクセスできるよう設定している。DockerHubで公開されているWordPressコンテナでは、デフォルトで「mysql」という名称のMySQLホストに接続するように構成されており、これだけでMySQLへ接続できるようになる(詳しくはDockerHubのwordpressページを参照)。また、「volumes」設定項目でホスト上に配置したプラグインのディレクトリをコンテナ内のWordPressのプラグインディレクトリにマウントするようにしている。このようにすることで、コンテナイメージ自身を修正することなく、任意のプラグインを追加することが可能になる。

この設定ファイルを作成したら、このdocker-compose.ymlファイルが格納されているディレクトリ内で次のようにdocker-composeコマンドを実行することで2つのコンテナが起動し、サービスが開始される。

# docker-compose up -d

なお、ここで指定されている「-d」オプションはそれぞれのコンテナをデタッチドモード(Detached mode)でバックグラウンドで起動させるオプションだ。これを付けないと、2つのコンテナがフォアグラウンドで起動するので注意したい。

コンテナの起動後、「docker ps」コマンドで稼動しているコンテナを確認すると、次のようにプロジェクト名(docker-compose.ymlファイルを格納したディレクトリ。ここでは「compose」)とサービス名(ここでは「my_wordpress」および「my_mysql」)、そしてインスタンス数(ここでは「1」)をアンダースコア(「_」)で繋いだ名前でコンテナが作成されていることが分かる。

# docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
df629ab197f3        wordpress:4.5-apache   "/entrypoint.sh apach"   5 minutes ago       Up 2 seconds        0.0.0.0:80->80/tcp       compose_my_wordpress_1
b328aae57177        mysql:5.7              "docker-entrypoint.sh"   5 minutes ago       Up 3 seconds        3306/tcp                 compose_my_mysql_1

また、「docker up」コマンドではサービス名を引数として指定することで、指定したサービスだけを起動することもできる。たとえば「my_mysql」サービスのみを起動したい場合、次のようにする。

docker-compose up -d my_mysql

起動したコンテナを停止させるには、同じディレクトリで「docker-compose down」コマンドを実行すれば良い。

# docker-compose down

なお、「docker-compose down」コマンドの実行後、停止されたコンテナは自動的に削除される。

コンテナ起動コマンドの挙動の違い

docker-composeコマンドでは、「up」以外にもコンテナを起動させるサブコマンドとして「create」や「run」、「start」が用意されている。createサブコマンドではコンテナの作成のみを行い、実行は行わない点が異なる。

また、runサブコマンドは環境変数や公開ポート、コンテナ内で実行するコマンドを詳細に指定できる点が異なる。作成されるコンテナ名がデフォルトでは「<プロジェクト名>_<サービス名>_run_<インスタンス番号>」になるのも相違点だ。

startサブコマンドは停止状態にある既存のコンテナを実行させるもので、createサブコマンドで作成したコンテナや、stopサブコマンドで停止させたコンテナを実行させる際に利用できる。

ボリュームやネットワークの設定

Docker Composerではコンテナだけでなく、ボリュームやネットワークの設定を設定ファイルに記述して自動作成させることも可能だ。この場合、設定ファイルの「volumes:」や「networks:」以下にそれぞれの情報を記述する。

たとえばボリュームについては、以下のように定義できる。

volumes:
  <ボリューム名1>:
    driver: <ドライバ名>
    driver_opts:
      <オプション1>: <値>
      <オプション2>: <値>
      
      
  <ボリューム名2>:
    driver: <ドライバ名>
    driver_opts:
      <オプション1>: <値>
      <オプション2>: <値>
      
      

また、ネットワークについては、以下のように定義できる。

networks:
  <ネットワーク名1>:
    driver: <ドライバ名>
    driver_opts:
      <オプション1>: <値>
      <オプション2>: <値>
      
      
  <ネットワーク名2>:
    driver: <ドライバ名>
    driver_opts:
      <オプション1>: <値>
      <オプション2>: <値>
      
      

ボリュームやネットワークについては、それぞれDockerのボリューム/ネットワーク機能と同様に設定が行える。Dockerのボリューム機能については「Dockerのボリュームプラグインとストレージドライバ(Dockerの最新機能を使ってみよう:第2回)」記事で、ネットワーク機能については「Dockerのマルチホストネットワークで複数ホスト間を繋ぐ仮想ネットワークを作る(Dockerの最新機能を使ってみよう:第1回)」記事で説明しているので、詳しくはそちらを参照して欲しい。

ビルド用の設定の記述

Docker Composeでは、コンテナイメージのビルドを行うための設定も記述できる。この設定は、「build:」以下に記述する。ただし、Docker Composeはあくまで「docker build」コマンドのラッパー的に動作するだけで、別途ビルド設定ファイル(Dockerfile)等が必要となる。

たとえば、compose.ymlファイルと同じディレクトリ内にあるbuildディレクトリ内にDockerfileやそのほかビルドに必要なファイルが格納されている場合、以下のようになる。

build:
  context: ./build  ←ビルドに必要なファイルが格納されているディレクトリ
  dockerfile: Dockerfile  ←使用するDockerfile
  args:  ←ビルド時に指定するオプションパラメータ
    <パラメータ1>: <値>
    <パラメータ2>: <値>
    
    

設定ファイルを分離する

docker-composeのデフォルトの動作では、カレントディレクトリのdocker-compose.ymlファイルに加えて、「docker-compose.override.yml」というファイルも設定ファイルとして認識して読み込もうとする。この際の挙動としては、まずdocker-compose.ymlファイルを読み込み、続いてdocker-compose.override.ymlファイルの内容をそれに追加/上書きする、という流れになる。また、docker-composeコマンドの「-f <設定ファイル>」オプションを複数使用することでも複数の設定ファイルを指定することが可能だ。こちらの場合、後から指定したファイルの内容が先に読み込まれていた設定ファイルの内容に追加/上書きされる形になる。

これを利用することで、1つのファイルには共通して利用する設定を記述し、環境毎に異なる設定については2つめのファイルに記述する、といったような、複数のファイルに設定内容を分割して記述することが可能となる。

将来的にはDockerのクラスタ機能との連動も可能に

現時点では、Docker Composeでは単一のホスト、もしくはDocker Swwarmを利用して構築されたDockerクラスタでの利用しかサポートされていない。7月末にリリースされたDocker 1.12では「Swarm Mode」と呼ばれるクラスタ機構が導入されたものの、Docker ComposeとSwarm Modeを直接組み合わせて利用することはできないのだが、その代わりにDocker 1.12で実験的に実装されている「Stacks」という機能を利用して、Docker Composeの設定ファイルをベースにSwarm Modeを使ったクラスタ上でコンテナを実行できるようになっている。

Stacks機能についてはまだ実験的という段階であるため詳しくは紹介しないが、簡単に説明するとdocker-composeコマンドの「bundle」サブコマンドを実行することで、Stacksで使用される「distributed application bundle」と呼ばれる設定ファイルを作成でき、これをdockerコマンドの「deploy」サブコマンドの引数として与えて読み込ませることで、複数のコンテナをDockerクラスタ上にデプロイできる、というものになっている。

近年Dockerは「オーケストレーション」と呼ばれる、クラスタの構築やコンテナのデプロイなどに注力しているが、複数コンテナの自動デプロイについてはDocker本体には取り込まれていなかった。しかし、DockerのStacks機能でついにそれが実現することになる。

Docker Composeは複数のコンテナを立ち上げる場合だけでなく、多数のオプションをコンテナに指定するようなケースでも便利だ。DockerのStacks機能の予習の意味も含めて、一度試してみてはいかがだろうか。