コンテナ通信の理解¶
このセクションでは、Docker デフォルト・ブリッッジ内部のコンテナ通信について説明します。このネットワークは bridge という名称の bridge ネットワークであり、Docker インストール時に自動的に作成されるものです。
注釈
Docker ネットワーク機能 を使えば、デフォルト・ブリッジ・ネットワークに加え、自分で定義したネットワークも作成できます。
外の世界との通信¶
コンテナが世界と通信できるかどうかは、2つの要素が左右します。1つめの要素は、ホストマシンが IP パケットを転送できるかどうかです。2つめはホスト側の iptables が特定の接続を許可するかどうかです。
IP パケット転送は、 ip_forward システム・パラメータで管理されます。このパラメータが 1 の時のみ、パケットは通信出来ます。通常、Docker サーバはデフォルトの設定のままでも --ip-forward=true であり、Docker はサーバの起動時に ip_forward を 1 にします。もし --ip-foward=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=false と iptables=true のオプションを指定すると、 docker run は --link= オプションの情報を参照し、他のコンテナが新しいコンテナの公開用ポートに接続できるよう iptables の ACCEPT ルールのペアを追加します。この公開用ポートとは、 Dockerfile の EXPOSE 行で指定していたものです。
注釈
--link= で指定する コンテナ名 の値は、Docker が自動的に割り当てる stupefied_pare の様な名前ではなく、 docker run の実行時に --name= で名前を割り当てておく必要があります。ホスト名でなければ、Docker は --link= オプションの内容を理解できません。
Docker ホスト上で iptables コマンドを実行すると、 FORWARD チェーンの場所で、デフォルトのポリシーが ACCEPT か DROP かが確認できます。
# 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 アドレスからの接続に見えるでしょう。