フィルタ¶
Docker Swarm
スケジューラは複数のフィルタを持っています。
ノードの一部(サブセット)にコンテナをスケジュールする時、次のフィルタが利用できます。
利用可能なフィルタを指定するには、 swarm manage
の実行時に --filter
フラグを使って指定します。
Constraint (コンストレイント)フィルタ¶
Constraint(訳者注:制約や制限の意味)は、特定のノードをキー・バリューの組で結び付けます。これらの情報は node のタグとして確認できます。
コンテナを作成時、ノードを配置するグループ(サブセット)を選べます。グループとは、コンテナのスケジューリングにあたり、1つまたは複数のキー・バリューの組が一致すると考えられるものです。この方法には、複数の指定方法があります。
- ホスト・プロパティを指定した選択(
storage=ssd
のように、特定のハードウェアにコンテナをスケジュールするため) - ノードの基盤に、物理的な場所をタグ付けする(
region=us-ease
のように、指定した場所でコンテナを強制的に実行) - 論理的なクラスタの分割(
environment=production
のように、プロパティの違いによりクラスタを複数のサブクラスタに分割)
ノードに対して特定のキー・バリューの組み合わせをタグ付けするには、docker 起動時のオプションで、少なくとも1つの --label
指定が必要です。
例えば、 node-1
を起動するとき storage=ssd
ラベルを付けてみましょう。
$ docker -d --label storage=ssd
$ swarm join --advertise=192.168.0.42:2375 token://XXXXXXXXXXXXXXXXXX
ただし次は node-2
を storage=disk
で起動します:
$ docker -d --label storage=disk
$ swarm join --advertise=192.168.0.43:2375 token://XXXXXXXXXXXXXXXXXX
ノードがクラスタに登録されると、マスタは各々のタグを取得し、新しいコンテナをスケジューリングするときにそれらを反映します。
それでは MySQL サーバを起動し、良い I/O 性能を持つフラッシュ・ドライブ上で利用できるようにしましょう:
$ docker run -d -P -e constraint:storage==ssd --name db mysql
f8b693db9cd6
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
f8b693db9cd6 mysql:latest "mysqld" Less than a second ago running 192.168.0.42:49178->3306/tcp node-1 db
この例では、マスタは選択された全てのノードから、事前に指定された storage=ssd
を強制したリソース管理を適用します。 node-1
は フラッシュ・ドライブ上で動いているホストが選ばれています。
次はクラスタ上に Nginx フロントエンドを走らせてみます。ですが、ログをディスクに沢山書き込むのでフラッシュ・ドライブを使いたくありません。
$ docker run -d -P -e constraint:storage==disk --name frontend nginx
963841b138d8
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
963841b138d8 nginx:latest "nginx" Less than a second ago running 192.168.0.43:49177->80/tcp node-2 frontend
f8b693db9cd6 mysql:latest "mysqld" Up About a minute running 192.168.0.42:49178->3306/tcp node-1 db
スケジューラは storage=disk
ラベルを付けて起動済みの node-2
で起動します。
標準制約(Standard Constraint)¶
さらに、ノードを開始するときに特に指定していなくても、コンテナのスケジュールに使う標準 constraint セットを使えます。これらのタグは docker info で確認できるものです。現在利用できるのは次の通りです。
- ノード ID またはノード名(”node” をキーに用いる)
- storagedriver(ストレージ・ドライバ)
- executiondriver(実行ドライバ)
- kernelversion(カーネルバージョン)
- operatingsystem(オペレーティング・システム)
Affinity(アフィニティ)フィルタ¶
コンテナ間を”引き寄せて” を作成するのに、–affinity:<フィルタ> を使うことができます(訳者注:affinity とは親密さの意味)。例えば、あるコンテナを実行したとします。別のコンテナを実行するとき、特定のイメージやラベルを持つコンテナのある場所で実行できます。この引き寄せ機能によって、コンテナを同じネットワーク・ノード上で確実に動かせます。そのとき、どのノードで実行しているかを知る必要はありません。
コンテナの親密さ(affinity)¶
新しいコンテナを、既存のコンテナ名や ID を基にしてスケジューリングできます。例えば、 frontend
という名前で nginx
を実行します。
$ docker run -d -p 80:80 --name frontend nginx
87c4376856a8
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1 frontend
それから、 -e affinity:container==frontend
フラグを使い、2つめのコンテナを frontend
の隣にスケジュールします。
$ docker run -d --name logger -e affinity:container==frontend logger
87c4376856a8
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1 frontend
963841b138d8 logger:latest "logger" Less than a second ago running node-1 logger
コンテナ名のアフィニティ指定によって、 logger
コンテナは frontend
コンテナと同じ node-1
コンテナで実行されることになります。 frontend
という名前だけでなく、次のように ID を使った指定もできます
docker run -d --name logger -e affinity:container==87c4376856a8
イメージ・アフィニティ¶
コンテナを起動するとき、特定のイメージをダウンロード済みのノードのみにスケジュールすることができます。
$ docker -H node-1:2375 pull redis
$ docker -H node-2:2375 pull mysql
$ docker -H node-3:2375 pull redis
node-1
と node-3
のみが redis
イメージを持っています。 -e affinity:image==redis
フィルタを使い、これらのノード上でスケジュールします。
$ docker run -d --name redis1 -e affinity:image==redis redis
$ docker run -d --name redis2 -e affinity:image==redis redis
$ docker run -d --name redis3 -e affinity:image==redis redis
$ docker run -d --name redis4 -e affinity:image==redis redis
$ docker run -d --name redis5 -e affinity:image==redis redis
$ docker run -d --name redis6 -e affinity:image==redis redis
$ docker run -d --name redis7 -e affinity:image==redis redis
$ docker run -d --name redis8 -e affinity:image==redis redis
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
87c4376856a8 redis:latest "redis" Less than a second ago running node-1 redis1
1212386856a8 redis:latest "redis" Less than a second ago running node-1 redis2
87c4376639a8 redis:latest "redis" Less than a second ago running node-3 redis3
1234376856a8 redis:latest "redis" Less than a second ago running node-1 redis4
86c2136253a8 redis:latest "redis" Less than a second ago running node-3 redis5
87c3236856a8 redis:latest "redis" Less than a second ago running node-3 redis6
87c4376856a8 redis:latest "redis" Less than a second ago running node-3 redis7
963841b138d8 redis:latest "redis" Less than a second ago running node-1 redis8
ここで見えるように、コンテナがスケジュールされるのは redis
イメージを持っているノードのみです。イメージ名に加えて、特定のイメージ ID も指定できます。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
redis latest 06a1f75304ba 2 days ago 111.1 MB
$ docker run -d --name redis1 -e affinity:image==06a1f75304ba redis
ラベル・アフィニティ¶
ラベル・アフィニティによって、コンテナのラベルで引き寄せてセットアップできます。例えば、 nginx
コンテナを com.example.type=frontend
ラベルをつけて起動します。
$ docker run -d -p 80:80 --label com.example.type=frontend nginx
87c4376856a8
$ docker ps --filter "label=com.example.type=frontend"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1 trusting_yonath
それから、 -e affinity:com.example.type==frontend
を使って、 com.example.type==fronten
ラベルを持つコンテナの隣にスケジュールします。
$ docker run -d -e affinity:com.example.type==frontend logger
87c4376856a8
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NODE NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1 trusting_yonath
963841b138d8 logger:latest "logger" Less than a second ago running node-1 happy_hawking
logger
コンテナは、最終的に node-1
に置かれます。これはアフィニティに com.example.type==frontend
ラベルを指定しているからです。
文法表現¶
アフィニティや制約は、 key
と value
の組み合わせで表現します。 key
は英数字のパターンに従います。ただし、先頭はアルファベットかアンダースコアです。 value
は次のようなものです。
- 英数字の文字列、ドット、ハイフン、アンダースコア。
- 部分一致、例えば
abc*
。 /regexp/
形式の正規表現。Go 言語の正規表現構文をサポート。
現時点の Swarm は、アフィニティ・constraint で演算子 ==
と !=
をサポートしています。
constraint:node==node1
は、ノードnode1
に一致。constraint:node!=node1
は、node1
をのぞく全てのノードに一致。constraint:region!=us*
は、us
が付いているリージョン以外のノードに一致。constraint:node==/node[12]/
は、node1
とnode2
に一致。constraint:node==/node\d/
は、node
+ 10進数の1文字に一致。constraint:node!=/node-[01]/
は、node-0
とnode-1
以外の全てのノードに一致。constraint:node!=/foo\[bar\]/
は、foo[var]
以外の全てのノードに一致。constraint:node==/(?i)node1/
は、大文字・小文字を区別しないnode1
に一致。そのため、NoDe1
やNODE1
も一致する。
Soft アフィニティ・制約の設定¶
デフォルトでは、アフィニティと制約は厳密(ハード)に強制されるものです。アフィニティや制約で指定した条件に対応するノードがなければ、コンテナはスケジュールされません。Soft affinities/constrains (ソフト設定)があれば、スケジュールが一致するルールを探そうとします。もし一致しなければ、スケジューラはフィルタを廃棄し、コンテナはスケジューラのストラテジに従ってスケジュールします
アフィニティと制約のソフト設定は ~
で指定します。例えば、次のように指定します。
$ docker run -d --name redis1 -e affinity:image==~redis redis
もし、クラスタにイメージ redis
を持つノードが無ければ、スケジューラはアフィニティを破棄し、ストラテジに従ってスケジュールします。
$ docker run -d --name redis2 -e constraint:region==~us* redis
もし、 us
リージョンに属すノードがクラスタに無ければ、スケジューラは制約を破棄し、ストラテジに従ってスケジュールします。
$ docker run -d --name redis5 -e affinity:container!=~redis* redis
アフィニティ・フィルタは新しい redis5
コンテナを、指定した redis*
の名前を含むコンテナが無いノードにスケジュールします。もしクラスタの各々のノードが redis*
コンテナを持っている場合、スケジューラはアフィニティのルールを破棄し、ストラテジに従ってスケジュールします。
ポート・フィルタ¶
ports
フィルタは、ユニーク(未使用)なリソースを探し出します。
$ docker run -d -p 80:80 nginx
87c4376856a8
$ docker ps
CONTAINER ID IMAGE COMMAND PORTS NODE NAMES
87c4376856a8 nginx:latest "nginx" 192.168.0.42:80->80/tcp node-1 prickly_engelbart
Docker クラスタから、パブリックのポート 80
が利用可能なノードを選択し、コンテナの実行をスケジュールします。この例では node-1
が該当します。
他のコンテナでパブリックのポート 80
で起動しようとするなら、既に node-1
は使用中のため、別のノードが選ばれることになります。
$ docker run -d -p 80:80 nginx
963841b138d8
$ docker ps
CONTAINER ID IMAGE COMMAND PORTS NODE NAMES
963841b138d8 nginx:latest "nginx" 192.168.0.43:80->80/tcp node-2 dreamy_turing
87c4376856a8 nginx:latest "nginx" 192.168.0.42:80->80/tcp node-1 prickly_engelbart
再び同じコマンドを実行すると、ポート 80
が使えない node-1
や node-2
ではなく、 node-3
が選ばれます。
$ docker run -d -p 80:80 nginx
963841b138d8
$ docker ps
CONTAINER ID IMAGE COMMAND PORTS NODE NAMES
f8b693db9cd6 nginx:latest "nginx" 192.168.0.44:80->80/tcp node-3 stoic_albattani
963841b138d8 nginx:latest "nginx" 192.168.0.43:80->80/tcp node-2 dreamy_turing
87c4376856a8 nginx:latest "nginx" 192.168.0.42:80->80/tcp node-1 prickly_engelbart
最終的に、クラスタ上でポート 80
が利用可能なノードが無くなると、Docker Swam はコンテナの実行を拒否します。
$ docker run -d -p 80:80 nginx
2014/10/29 00:33:20 Error response from daemon: no resources available to schedule container
ホスト・モードでのポートフィルタ¶
Docker を --net=host
を使ったホスト・モードで実行すると、デフォルトの bridge
モードとは異なり、ポートのバインディングができない host
モードになります。そのため、1つ以上のポート番号を明示する必要があります( Dockerfile で EXPOSE
を使うか、コマンドラインで --expose
を使います )。Swarm がこの情報を使うのは、 host
モードで新しいコンテナが利用可能なノードを選ぶときです。
例えば、以下のコマンドは nginx を3つのノード・クラスタで起動します。
$ docker run -d --expose=80 --net=host nginx
640297cb29a7
$ docker run -d --expose=80 --net=host nginx
7ecf562b1b3f
$ docker run -d --expose=80 --net=host nginx
09a92f582bc2
ポートの利用情報は、 docker ps
コマンドを通して利用可能です。これは全てのノードが host モードで起動されているためです。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
640297cb29a7 nginx:1 "nginx -g 'daemon of Less than a second ago Up 30 seconds box3/furious_heisenberg
7ecf562b1b3f nginx:1 "nginx -g 'daemon of Less than a second ago Up 28 seconds box2/ecstatic_meitner
09a92f582bc2 nginx:1 "nginx -g 'daemon of 46 seconds ago Up 27 seconds box1/mad_goldstine
4つめのコンテナを準備しようとしても、Swarm は拒否するでしょう。
$ docker run -d --expose=80 --net=host nginx
FATA[0000] Error response from daemon: unable to find a node with port 80/tcp available in the Host mode
そのかわり、ポート 81
のような、異なったポートをバインドすることはできます。
$ docker run -d -p 81:80 nginx:latest
832f42819adc
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
832f42819adc nginx:1 "nginx -g 'daemon of Less than a second ago Up Less than a second 443/tcp, 192.168.136.136:81->80/tcp box3/thirsty_hawking
640297cb29a7 nginx:1 "nginx -g 'daemon of 8 seconds ago Up About a minute box3/furious_heisenberg
7ecf562b1b3f nginx:1 "nginx -g 'daemon of 13 seconds ago Up About a minute box2/ecstatic_meitner
09a92f582bc2 nginx:1 "nginx -g 'daemon of About a minute ago Up About a minute box1/mad_gol
依存関係フィルタ¶
このフィルタは、コンテナの依存関係により、同じノード上にスケジュールするものです。
現時点では、次の依存関係を宣言できます。
- ボリューム共有:
--volumes-from=dependency
- リンク:
--link=dependency:alias
- 共有ネットワーク層:
--net=container:dependency
Swarm は依存関係のある同じノード上にコンテナを設置しようとします。もし実行できなそうであれば(依存関係のコンテナが存在しなかったり、ノードに十分なリソースが無い場合)、コンテナは作成されません。
必要であれば、複数の依存関係を組み合わせることもできます。例えば、 --volumes-from=A --net=container:B
は、コンテナ A
と B
を同じノード上に置こうとします。しかし、これらのコンテナが別々のノードで動いているなら、Swarm はコンテナのスケジューリングを行いません。
ヘルス・フィルタ¶
ヘルスフィルタは、障害が発生しているノードへのスケジューリングを阻止します。