単一のDockerホスト内の色々なネットワーク構成例


 Dockerは、コンテナというコンパクトで強固な仮想環境を提供してくれるのですが、ネットワークに関しても、他の仮想化技術に負けない仮想ネットワーク機能が実装されてます。

 前回の記事「Dockerネットワークの概要とその作り方の解説」では、Dockerネットワークの概要説明および独自ネットワークの作り方についてご紹介させていただきました。

 今回は、作成した独自ネットワークにコンテナを参加させたり、1つのコンテナを複数のネットワークに参加させるなど、より深くDockerネットワークの機能をご紹介したいと思います。

 

独自にネットワークを作成する

 まずはネットワークをひとつ作成してみましょう。

 以下のコマンドでtestnet10という名前のブリッジネットワークを作成します。

$ docker network create -d bridge testnet10

 docker network lsコマンドで確認します。

$ docker network ls
NETWORK ID     NAME      DRIVER  SCOPE
8b2a7b193570   bridge    bridge  local
76436c8075b5   host      host    local
825a5633a688   none      null    local
83f401dc2eaf   testnet10 bridge  local

 testnet10ネットワークが作成されていることが確認できました。(赤字部分)

 作成したtestnet10ネットワークの詳細情報をdocker network inspectコマンドで確認してみましょう。

$ docker network inspect testnet10

 以下のような内容が出力されました。

[
 {
 "Name": "testnet10",
 "Id": "83f401dc2eaf11bee6ab7b1e78d4130d8876e432f2ba772dbdfe55ea5f9815ec",
 "Created": "2017-04-01T10:14:55.308206648+09:00",
 "Scope": "local",
 "Driver": "bridge",
 "EnableIPv6": false,
 "IPAM": {
 "Driver": "default",
 "Options": {},
 "Config": [
 {
 "Subnet": "172.18.0.0/16",
 "Gateway": "172.18.0.1"
 }
 ]
 },
 "Internal": false,
 "Attachable": false,
 "Containers": {},
 "Options": {},
 "Labels": {}
 }
]

 上の内容のチェックポイントは、赤字の部分の「Name」、「Id」の先頭12文字、「Driver」、「Subnet」、「Gateway」、「Containers」です。

 「Name」には、ネットワーク作成時に指定した名前が設定されてます。

 「Id」の先頭12文字は、testnet10ネットワークが使用するDockerホスト上のネットワークインターフェイス名に使用されます。

 Linuxのipコマンドで確認してみましょう。

$ ip a
(途中省略)
11: br-83f401dc2eaf: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
 link/ether 02:42:a1:57:f9:76 brd ff:ff:ff:ff:ff:ff
 inet 172.18.0.1/16 scope global br-83f401dc2eaf
 valid_lft forever preferred_lft forever

 出力されたインターフェイスの中に「br-xxxxxxxxxxxx」という名前があると思います。私の環境では「br-83f401dc2eaf」です。この「br-」の後に付いている文字列がIdの先頭12文字と同じになります。

 「Driver」には、ネットワークの種類が設定されています。今回作成しましたのはブリッジネットワークですので、「bridge」が設定されています。これはDockerインストール時に自動作成されるbridgeのことではありませんのでご注意ください。

 「Subnet」には、ネットワークのアドレス範囲が設定されています。

 「Gateway」には、ネットワークのゲートウェイアドレスが設定されています。

 「Containers」には、ネットワークに参加しているコンテナの情報が出力されます。まだtestnet10には参加しているコンテナがありませんので、なにも出力されておりません。

 

作成したDockerネットワークに起動したコンテナを参加させる

 ではtestnet10ネットワークにコンテナを参加させてみましょう。

docker-network-net1con1

 特定のネットワークにコンテナを参加させるためには、そのコンテナの起動時に、参加するネットワークを「--net」オプションで指定します。指定しない場合はbridgeネットワークに参加されます。bridgeネットワークは、Dockerインストール時に自動作成されている仮想ネットワークです。

 以下のコマンドで、testnet10ネットワークに参加したコンテナvmtestを起動してみます。

$ docker run -d --name vmtest --net testnet10 centos init

 では、先ほど使用したdocker network inspectコマンドで再度確認してみます。

$ docker network inspect testnet10

 「Containers」の部分だけ確認してみます。

(省略)
"Containers": {
 "525230ef8236526a97186d607adb03045463291fd326ad76ab7e566ef5bce647": {
 "Name": "vmtest",
 "EndpointID": "0b8253efb764c9358728e8952c59ed985666f49e05c5c6263670040f624350e1",
 "MacAddress": "02:42:ac:12:00:02",
 "IPv4Address": "172.18.0.2/16",
 "IPv6Address": ""
 }
 },
(省略)

 ネットワークの作成直後は空だったのですが、今回はvmtestコンテナの情報が出力されてます。これによって、作成したネットワークtestnet10にコンテナvmtestが参加していることが確認できました。

 「IPv4Address」の部分を確認しますと、「172.18.0.2」のIPアドレスが設定されていることがわかります。

 このIPアドレスは、testnet10ネットワークの詳細情報の「Subnet」に設定されてましたアドレス範囲内のアドレスです。

 コンテナが特定のネットワークに参加しますと、Dockerによって、対象のネットワークのアドレス範囲内のIPアドレスが、コンテナに自動的に設定されます。

 コンテナ内でDHCPクライアントは起動されてませんので、DHCPサーバによるアドレス付与ではありません。

 また、今回作成したネットワークtestnet10はブリッジネットワークですので、Dockerによって自動的にDockerホストの物理ネットワークインターフェイス(私の環境ではeth0)に対して、iptables機能によるIPマスカレード設定が行われています。

 コンテナからDockerホスト外への通信は、このIPマスカレード設定によって可能となってます。試しにコンテナ内からDockerホスト外のIPアドレスに対してpingを飛ばしてみてください。

 

同じDockerネットワーク内のコンテナ間の疎通確認

 同じDockerネットワークに参加しているコンテナは通信可能であることを確認します。

docker-network-net1con2

 コンテナvmtest2を起動して、前項で作成したtestnet10に参加させます。

$ docker run -d --name vmtest2 --net testnet10 centos init

 念のため、docker network inspectコマンドで確認します。

$ docker network inspect testnet10

 「Containers」の設定を確認します。

"Containers": {
 "39bcd2e73b967e78ba4b3c7221b446100b6a5ecba85ea6064e89adccd9ea162f": {
 "Name": "vmtest2",
 "EndpointID": "6a15a6d33f966f64c49f969b4d0593db228077456bd2b8f56ad486b8c1e5b575",
 "MacAddress": "02:42:ac:12:00:03",
 "IPv4Address": "172.18.0.3/16",
 "IPv6Address": ""
 },
 "525230ef8236526a97186d607adb03045463291fd326ad76ab7e566ef5bce647": {
 "Name": "vmtest",
 "EndpointID": "0b8253efb764c9358728e8952c59ed985666f49e05c5c6263670040f624350e1",
 "MacAddress": "02:42:ac:12:00:02",
 "IPv4Address": "172.18.0.2/16",
 "IPv6Address": ""
 }
 },

 vmtestとvmtest2の2つのコンテナがtestnet10に参加していることが確認できました。それぞれのコンテナのIPアドレスも確認できます。

 vmtestが「172.18.0.2」、vmtest2が「172.18.0.3」ですね。

 それでは、vmtest2上でbashを起動して、vmtestに対してpingを飛ばしてみましょう。

$ docker exec -it vmtest2 bash

 vmtest2上のbashのプロンプトが表示されますので、pingを実行します。

[root@39bcd2e73b96 /]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.076 ms
^C
--- 172.18.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1005ms
rtt min/avg/max/mdev = 0.076/0.085/0.094/0.009 ms

 実は同一ネットワーク内では、他コンテナの名前解決も可能です。

[root@39bcd2e73b96 /]# ping vmtest
PING vmtest (172.18.0.2) 56(84) bytes of data.
64 bytes from vmtest.testnet10 (172.18.0.2): icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from vmtest.testnet10 (172.18.0.2): icmp_seq=2 ttl=64 time=0.059 ms
^C
--- vmtest ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1008ms
rtt min/avg/max/mdev = 0.059/0.061/0.063/0.002 ms

 以上より、同一ネットワーク内での疎通が確認できました。

 

異なるDockerネットワーク間のコンテナの独立性の確認

 今度は、異なるDockerネットワークに参加しているコンテナ間で疎通できないことを確認してみます。

docker-network-net2con2

 新規にネットワークtestnet20を作成して、そのネットワークにコンテナvmtest3を参加させてみます。

$ docker network create -d bridge testnet20
$ docker run -d --name vmtest3 --net testnet20 centos init

 念のため、docker network inspectコマンドで確認します。

$ docker network inspect testnet20

 「Containers」の設定を確認します。

"Containers": {
 "6b93d876f217003f038cc1a9019ed13bc6db45b544023b5e89ac2e89e4945864": {
 "Name": "vmtest3",
 "EndpointID": "2619b5482cf3c0166f0eecd23ac7528854e056935d36b65774d8d3263d175038",
 "MacAddress": "02:42:ac:13:00:02",
 "IPv4Address": "172.19.0.2/16",
 "IPv6Address": ""
 }
 },

 環境が整いましたので、vmtest3上でbashを起動して、前項で作成したネットワークtestnet10上のコンテナvmtest2(IPアドレスは172.18.0.3)に対してpingを飛ばしてみます。

$ docker exec -it vmtest3 bash
[root@6b93d876f217 /]#
[root@6b93d876f217 /]# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
^C
--- 172.18.0.3 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3037ms

 pingの応答はありませんでした。

 逆にvmtest2からvmtest3(IPアドレスは172.19.0.2)に対してpingを飛ばしてみます。

$ docker exec -it vmtest2 bash
[root@39bcd2e73b96 /]# ping 172.19.0.2
PING 172.19.0.2 (172.19.0.2) 56(84) bytes of data.
^C
--- 172.19.0.2 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3007ms

 同じくpingの応答はありませんでした。

 よって、異なるネットワークのコンテナ間は通信できないことが確認できました。

 

コンテナを複数のDockerネットワークに接続する

 1つのコンテナを複数のネットワークに参加させることもできます。

 例えば、2つのWebコンテナがあって、それぞれ同じDBコンテナにアクセスするが、Webコンテナ同士はネットワーク的に独立させたい、という環境が実現可能です。

 本記事でこれまでに作成した環境は以下の図の構成になっています。

docker-network-net2con3

 

 この構成で、vmtest2をtestnet20にも参加(上図の点線矢印)させれば、vmtest2をDBコンテナ、vmtestとvmtest3をWebコンテナと想定することで、例に挙げたニーズの動作確認ができそうですね。

 コンテナを起動するdocker runコマンドの仕様では、ネットワークの指定(--net)はひとつしかできません。

 よって、コンテナを複数のネットワークに参加させる場合は、コンテナが起動した後に、docker network connectコマンドを使用してダイナミックに参加させます。

 では、以下のコマンドで、vmtest2をtestnet20に参加させます。

$ docker network connect testnet20 vmtest2

 docker network inspectコマンドで確認します。

$ docker network inspect testnet20

 「Containers」の設定のみ確認します。

"Containers": {
 "39bcd2e73b967e78ba4b3c7221b446100b6a5ecba85ea6064e89adccd9ea162f": {
 "Name": "vmtest2",
 "EndpointID": "9670cc9a02adb73fafcf31a0b913cbc0f529f22ca2cd9b74721d8844b9d4e3d2",
 "MacAddress": "02:42:ac:13:00:03",
 "IPv4Address": "172.19.0.3/16",
 "IPv6Address": ""
 },
 "6b93d876f217003f038cc1a9019ed13bc6db45b544023b5e89ac2e89e4945864": {
 "Name": "vmtest3",
 "EndpointID": "2619b5482cf3c0166f0eecd23ac7528854e056935d36b65774d8d3263d175038",
 "MacAddress": "02:42:ac:13:00:02",
 "IPv4Address": "172.19.0.2/16",
 "IPv6Address": ""
 }
 },

 念のため、testnet10の「Containers」の設定も確認します。

$ docker network inspect testnet10
"Containers": {
 "39bcd2e73b967e78ba4b3c7221b446100b6a5ecba85ea6064e89adccd9ea162f": {
 "Name": "vmtest2",
 "EndpointID": "6a15a6d33f966f64c49f969b4d0593db228077456bd2b8f56ad486b8c1e5b575",
 "MacAddress": "02:42:ac:12:00:03",
 "IPv4Address": "172.18.0.3/16",
 "IPv6Address": ""
 },
 "525230ef8236526a97186d607adb03045463291fd326ad76ab7e566ef5bce647": {
 "Name": "vmtest",
 "EndpointID": "0b8253efb764c9358728e8952c59ed985666f49e05c5c6263670040f624350e1",
 "MacAddress": "02:42:ac:12:00:02",
 "IPv4Address": "172.18.0.2/16",
 "IPv6Address": ""
 }
 },

 ネットワークtestnet10とtestnet20のどちらにもvmtest2が存在すること確認できました。

 では、pingコマンドで疎通確認を以下のパターンで行います。pingはIPアドレス指定で行います。カッコ内はIPアドレスです。

  1. vmtest(172.18.0.2) ⇔ vmtest2(172.18.0.3)
  2. vmtest(172.18.0.2) ⇔ vmtest3(172.19.0.2)
  3. vmtest2(172.19.0.3) ⇔ vmtest3(172.19.0.2)

 1と3のみ疎通が確認できて、2はpingの応答が無ければ成功ですね。

 結果は、以下の通りでした。

  1. vmtest ⇔ vmtest2  ping応答あり
  2. vmtest ⇔ vmtest3  ping応答無し
  3. vmtest2 ⇔ vmtest3  ping応答あり

 予想通りの結果でした。

 

まとめ

 同一ネットワーク上のコンテナの疎通、異なるネットワーク上のコンテナの疎通、コンテナを複数のネットワークに参加させる、という3つの基本的な構成について解説しました。

 この基本構成を組み合わせて応用することで、様々な構成のネットワークを作成できるのではないかと思います。

 でも、実際のシステムで単一サーバーのものはほとんど無く、普通は複数台のサーバーを使用してシステムを構築しています。

 Dockerは、もちろん複数サーバー構成のシステムのことも考慮してまして、物理的に異なるサーバーにまたがったネットワークを作成することも可能です。

 これをマルチホストネットワークと言います。

 これに関しましては、別記事「Dockerのマルチホストネットワークの概要説明と環境構築」で解説しております。宜しかったらご利用ください。

 

 最後までお読みいただきありがとうございました。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です