コンテナ通信の理解¶
このセクションでは、Docker デフォルト・ブリッジ内部のコンテナ通信について説明します。このネットワークは bridge
という名称の bridge
ネットワークであり、Docker インストール時に自動的に作成されるものです。
注釈
Docker ネットワーク機能 を使えば、デフォルト・ブリッジ・ネットワークに加え、自分で定義したネットワークも作成できます。
外の世界との通信¶
コンテナが世界と通信できるかどうかは、2つの要素が左右します。1つめの要素は、ホストマシンが IP パケットを転送できるかどうかです。2つめはホスト側の iptables
が特定の接続を許可するかどうかです。
IP パケット転送は、 ip_forward
システム・パラメータで管理されます。このパラメータが 1
の時のみ、パケットは通信出来ます。通常、Docker サーバはデフォルトの設定のままでも --ip-forward=true
であり、Docker はサーバの起動時に ip_forward
を 1
にします。もし --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=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 アドレスからの接続に見えるでしょう。
参考
- Understand container communication
- https://docs.docker.com/engine/userguide/networking/default_network/container-communication/