【Dockerの最新機能を使ってみよう】マルチホストネットワークで複数ホスト間を繋ぐ仮想ネットワークを作る 3ページ

マルチホストネットワークの作成と利用

 それでは、マルチホストネットワークを実際に作成して使用してみよう。まず、次のように「-d」オプションでoverlayドライバを指定して「docker network create」コマンドを実行してネットワークを作成する。ここではネットワーク名として「testnet02」を指定した。

# docker network create -d overlay testnet02
a35a95625a09b2b7a680ec59932f323f4d5f7596b970ac3808449244eb03f7c7

 「docker network inspect」コマンドでこのネットワークの情報を確認すると、bridgeドライバで作成したネットワークとは異なるネットワークアドレスが割り当てられていることが分かる。

# docker network inspect testnet02
[
    {
        "Name": "testnet02",
        "Id": "a35a95625a09b2b7a680ec59932f323f4d5f7596b970ac3808449244eb03f7c7",
        "Scope": "global",
        "Driver": "overlay",
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1/24"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

 作成されたネットワークは、すべてのDockerホスト内で共有される。たとえば「docker create network」コマンドを実行したのとは異なるDockerホストで「docker network ls」コマンドを実行してみると、このホスト上でも先ほど作成した「testnet02」ネットワークが認識されていることが分かる。

# docker network ls
NETWORK ID          NAME                DRIVER
a35a95625a09        testnet02           overlay
1a1ecc8ea3f7        bridge              bridge
ae6eadc28386        none                null
7c66cf43a8cc        host                host

 続いて、このネットワークをコンテナに接続してみよう。「docker network connect」コマンドを利用すれば、すでに稼動しているコンテナに別のネットワークを接続することが可能だ。まずは本記事の初めに作成したmysql01コンテナに、testnet02ネットワークを接続してみよう。

# docker network connect testnet02 mysql01

 接続後、「docker inspect」コマンドでmysql01コンテナの情報を見てみると、testnet01およびtestnet02の2つのネットワークに対応したIPアドレスが割り当てられていることが分かる。

# docker inspect mysql01
  
  
            "Networks": {
                "testnet01": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "bd48adb5b4a787cb499640fabff3b2a4bd5c13077b954926443298bf5ad297bc",
                    "EndpointID": "0d0c13fa6d3f266411e07980e8077fcc1bfce303deb9560a96ab13cf1e877283",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:02"
                },
                "testnet02": {
                    "IPAMConfig": {},
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "a35a95625a09b2b7a680ec59932f323f4d5f7596b970ac3808449244eb03f7c7",
                    "EndpointID": "0cc20ccf5c9f6a1128f1c3948c5e3065fbdc8d75b47ba74083c139f4bc278a8c",
                    "Gateway": "",
                    "IPAddress": "10.0.0.2",
                    "IPPrefixLen": 24,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:0a:00:00:02"
                }
  
  

 これで、testnet02ネットワーク内のコンテナからmysql01コンテナ内で稼動しているMySQLに「mysql01.testnet02」というホスト名を使ってアクセスできるようになる。もちろん、mysql01コンテナを稼動させているDockerホスト以外のDockerホスト上で稼動しているコンテナからもアクセスが可能だ。たとえば、別のDockerホスト上で次のようにWordPressコンテナを立ち上げて、WordPressを稼動させることができる。

# docker run --name wp01 --net=testnet02 -p 80:80 -e WORDPRESS_DB_HOST=mysql01.testnet02 -e WORDPRESS_DB_USER=wordpress -e WORDPRESS_DB_PASSWORD=<MySQLのrootパスワード> -d wordpress

 なお、overlayドライバが割り当てたIPアドレス(この例ではtestnet02に接続された「10.0.0.2」というIPアドレス)には、そのコンテナを稼動させているDockerホストからもアクセスできない点に注意したい。

↓bridgeドライバで割り当てられたIPアドレスへのping
# ping 172.18.0.1
PING 172.18.0.1 (172.18.0.1) 56(84) bytes of data.
64 bytes from 172.18.0.1: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 172.18.0.1: icmp_seq=2 ttl=64 time=0.075 ms
^C
--- 172.18.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.062/0.068/0.075/0.010 ms

↓overlayドライバで割り当てられたIPアドレスへのping
# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
^C
--- 10.0.0.2 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 2999ms
↑パケットが到達せず、通信できない

マルチホストネットワークでのリンク機能

 「docker run」コマンドでは、コンテナから別のコンテナにアクセスするための別名(エイリアス)を指定する「–link」オプションが用意されていた。Docker 1.9まではこのオプションはbridgeネットワークでしか利用できなかったが、Docker 1.10ではそれ以外のネットワークでも利用が可能になっている。

 「–link」オプションでは、「–link=<コンテナ名>:<エイリアス名>」といった形でコンテナ名およびエイリアス名を指定できる。例えば「–link=mysql01:db」のように指定すると、そのコンテナ内からは「db」というホスト名でmysql01コンテナにアクセスが可能になる。

# docker run -it --rm --net=testnet02 --link=mysql01:db busybox
/ # ping db
PING db (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.173 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.114 ms
^C
--- db ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.114/0.143/0.173 ms

 なお、リンク機能は同じネットワーク上にあるホスト間でのみ利用可能だ。また、「docker network connect」コマンドの「–link」オプションでも同様のリンク設定が可能になっている。

ネットワーク外へのアクセスが禁止された内部ネットワークを作る

 Docker 1.10では新たに「内部ネットワーク(internal network)」という機能も導入されている。これは、ネットワーク外との通信が行えないネットワークを作成する機能だ。内部ネットワークは、次のようにネットワークの作成時に「–internal」オプションを指定することで作成できる。

# docker network create --internal -d overlay testnet03
58936e24df57dcb670a64a5ccbb7225f7738c3d68f4ba8cc747782ab35b35c91

 このように作成されたネットワークでは、ネットワーク外への通信が行えず、またネットワーク外からネットワーク内への通信も行えない。次の例は、内部ネットワークとして作成された「testnet03」ネットワークからネットワーク外にアクセスしようとした例だ。ここでは「Network is unreachable」と表示され、アクセスが行えなくなっていることが分かる。

# docker run -it --rm --net=testnet03 busybox
/ # ping osdn.jp
PING osdn.jp (202.221.179.11): 56 data bytes
ping: sendto: Network is unreachable

 もちろん、この場合でも同じ内部ネットワークに接続されたホスト間での通信は可能だ。

コンテナに任意のIPアドレスを割り当てる

 従来、Dockerではコンテナに割り当てられるIPアドレスは自動的に決定されていた。しかしDocker 1.10では、コンテナに割り当てるIPアドレスを指定できるよう「docker run」コマンドや「docker network」コマンドに「–ip」および「–ip6」オプションが追加されている。ただし、この機能はネットワークの作成時に明示的にネットワークが使用するIPアドレスを指定しておいたネットワークでのみ利用が可能となっている。

 ネットワークの作成時に使用するIPアドレスを指定するには、「–subnet」オプションを使用する。次の例は、10.0.1.0/24というネットワークを指定するものだ。

# docker network create --subnet=10.0.1.0/24 testnet04
4d833c534a46fec58d72d8de5e8536574d6653a0600dce653c474e7d8bb4825d

 このようにして作成したネットワークにコンテナを接続する場合、「–ip」オプションでコンテナに割り当てるIPアドレスを指定できる。次の例では、10.0.1.100というIPアドレスを割り当てている。

# docker run -ti --net=testnet04 --rm --ip=10.0.1.100 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
194: eth0@if195: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:0a:00:01:64 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.100/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe00:164/64 scope link
       valid_lft forever preferred_lft forever

 なお、ネットワークに割り当てられたサブネット外のIPアドレスを指定した場合、次のようにエラーが発生しコンテナを起動できない。

# docker run -ti --net=testnet04 --rm --ip=10.0.2.100 busybox
docker: Error response from daemon: Invalid preferred address 10.0.2.100: It does not belong to any of this network's subnets.

 なお、ここではIPv4アドレスを指定しているが、「–ip6」オプションを利用することでIPv6アドレスを割り当てることも可能だ。また、「docker run」コマンドだけでなく、「docker network connect」コマンドでも同様に「–ip」および「–ip6」オプションでIPアドレスの割り当てが可能だ。

マルチホストネットワークでDockerクラスタの構築がより容易かつ柔軟に

 今回紹介したDockerのマルチホストネットワーク機能を利用することで、従来は別の技術を導入する必要があった複数のDockerホスト間の連携が簡単に行えるようになった。また、異なるネットワーク技術を使う場合でも、同じ「docker network」コマンドで仮想ネットワークの管理が行えるというメリットもある。Docker向けのネットワークドライバは仕様が公開されているため、今後サポートされる仮想ネットワークも増えていくと思われる。