【さわって学ぶクラウドインフラ docker 基礎からのコンテナ構築】第6章 コンテナのネットワークで知らなかったことをざっくりまとめてみた
目次
- 目次
- 概要
- 3つのネットワーク
- bridgeネットワーク
- コンテナに割り当てられているIPアドレスを確認する
- コンテナ同士の通信
- Dockerのネットワークを新規に作成して通信を分ける
- Dockerネットワーク内にコンテナを作る
- 既存のコンテナを別のDockerネットワークに所属させる
- コンテナ名で通信ができることを確認する
- Dockerネットワークの削除
- hostネットワーク
- noneネットワーク
- 参考記事
概要
Dockerホスト上では、複数の独立したコンテナを実行する事ができます。時にはコンテナ間での通信が必要な場面があるので、コンテナのネットワークについて学びます。
3つのネットワーク
Dockerでは、 さまざまなネットワークを作り、Dockerホストとコンテナ、またはコンテナ間で通信する事ができます。 以下のコマンドでDockerが管理するネットワークを確認できます。
ubuntu@ip-10-0-12-65:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 49ea1ad2bf81 bridge bridge local d8850b15265b host host local a8e3cb52fef7 none null local ubuntu@ip-10-0-12-65:~$
規定では「bridge」「host」「none」という3つのネットワークがあります。このうちよく使われるのが「bridge」ネットワークです。
bridgeネットワーク
bridgeネットワークとは、 デフォルトのネットワークのことです。docker run(もしくはdocker create)でコンテナを作成する場合、ネットワークオプションを指定しなかったら、このネットワークが使われます。このネットワークにコンテナが属すことになります。 bridgeネットワークにおいては、それぞれのコンテナのネットワークは独立しており、-pオプションでどのコンテナ(またはDockerホスト)と通信するかを決めます。
(注) bridgeネットワークはIPマスカレード(ポート番号を利用することで、1つのグローバルIPアドレスと複数のプライベートIPアドレスを紐付けて変換する技術)を使って構成されています。
コンテナに割り当てられているIPアドレスを確認する
DockerホストやDockerコンテナは一つの仮想的なbirdgeネットワークによて接続されます。ネットワーク通信なので、DockerホストやDockerコンテナにはIPアドレスが付与されています。
コンテナのIPアドレスを確認するためには、コンテナを起動させて、docker container inspectコマンドを実行します。このうち「NetworkSettings」の部分にIPアドレスが記載されています。
(※) コンテナのIPアドレスを確認するためには、docker container inspect以外に、コンテナ内でipコマンドやifconfigコマンドを実行して確認する事ができます。イメージによっては、軽量化のためにipコマンドやifconfigコマンドが入っていない場合もあります。
docker container inspect コンテナ名
"NetworkSettings": { "Bridge": "", "SandboxID": "ff3b23c1fcb196bcc3ad90310c87b73d56a21977c04ea38b6c34aae574a829ec", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "80/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "8080" }, { "HostIp": "::", "HostPort": "8080" } ] }, "SandboxKey": "/var/run/docker/netns/ff3b23c1fcb1", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "a2e7c6bb5d3fa4c254754499871c086bb39f54ca7e53fda8cd28472a95fbce48", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "49ea1ad2bf81b1c4315446f90cb1e10339d886434673c2e1c78146875beaa801", "EndpointID": "a2e7c6bb5d3fa4c254754499871c086bb39f54ca7e53fda8cd28472a95fbce48", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } }
docker container inspectを実行すると、そのコンテナの全情報が表示されるので、--formatオプションを指定して特定の項目だけ表示することもできます。以下のコマンドでは、IPアドレスの部分だけを取得しています。
docker container inspect --format="{{.NetworkSettings.IPAddress}}" コンテナ名
コンテナ同士の通信
コンテナはそれぞれIPアドレスを持ち、bridgeネットワークに接続されています。そのため、コンテナ同士は、このネットワークを通じて互いに通信できます。 コンテナ間の通信の場合、-pオプションを指定しなくても可能です。-pオプションはあくまでDockerホストで受信したリクエストをDockerコンテナの特定のポートに転送するための設定です。Dockerコンテナ間で通信する場合は、Dockerホストを経由しないので、-pオプションは関係ないです。
コンテナのシェルを立ち上げて、curlコマンドやpingコマンドを使うことで、別のコンテナと通信できるかを確認できます。
作業手順
手順1:
以下のコマンドを実行して、ubuntuのコンテナを立ち上げます。
docker run --rm -it ubuntu /bin/bash
手順2:
ip、ping、curlという3つのコマンドを使いたいので、aptコマンドでインストールします。
apt update apt -y upgrade apt install -y iproute2 iputils-ping curl
手順3:
ipコマンドを入力して、コンテナ自身のIPアドレスを確認します。
ip address
コンテナのIPアドレスは172.17.0.4である事が分かりました。
root@00f8a5490627:/# ip address 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 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 24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
手順4:
既に存在しているコンテナに対してpingコマンドを使って疎通確認をします。結果が「0% packet loss」になっていれば疎通できています。
root@00f8a5490627:/# ping -c 4 172.17.0.2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.104 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.063 ms 64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.066 ms 64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.065 ms --- 172.17.0.2 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3054ms rtt min/avg/max/mdev = 0.063/0.074/0.104/0.017 ms root@00f8a5490627:/# ping -c 4 172.17.0.3 PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.098 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.066 ms 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.067 ms 64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.065 ms --- 172.17.0.3 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3058ms rtt min/avg/max/mdev = 0.065/0.074/0.098/0.013 ms
(※) -c 4は4回試したら終わるオプションです。オプションを省略すると、ずっと動きっぱなしになるので、ctrl + cで停止します。
手順5:
curlコマンドでWebサーバーに接続してコンテンツを取得できるかを確認します。ポートは省略すると既定のポート80番に接続されます。
curl http://IPアドレス/
root@00f8a5490627:/# curl http://172.17.0.2 <html><body><h1>It works!</h1></body></html>
(注) pingコマンドやcurlコマンドにIPアドレスではなくコンテナ名を指定すると、エラーになるので、気をつけましょう。
Dockerのネットワークを新規に作成して通信を分ける
コンテナ間で通信するためには、IPアドレスを指定する必要があります。しかし、コンテナのIPアドレスをdocker container inspectで確認しないといけないので、面倒です。 コンテナ名で通信するためには、Dockerネットワークを新規作成するか、linkオプションを指定します。linkオプションは推奨されていないので、コンテナ名でコンテナ間通信をするために、Dockerネットワークを作成します。Dockerネットワークを作成して、その中に複数のコンテナを所属させれば、そのDockerネットワークに所属しているコンテナ間でコンテナ名を使って通信ができます。
Dockerネットワーク
Dockerネットワークとは、 ユーザーが作成した任意のネットワークのことです。 ネットワークを作ることで、「あるコンテナは、こちらのネットワークに、別のコンテナはこちらのネットワークに」というように、別々のネットワークにコンテナを所属させる事ができます。
Dockerネットワークを作ると、その数だけ、Dockerホスト上には「br-DockerのネットワークIDの先頭」という名前のネットワークインターフェースが作られます。
Dockerネットワークのメリット
Dockerネットワークのメリットは、コンテナ間で通信するときに、コンテナ名を指定して通信ができるところです。bridgeネットワークで問題となっていたIPアドレスでしか通信できないという問題を解決します。
Dockerネットワークを作る
以下のコマンドを実行して、Dockerネットワークを作成します。
docker network create ネットワーク名
(※) Dockerネットワークを作成すると、それに伴い、Dockerホストにネットワークインターフェースが追加されます。
ubuntu@ip-10-0-12-65:~$ docker network create mydockernet 51b0d74b3e53d3e295802c483dfe40d22b02ebc6481d89a51677d372ad59a566 ubuntu@ip-10-0-12-65:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 49ea1ad2bf81 bridge bridge local d8850b15265b host host local 51b0d74b3e53 mydockernet bridge local a8e3cb52fef7 none null local
新しく「mydockernet」という名前のネットワークがbridgeというドライバーで作成された事が分かります。
Dockerネットワークの詳細情報を見るためには、以下のコマンドを実行します。
docker network inspect Dockerネットワーク名
ubuntu@ip-10-0-12-65:~$ docker network inspect mydockernet [ { "Name": "mydockernet", "Id": "51b0d74b3e53d3e295802c483dfe40d22b02ebc6481d89a51677d372ad59a566", "Created": "2022-11-23T06:46:47.833364427Z", "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, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ]
Dockerネットワーク内にコンテナを作る
Dockerネットワーク内にコンテナを作成するためには、--netオプションを指定します。
docker run -dit --name web01 -p 8080:80 --net Dockerネットワーク名 httpd:2.4
docker network inspect ネットワーク名で、Containersの部分にネットワークに所属させたコンテナが存在すればOKです。
既存のコンテナを別のDockerネットワークに所属させる
既存のコンテナを別のDockerネットワークに所属させるためには、docker network connectコマンドおよびdocker network disconnectコマンドを使用します。docker network connectでコンテナをネットワークに所属させたり、docker network disconnectでコンテナをネットワークから切断したりできます。
docker network connect ネットワーク名(ネットワークID) コンテナ名(コンテナID)
docker network disconnect ネットワーク名(ネットワークID) コンテナ名(コンテナID)
bridgeネットワークから別のDockerネットワークにコンテナを所属させるためには、以下のコマンドを実行します。
docker network disconnect bridge web01 docker network connect mydockernet web01
コンテナ名で通信ができることを確認する
Dockerネットワーク内のコンテナ間では、以下のようにpingやcurlでコンテナ名を指定して通信する事ができます。
root@9ed0ae318511:/# ping -c 4 web01 PING web01 (172.18.0.2) 56(84) bytes of data. 64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=1 ttl=64 time=0.085 ms 64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=2 ttl=64 time=0.082 ms 64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=3 ttl=64 time=0.069 ms 64 bytes from web01.mydockernet (172.18.0.2): icmp_seq=4 ttl=64 time=0.068 ms --- web01 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3060ms rtt min/avg/max/mdev = 0.068/0.076/0.085/0.007 ms root@9ed0ae318511:/#
root@9ed0ae318511:/# curl http://web01 <html><body><h1>It works!</h1></body></html>
(※)Dockerネットワークを使ってコンテナ間で通信する際にコンテナ名でアクセスできる理由は、Dockerが用意しているDNSサーバーを使って、コンテナ名とIPアドレスを紐づけているからです。
Dockerネットワークの削除
ネットワークを削除するためには、まずはネットワークを利用しているコンテナを削除 or ネットワークから切断する必要があります。その後Dockerネットワークを削除できます。 以下のコマンドでDockerネットワークを削除できます。
docker network rm Dockerネットワーク名
(※) Dockerネットワークを削除すると、それに対応するDockerホストのインターフェースも削除されます。
hostネットワーク
hostネットワークでは、IPマスカレードを使わずに、コンテナがホストのIPアドレスを共有します。あまり使わないので、使う時になったら調べます。
noneネットワーク
noneネットワークでは、コンテナはネットワークに接続されません。docker run(もしくはdocker create)の際に、--net noneを指定します。または、docker network disconnectでネットワークから切断しても同じ状態になります。セキュリティを高めたいなどの理由でコンテナをネットワーク通信から隔離したい時に使います。hostネットワークと同様、あまり使わないので、使う時になったら調べます。
参考記事
さわって学ぶクラウドインフラ docker基礎からのコンテナ構築 | 大澤 文孝, 浅居 尚 |本 | 通販 | Amazon
Docker の bridge と host ネットワークについて勉強する - Qiita
第29回 Docker Networkingの基礎知識 標準的なネットワークを理解する:古賀政純の「攻めのITのためのDocker塾」(5/5 ページ) - ITmedia エンタープライズ
【 ping 】コマンド/【 ping6 】コマンド――通信相手にパケットを送って応答を調べる:Linux基本コマンドTips(143) - @IT