LoginSignup
7
6

More than 5 years have passed since last update.

フィルタ

原文:https://docs.docker.com/swarm/scheduler/filter/

Docker Swam スケジューラは複数のフィルタを持っています。

ノードのサブセット(一部)にコンテナをスケジュールするとき、次のフィルタが利用できます:

  • Constraint(強制)
  • Affinity(親密さ)
  • Port(ポート)
  • Dependency(依存性)
  • Health(ヘルス)

何らかのフィルタを使いたいときは swam manage--filter フラグを使います。

Constraint フィルタ

Constraint は特定のノードに対してキー・バリューの組を結び付けます。これらは node タグで見られます。

コンテナの作成時、ノードのサブセットを選択することができます。これは、スケジューリングのために、特定のノード、あるいはキー・バリューの組で一致すべきと考えられるノードです。

この手法はいくつかの特定の使い方があります:

  • ホスト・プロパティを指定した選択(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-2storage=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 で起動します。

Constraints の標準

加えて、ノードを開始するときに特に指定しなくても、コンテナのスケジュールに使う標準 constraint セットを使えます。これらのタグは docker info で確認でき、現在利用できるのは:

  • ノード ID またはノード名("node" をキーに用いる)
  • storagedriver(ストレージ・ドライバ)
  • executiondriver(実行ドライバ)
  • kernelversion(カーネルバージョン)
  • operatingsystem(オペレーティング・システム)

アフィニティ (親密さ)フィルタ

コンテナ間を"引き寄せて" を作成するのに、--affinity:<フィルタ> を使うことができます。例えば、コンテナを実行するときの場所を指定し、その隣に次の特定のイメージやラベルを持つコンテナを配置することができます。この引き寄せ機能によって、コンテナを同じネットワークノードで確実に動かします。そのとき、どちらのノードで実行しているか知る必要はありません。

コンテナのアフィニティ(親密さ)

新しいコンテナを実行したあと、隣に他の名前や ID を持つコンテナを実行できます。例えば、frontend という名前で nginx コンテナを実行します:

$ docker run -d -p 80:80 --name front 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      logge

affinity の名前によって、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-1node-3redis イメージを持っています。-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=front"
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 ラベルを指定しているからです。

文法表現

アフィニティや constraint(制約)は、 keyvalue の組み合わせで表現します。key は英数字のパターンに従います。ただし、先頭はアルファベットかアンダースコアです。

value は次のようなものです:

  • 英数字の文字列、ドット、ハイフン、アンダースコア
  • 部分一致、例えば abc*
  • /regexp/ 形式の正規表現

Go 言語の正規表現文法をサポートしています。

現時点の Swarm は、アフィニティ・constraint で演算子 ==!= をサポートしています。

例えば、

  • constraint:node==node1 は、ノード node1 にマッチ
  • constraint:node!=node1 は、node1 をのぞく全てのノードにマッチ
  • constraint:region!=us* は、us が付いているリージョン以外のノードにマッチ
  • constraint:node==/node[12]/ は、node1node2 にマッチ
  • constraint:node==/node\d/ は、node + 10進数の1文字にマッチ
  • constraint:node!=/node-[01]/ は、node-0node-1 以外の全てのノードにマッチ
  • constraint:node!=/foo\[bar\]/ は、foo[var] 以外の全てのノードにマッチ
  • constraint:node==/(?i)node1/ は、大文字・小文字を区別しない node1 にマッチします。そのため、NoDe1NODE1 もマッチします。

Soft affinities/constrains (ソフトなアフィニティ・制約)

デフォルトでは、アフィニティと制約はハードに強制されるものです。アフィニティや制約がなければ、コンテナはスケジュールされません。Soft affinities/constrains があれば、スケジュールのために一致するルールを探そうとします。もし一致しなければ、スケジューラはフィルタを廃棄し、コンテナをスケジューラのストラテジに従ってコンテナをスケジュールします。

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-1node-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 を使ったホスト・モードの実行は、ポートのバインディングができない host モードのため、デフォルトの bridge モードとは異なります。そのため、1つ以上のポート番号を明示する必要があります( DockerfileEXPOSE を使うか、コマンドラインで --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_goldstine

dependency(依存)フィルタ

このフィルタは同じノード上でのコンテナ依存性をスケジュールします。

現時点では、次の依存性を宣言できます:

  • ボリューム共有:--volumes-from=dependency
  • リンク: --link=dependency:alias
  • 共有ネットワーク層:--net=container:dependency

Swarm は同じノード上で依存性のあるコンテナを設置しようとします。もし実行できなそうであれば(依存性のコンテナが存在しなかったり、ノードに十分なリソースが無い場合)、コンテナは作成されません。

可能であれば、複数の依存性を組み合わせることもできます。例えば、--volumes-from=A --net=container:B は、AB と同じノード上にコンテナを置こうとします。これらのコンテナが別々のノードで動いているなら、Swarm はコンテナのスケジューリングを行いません。

ヘルス・フィルタ

障害が発生しているノードをフィルタします。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6