【 docker入門 】 docker コンテナ の ネットワーク 概要と設定方法をご紹介
docker入門 第三弾です。
過去に投稿した2つのコンテナ関連の記事では、コンテナ単体を作るところまでをゴールにしていました。
しかし、実際は複数のコンテナ間で通信をさせてサービスや機能を提供したりシステムを構築します。
今回は、コンテナ同士をどのように通信させるのか基礎的な設定から説明していきます。
docker のネットワークの種類
現状、自分のdockerでどのようなネットワークが管理されているかはdocker network ls
コマンドで確認することができます。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c23cba88ae63 bridge bridge local
56a710f51861 docker_gwbridge bridge local
0bbee5e422cd host host local
d900789f82bd none null local
上から、
- bridgeネットワーク
- hostネットワーク
- noneネットワーク
と呼ばれるネットワークになっております。
dockerではこれに加えてユーザー定義ネットワークというものが存在し、大きく分けると4種類のネットワークが存在します。
そもそもネットワークがわからんという方
今回はネットワークに関する話になるので、コンテナの知識だけでは少々きついです。
過去に、ネットワークの超基礎的なところを記事にしているので合わせてご確認ください。
hostネットワーク
このネットワークに接続されているコンテナは、dockerデーモンが動作しているホスト(以下dockerホスト)と同じIPが割り当てられます。
例えば、192.168.1.1/24のIPアドレスが割り当てられたPCにdockerをインストールして使っている場合は、PCと同じアドレス、すなわち192.168.1.1というIPがhostネットワークに接続しているコンテナにも割り当てられます。
図にするとこんな感じです。
bridgeネットワーク
特にネットワークを指定しなかったコンテナはデフォルトでこのネットワークに接続されます。
このネットワークに接続されているコンテナには、dockerによって自動採番されたIPアドレスが割り当てられコンテナ同士はL2の通信で他のコンテナと通信します。
bridgeとついていることからもL2の通信であることがイメージしやすいかと思います。
例えば、192.168.1.1/24のIPアドレスが割り当てられたPCにdockerをインストールして使っている場合は、PCの内部に仮想的なネットワーク172.16.1.1/24が作成されており、bridgeネットワークに接続されたコンテナには172.16.1.XのIPが自動で付与されるというような感じです。
このネットワークでは、コンテナ同士の名前解決ができません。
コンテナ作成時に$ docker run --name web1
などとしていても他のコンテナから$ ping web1
と実行しても通信できません。
$ docker network ls
の結果でbridgeネットワークが2つ出力されていますが、docker_gwbridgeは複数のdockerホスト間でネットワークを構築するオーバーレイネットワークのためのネットワークです。
今回は、詳しく書きませんが言葉は覚えておいた方が良いかと思います。
先程の図にbridgeネットワークを追加するとこうです。
ユーザー定義ネットワーク
冒頭にある$ docker network ls の結果には乗っていませんが、ユーザー定義ネットワークというものも存在します。
このネットワークはほとんどbridgeネットワークと同じなのですが、名前解決ができるという特徴があります。
noneネットワーク
このネットワークに接続されているコンテナはループバックアドレス(127.0.0.1)のためのインターフェースしか持たず、他のコンテナと通信できないスタンドアロンなネットワークです。
noneネットワークに接続しているコンテナは他のネットワークに接続できないという制約があります。
これら4つのネットワークはそれぞれ以下の図のようになります。
ざっくりとそれぞれのネットワークについてご紹介しましたので、次は実際に設定してみましょう。
bridgeネットワークに作成したコンテナ同士で通信させる
まずは、デフォルトで接続されるbridgeネットワークにコンテナを作成して通信させてみます。
こんなイメージです。※IPなどは出鱈目です。
まずは、docker runコマンドでnginxのコンテナを作成します。
$ docker run --name web1 -d -p 8080:80 nginx 171ms 日 2/13 21:55:10 2022
8fb090e27e7d35c32bf4a0aedcff522eae775275fda4c4994948ca3d398ff7ee
docker ps -a 2340ms 日 2/13 21:55:19 2022
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8fb090e27e7d nginx "/docker-entrypoint.…" 12 seconds ago Up 9 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp web1
この状態で、dockerのネットワークを確認するdocker network inspect
コマンドを実行しbridgeネットワークに所属しているコンテナを確認してみます。
$ docker network inspect bridge
・・・省略・・・
"Containers": {
"8fb090e27e7d35c32bf4a0aedcff522eae775275fda4c4994948ca3d398ff7ee": {
"Name": "web1",
"EndpointID": "1635540f0f10aad340484e6c9c4d4d8f5a79fc68a07a8f5f2c597b0e290c7369",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
・・・省略・・・
ネットワークの情報も一緒に出てくるのでちょっと長いですが、Containersのところで先程作成したweb1というコンテナとそのネットワーク情報が確認できます。
dockerホストがmacの場合、172.17.0.2にpingを打っても通信できません。
bridgeなので通信できても良さそうなのですが、ifconfigなどで自身のインターフェースを確認するとbridgeネットワークのインターフェースがありません。
Docker ドキュメント日本語化プロジェクトの記述によると、macからは見えないようになっているようです。
dockerホストからbridgeネットワークのコンテナに通信する場合はLinuxの仮想マシンを使うかdocker-machineコマンドで仮想ホストを作成してその上で実行してみましょう。
次に、作成したweb1に対して通信を行うコンテナを作成します。
web1はwebサーバとして稼働しているので、curlを実行するコンテナを作成します。
Dockerfileは以下の通り。
FROM alpine:3.7
RUN apk update
RUN apk add curl
CMD curl http://172.17.0.2
ベースイメージのalpine:3.7は軽量のLinuxです。
curlをインストールして使えるようにしているだけのイメージになります。
早速ビルドして実行します。
$ docker build -t my-curl . 40.9s 日 2/13 22:13:26 2022
[+] Building 10.0s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 117B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3.7 4.0s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [1/3] FROM docker.io/library/alpine:3.7@sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10 2.5s
=> => resolve docker.io/library/alpine:3.7@sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10 0.0s
=> => sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f 1.51kB / 1.51kB 0.0s
=> => sha256:5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6 2.11MB / 2.11MB 2.0s
=> => sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10 1.41kB / 1.41kB 0.0s
=> => sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b 528B / 528B 0.0s
=> => extracting sha256:5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6 0.3s
=> [2/3] RUN apk update 2.1s
=> [3/3] RUN apk add curl 1.1s
=> exporting to image 0.2s
=> => exporting layers 0.1s
=> => writing image sha256:412011fdb2f5b62be1a3235fa51aaf3e2c1d0010fedad212f194440361e793e1 0.0s
=> => naming to docker.io/library/my-curl 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
$ docker run --name my-curl my-curl 20s 日 2/13 22:14:40 2022
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 100k 0 --:--:-- --:--:-- --:--:-- 300k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
はい!OK!
ご覧の通り、172.17.0.2に対してcurlを実行し、htmlのレスポンスを取得することができていますね。
内容も、nginxのデフォルトページなので問題なさそうです。
試しに、名前解決をしてみる
名前解決はできないとお伝えしていますが、実際どうなのかやってみます。
Dockerfileを以下のように書き換えてビルドし直します。
FROM alpine:3.7
RUN apk update
RUN apk add curl
CMD curl http://web1
実行結果は以下の通り。
$ docker run --name my-curl my-curl 221ms 日 2/13 22:23:43 2022
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0curl: (6) Could not resolve host: web1
まあ、予想通り「Could not resolve host: web1」ですね。。
ユーザー定義ネットワークを作成して、コンテナのネットワークを切り替える
ユーザー定義とあるように、このネットワークはdocker network create
コマンドを実行して新規ネットワークを作成。自分で作成する必要があります。
$ dockera network create my-network
2bced8ebef523ac0471e730e33279a54bd5d97241a61869ef8de188d062bc08f
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c23cba88ae63 bridge bridge local
56a710f51861 docker_gwbridge bridge local
0bbee5e422cd host host local
2bced8ebef52 my-network bridge local
d900789f82bd none null local
したから2番目に作成した「my-network」が確認できました。これでネットワーク作成は完了です。
次に、先程作成したweb1の接続されているネットワークを切り替えます。
$ docker network disconnect web1
# 特に何も出力されません。
$ docker network inspect bridge
・・・省略・・・
"Containers": {},
・・・省略・・・
bridgeネットワークの詳細からweb1のコンテナがなくなっていることが確認できます。
つぎに、先程作成した「my-network」に接続します。
$ docker network connect my-network web1
#特に何も出力されません。
$ docker network inspect my-network
・・・省略・・・
"Containers": {
"8fb090e27e7d35c32bf4a0aedcff522eae775275fda4c4994948ca3d398ff7ee": {
"Name": "web1",
"EndpointID": "890a78a864bf914ab0ad1050de9b0ca3c44e70048d84ef5403ec822eaced8017",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
}
・・・省略・・・
これでweb1を作成したユーザー定義ネットワークに接続することができました。
再び、curlを実行するコンテナを起動してみます。
ただし、今回は起動時に接続するネットワークを指定して起動します。
$ docker run --name my-curl --net my-network my-curl
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
100 615 100 615 0 0 13977 0 --:--:-- --:--:-- --:--:-- 13977
はい!OK!
今度は、http://web1に対しても名前解決して通信することができました!