ぜんぜんわからない、俺たちは雰囲気で Docker を使っている。そんな状況を打破するために、きちんと基本を押さえましょうという状況です。
今日の docker (for mac) はこちらです。
$ docker -v Docker version 18.03.1-ce, build 9ee9f40
というわけで、まずはネットワークからですが、面白かったのを最初にまとめておきます。
NW | コンテナ間疎通 | コンテナの名前解決 |
---|---|---|
bridge | o | x |
ユーザ定義ネットワーク | o | o |
Docker におけるネットワーク
Docker が持つネットワークは、docker network ls
で参照することができます。
マルチホストネットワークを使わない場合、何も考えずにコンテナを run するときに使うのは bridge
というネットワークになります。
$ docker network ls | head -2 NETWORK ID NAME DRIVER SCOPE 01da84451bd1 bridge bridge local
この bridge
と呼ばれるデフォルトネットワークは、同名の bridge
という Docker のネットワークドライバを使用するネットワークになります。
Docker におけるネットワークドライバは、デフォルトで以下の 5 つが用意されています。
スタンドアローンで Docker を使う場合、ほとんどは bridge
で済むはずです。ちなみに host
は Docker Swarm 限定で、overlay
は複数の Docker Host 上のコンテナを繋ぐ場合に利用するヤツです。
bridge
host
overlay
macvlan
none
単純に bridge
を使う
何も考えずに docker run
すると、そこで起動されたコンテナは bridge
ネットワークに接続されます。
例えば、以下のように 2 つコンテナを立ち上げた後、bridge
を inspect すると、立ち上げた 2 つのコンテナが bridge
ネットワークに接続されていることが分かります。
$ docker run -dit --name alpine1 alpine ash $ docker run -dit --name alpine2 alpine ash $ docker network inspect bridge | jq -r '.[0].Containers[] | [.Name, .IPv4Address]' [ "alpine1", "172.17.0.2/16" ] [ "alpine2", "172.17.0.3/16" ]
疎通確認と名前解決
それじゃ、alpine1 に attach して、alpine2 と疎通が取れるかを確認してみます。
結果は以下のとおりで、ping は通りますが、alpine2
の名前解決はできません。
/ # ping -c1 172.17.0.3 PING 172.17.0.3 (172.17.0.3): 56 data bytes 64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.126 ms --- 172.17.0.3 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.126/0.126/0.126 ms / # ping alpine2 ping: bad address 'alpine2'
自分でネットワークをつくる
IP アドレス帯を勝手に決められるのもアレですので、自分でネットワークを作ってしまいましょう。 ここでは、10.0.0.0/8 のサブネット内に、10.1.0.0/16 にコンテナを配置するようにしてみます。
$ docker network create --driver=bridge \ --subnet=10.0.0.0/8\ --ip-range=10.1.0.0/16\ --gateway=10.1.255.254\ kiririmode-network 244715a00a1c6eb5d0e1094b1117921dbd493f63cb2504102fb04498c3d8a9d4
そして、ここにコンテナを紐付けてみると、コンテナ 2 つが 10.1.0.0/16
の IP アドレスを持って kiririmode-network に接続できていることが分かります。
$ docker run -dit --name alpineA --network kiririmode-network alpine ash $ docker run -dit --name alpineB --network kiririmode-network alpine ash $ docker network inspect kiririmode-network | jq -r '.[0].Containers[] | [.Name, .IPv4Address]' [ "alpineA", "10.1.0.0/8" ] [ "alpineB", "10.1.0.1/8" ]
疎通確認と名前解決
こちらでも、疎通確認と名前解決をしてみましょう。
以下のように、bridge
ネットワークとは違い、名前解決も含めて成功していることが分かります。
/ # ping -c1 10.1.0.1 PING 10.1.0.1 (10.1.0.1): 56 data bytes 64 bytes from 10.1.0.1: seq=0 ttl=64 time=0.222 ms --- 10.1.0.1 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.222/0.222/0.222 ms / # ping -c1 alpineB PING alpineB (10.1.0.1): 56 data bytes 64 bytes from 10.1.0.1: seq=0 ttl=64 time=0.439 ms --- alpineB ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.439/0.439/0.439 ms
名前解決の差異はどこから来るのか
簡単な違いは以下のとおりです。
# bridge に接続されたコンテナ % docker exec alpine1 grep nameserver /etc/resolv.conf nameserver 192.168.65.1 # ユーザ定義ネットワークに接続されたコンテナ $ docker exec alpineA grep nameserver /etc/resolv.conf nameserver 127.0.0.11
このように、向いている DNS サーバが異なります。
ユーザ定義ネットワークである kiririmode-network
に接続されたコンテナは、127.0.0.11 という DNS サーバを向いていますが、
これはユーザ定義ネットワーク上にのみ構築される埋め込み DNS サーバになります。
ガイド を見る限り、bridge
ネットワークのみ、後方互換性を考慮して挙動に違いがあるようで。
埋め込み DNS サーバって、停止させたコンテナの名前を解決できるの?
では、一方のコンテナを停止させた場合、名前解決は引き続き行われるのでしょうか、それとも解決できなくなるのでしょうか。試した結果がこちら。
# 前提として最初は繋がる $ docker exec alpineA ping -c 1 alpineB PING alpineB (10.1.0.1): 56 data bytes 64 bytes from 10.1.0.1: seq=0 ttl=64 time=0.142 ms --- alpineB ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.142/0.142/0.142 ms # alpineB を停止 $ docker stop alpineB alpineB # 名前解決できなくなる $ docker exec alpineA ping -c 1 alpineB ping: bad address 'alpineB'