Dockerはコンテナというコンパクトなのに本格的な仮想環境を提供してくれるのですが、ネットワークに関しても、他の仮想化技術に負けない仮想ネットワーク機能が実装されてます。
デフォルトで用意されているDockerネットワークを利用しても良いのですが、ご自身で作成したものをカスタマイズして使用することで目的にピッタリのDockerネットワークをご利用になることが可能です。
Dockerネットワークを作成したりカスタマイズするは、使い慣れたDockerコマンドを使用して行います。
本記事では、複数のDockerネットワークを組み合わせたネットワーク構成を3つご紹介しています。
お読みになることで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」には、ネットワークに参加しているDockerコンテナの情報が出力されます。まだtestnet10には参加しているDockerコンテナがありませんので、なにも出力されておりません。
作成したDockerネットワークに起動したDockerコンテナを接続する
ではtestnet10ネットワークにDockerコンテナを接続させてみましょう。
特定のネットワークにDockerコンテナを参加させるためには、Dockerコンテナの起動時に、参加するネットワークを「--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コンテナが特定のネットワークに参加しますと、Dockerによって、対象のネットワークのアドレス範囲内のIPアドレスが、コンテナに自動的に設定されます。
Dockerコンテナ内でDHCPクライアントは起動されてませんので、DHCPサーバによるアドレス付与ではありません。
また、今回作成したネットワークtestnet10はブリッジネットワークですので、Dockerによって自動的にDockerホストの物理ネットワークインターフェイス(私の環境ではeth0)に対して、iptables機能によるIPマスカレード設定が行われています。
コンテナからDockerホスト外への通信は、このIPマスカレード設定によって可能になります。
試しにコンテナ内からDockerホスト外のIPアドレスに対してpingを飛ばしてみてください。
同じDockerネットワーク内のコンテナ間の疎通確認
同じDockerネットワークに参加しているコンテナは通信可能であることを確認します。
コンテナ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ネットワークに参加しているDockerコンテナ間で疎通できないことを確認してみます。
新規にネットワーク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コンテナを複数のDockerネットワークに接続する
1つのコンテナを複数のネットワークに参加させることもできます。
例えば、2つのWebコンテナがあって、それぞれ同じDBコンテナにアクセスするが、Webコンテナ同士はネットワーク的に独立させたい、という環境が実現可能です。
本記事でこれまでに作成した環境は以下の図の構成になっています。
この構成で、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アドレスです。
- vmtest(172.18.0.2) ⇔ vmtest2(172.18.0.3)
- vmtest(172.18.0.2) ⇔ vmtest3(172.19.0.2)
- vmtest2(172.19.0.3) ⇔ vmtest3(172.19.0.2)
1と3のみ疎通が確認できて、2はpingの応答が無ければ成功ですね。
結果は、以下の通りでした。
- vmtest ⇔ vmtest2 ping応答あり
- vmtest ⇔ vmtest3 ping応答無し
- vmtest2 ⇔ vmtest3 ping応答あり
予想通りの結果でした。
まとめ
同一ネットワーク上のコンテナの疎通、異なるネットワーク上のコンテナの疎通、コンテナを複数のネットワークに参加させる、という3つの基本的な構成について解説しました。
この基本構成を組み合わせて応用することで、様々な構成のネットワークを作成できるのではないかと思います。
本記事では1台のDockerホストマシン上で検証しましたが、実際のシステムで単一サーバーのものはほとんど無く、普通は複数台のサーバーを使用してシステムを構築しています。
Dockerは、もちろん複数サーバー構成のシステムのことも考慮してまして、物理的に異なるサーバーにまたがったネットワークを作成することも可能です。
これをマルチホストネットワークと言います。
これに関しましては、別記事「Dockerのマルチホストネットワークの概要説明と環境構築」で解説しております。宜しかったらご利用ください。
最後までお読みいただきありがとうございました。
コメント