コンテナ通信の理解

このセクションでは、Docker デフォルト・ブリッジ内部のコンテナ通信について説明します。このネットワークは bridge という名称の bridge ネットワークであり、Docker インストール時に自動的に作成されるものです。

注釈

Docker ネットワーク機能 を使えば、デフォルト・ブリッジ・ネットワークに加え、自分で定義したネットワークも作成できます。

外の世界との通信

コンテナが世界と通信できるかどうかは、2つの要素が左右します。1つめの要素は、ホストマシンが IP パケットを転送できるかどうかです。2つめはホスト側の iptables が特定の接続を許可するかどうかです。

IP パケット転送は、 ip_forward システム・パラメータで管理されます。このパラメータが 1 の時のみ、パケットは通信出来ます。通常、Docker サーバはデフォルトの設定のままでも --ip-forward=true であり、Docker はサーバの起動時に ip_forward1 にします。もし --ip-forward=false をセットし、システム・カーネルが有効な場合は、この --ip-forward=false オプションは無効化されます。カーネルの設定を確認は、手動で行います。

$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 0
$ sysctl net.ipv4.conf.all.forwarding=1
$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 1

Docker を使う多くの環境で ip_forward の有効化が必要となるでしょう。コンテナと世界が通信できるようにするには、この設定が最低限必要だからです。また、複数のブリッジをセットアップする場合は、コンテナ間での通信にも必要となります。

デーモン起動時に --iptables=false を設定しておくと、Docker はシステム上の iptables ルールセットを一切変更しません。そうでなければ、Docker サーバは DOCKER フィルタ・チェーンの転送ルールを追加します。

Docker は DOCKER フィルタ・チェーンのために、既存のルールを削除・変更しません。そのため、ユーザが必要であれば、コンテナに対して更なるアクセス制限するといった、高度なルールも作成できます。

Docker のデフォルト転送ルールは、全ての外部ソースの IP アドレス対して許可しています。コンテナを特定の IP アドレスやネットワークに対してのみ接続したい場合には、 DOCKER フィルタ・チェーンの一番上にネガティブ・ルールを追加します。例えば、コンテナが外部の IP アドレス 8.8.8.8 をソースとするもの しか 許可しない場合には、次のようなルールを追加します。

$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

コンテナ間の通信

2つのコンテナが通信できるかどうかは、オペレーティング・システム・レベルでの2つの要素に左右されます。

  • コンテナのネットワーク・インターフェースがネットワーク・トポロジに接続されていますか? デフォルトの Docker は、全てのコンテナを docker0 ブリッジに接続するので、コンテナ間でのパケット通信が可能な経路を提供します。他の利用可能なトポロジに関するドキュメントについては、後述します。
  • iptables は特定の接続を許可していますか? Docker はデーモンの起動時に --iptables=false を設定しておくと、システム上の iptables に対する変更を一切行いません。そのかわり、Docker サーバは FORWARD チェインにデフォルトのルールを追加する時、デフォルトの --icc=true であれば空の ACCEPT ポリシーを追加します。もし --icc=false であれば DROP ポリシーを設定します。

--icc=true のままにしておくか、あるいは --icc=false にすべきかという方針の検討には、 iptables を他のコンテナやメインのホストから守るかどうかです。たとえば、恣意的なポート探査やコンテナに対するアクセスは、問題を引き起こすかもしれません。

もし、より高い安全のために --icc=false を選択した場合は、コンテナが他のサービスと相互に通信するには、どのような設定が必要でしょうか。この答えが、 --link=CONTAINER_NAME_or_ID:ALIAS オプションです。これについては以前のセクションでサービス名についてで言及しました。もし Docker デーモンが --icc=falseiptables=true のオプションを指定すると、 docker run--link= オプションの情報を参照し、他のコンテナが新しいコンテナの公開用ポートに接続できるよう iptablesACCEPT ルールのペアを追加します。この公開用ポートとは、 DockerfileEXPOSE 行で指定していたものです。

注釈

--link= で指定する コンテナ名 の値は、Docker が自動的に割り当てる stupefied_pare の様な名前ではなく、 docker run の実行時に --name= で名前を割り当てておく必要があります。ホスト名でなければ、Docker は --link= オプションの内容を理解できません。

Docker ホスト上で iptables コマンドを実行すると、 FORWARD チェーンの場所で、デフォルトのポリシーが ACCEPTDROP かが確認できます。

# When --icc=false, you should see a DROP rule:

$ sudo iptables -L -n
...
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0
DROP       all  --  0.0.0.0/0            0.0.0.0/0
...

# When a --link= has been created under --icc=false,
# you should see port-specific ACCEPT rules overriding
# the subsequent DROP policy for all other packets:

$ sudo iptables -L -n
...
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0
DROP       all  --  0.0.0.0/0            0.0.0.0/0

Chain DOCKER (1 references)
target     prot opt source               destination
ACCEPT     tcp  --  172.17.0.2           172.17.0.3           tcp spt:80
ACCEPT     tcp  --  172.17.0.3           172.17.0.2           tcp dpt:80

注釈

ホストを広範囲にわたって公開する iptables のルールは、各コンテナが持つ実際の IP アドレスを通して公開されますのでご注意ください。そのため、あるコンテナから別のコンテナに対する接続は、前者のコンテナ自身が持っている IP アドレスからの接続に見えるでしょう。