Swarm で Compose を使う¶
Docker Compose と Docker Swarm は完全な統合を目指しています。つまり、Compose アプリケーションを Swarm クラスタに適用したら、単一の Docker ホスト上で展開するのと同じように動作します。
使用する Compose ファイル形式のバージョン によって、統合できる範囲が異なります。
バージョン1で
links
(リンク機能)を使う場合、アプリケーションは動作します。しかし、Swarm は全てのコンテナを1つのホスト上にスケジュールします。これは古いネットワーキング・システム上ではホストを横断したコンテナが扱えないためです。
バージョン2であれば、アプリケーションを変更しなくても動作するでしょう。
主な 制限 については以下をご覧ください。
Swarm では オーバレイ・ドライバ の設定や、マルチホスト・ネットワーク機能をサポートするカスタム・ドライバが利用可能です。
Docker Machine で Swarm クラスタやオーバレイ・ドライバをセットアップする方法は、 マルチホスト・ネットワーク機能を始める をご覧ください。セットアップ後にアプリケーションをデプロイするには、次のように非常にシンプルです。
$ eval "$(docker-machine env --swarm <name of swarm master machine>)"
$ docker-compose up
Compose の制限¶
イメージ構築¶
Dockerfile を使ったイメージ構築は、Swarm 上では単一ホスト上でしか行えません。そのため、構築したイメージは対象のホスト上のみに存在しており、他のノードに配布できません。
Compose を複数のノードにスケールさせる課題がある時は、自分自身で構築したレジストリ(例: Docker Hub)にイメージを push し、 docker-compose.yml
で参照させてください。
$ docker build -t myusername/web .
$ docker push myusername/web
$ cat docker-compose.yml
web:
image: myusername/web
$ docker-compose up -d
$ docker-compose scale web=3
複数の依存関係¶
サービスが強制共用スケジューリング(force co-scheduling)型で複数の依存関係がある場合(以下の 自動スケジューリング をご覧ください)、 Swarm は異なったノード上でも依存関係を解決できるかもしれません。たとえば、以下の例では foo
が必要とする bar
と baz
を一緒にスケジュールします。
version: "2"
services:
foo:
image: foo
volumes_from: ["bar"]
network_mode: "service:baz"
bar:
image: bar
baz:
image: baz
問題は、Swarm が最初に bar
と baz
が別のノードにスケジュールしてしまう可能性です(この時点ではお互いの依存性はありません)。そうならないように、 foo
を適切なノードに置く必要があります。
正常に行うためには、 手動スケジューリング で、3つのサービスを同じノード上で確実に起動します。
version: "2"
services:
foo:
image: foo
volumes_from: ["bar"]
network_mode: "service:baz"
environment:
- "constraint:node==node-1"
bar:
image: bar
environment:
- "constraint:node==node-1"
baz:
image: baz
environment:
- "constraint:node==node-1"
ホスト側のポートとコンテナの再作成¶
サービスがホスト側のポートを 80:8000
のように割り当てる(マップする)場合があります。それが docker-compose up
の初回実行時であればエラーが出るかもしれません。
docker: Error response from daemon: unable to find a node that satisfies
container==6ab2dfe36615ae786ef3fc35d641a260e3ea9663d6e69c5b70ce0ca6cb373c02.
エラーが発生する一般的なケースは、明確な割り当てのない( イメージや Compose ファイルで定義されていない)ボリュームを持つコンテナを作成する場合です。その場合はデータ領域を予約するために、Compose は Swarm に対して、前に起動したコンテナと同じノード上に新しいコンテナをスケジュールします。この結果、ポートが衝突してしまう可能性があります。
この問題に対処する2つの解決策があります。
コンテナがボリュームをマウントできるボリューム・ドライバを使えば、ボリュームに名前を指定することで、コンテナがどのノードにスケジュールされても適切にマウントします。
Compose でサービスのボリュームに名前を付けるだけでは、Swarm に対してスケジューリングの指示を出しません。
version: "2"
services:
web:
build: .
ports:
- "80:8000"
volumes:
- web-logs:/var/log/web
volumes:
web-logs:
driver: custom-volume-driver
新しいコンテナを作成する前に、古いコンテナを削除したら、ボリュームの中のデータが失われます。
$ docker-compose stop web
$ docker-compose rm -f web
$ docker-compose up web
コンテナのスケジューリング¶
自動スケジューリング¶
コンテナを同じ Swarm ノード上に確実にスケジュールするための、複数のオプションがあります。オプションは次の通りです。
network_mode: "service:..."
と、network_mode: "container:..."
(と、バージョン1のフォーマットであればnet: "container:..."
)
volumes_from
links
手動スケジューリング¶
Swarm にはコンテナをどこに配置するかを制御できるようにするための、豊富なスケジューリング群と親和性の示唆(affinity hint;アフィニティ・ヒント)があります。これらはコンテナの環境を通して指定可能です。Compose では environment
オプションを使って設定できます。
# 特定のノードにコンテナをスケジュールする
environment:
- "constraint:node==node-1"
# 「storage」ラベルに「ssd」が設定されているノードにコンテナをスケジュールする
environment:
- "constraint:storage==ssd"
# 「redis」イメージをダウンロード済みのコンテナにスケジュールする
environment:
- "affinity:image==redis"
利用可能なフィルタと表現については、Swarm のドキュメント をご覧ください。
参考
- Using Compose with Swarm