外部ネットワーク側からDockerコンテナに通信できる環境を作成する

dockerコンテナを活用した開発環境を整備するにあたり、既存ネットワーク機器、サーバ機器との通信できる環境が不可欠になります。そんな時に、必要最小限の手間がdocker-network環境を整備する方法を、まとめてみました。

docker-network.001.png


◼️ Linux Host環境の事前構成を確認しておく


(1) UbuntuOSのバージョン確認

$ cat /etc/lsb-release 

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS"


(2) NICインタフェース確認

$ ifconfig ens6

ens6 Link encap:Ethernet HWaddr 52:54:00:a8:f6:26
inet addr:192.168.100.201 Bcast:192.168.100.255 Mask:255.255.255.0
inet6 addr: 240b:11:53a0:400:5054:ff:fea8:f626/64 Scope:Global
inet6 addr: fe80::5054:ff:fea8:f626/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:21888 errors:0 dropped:0 overruns:0 frame:0
TX packets:19053 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:48194353 (48.1 MB) TX bytes:1774186 (1.7 MB)


(3) dockerバージョン確認

$ docker version

Client:
Version: 18.06.1-ce
API version: 1.38
Go version: go1.10.3
Git commit: e68fc7a
Built: Tue Aug 21 17:24:56 2018
OS/Arch: linux/amd64
Experimental: false

Server:
Engine:
Version: 18.06.1-ce
API version: 1.38 (minimum version 1.12)
Go version: go1.10.3
Git commit: e68fc7a
Built: Tue Aug 21 17:23:21 2018
OS/Arch: linux/amd64
Experimental: false


◼️ 通常のDocker環境で、外部ネットワークと通信してみる


(1) Dockerコンテナを起動する

手始めに、次のようなdocker-compose.yamlを活用して、dockerコンテナを起動します。


docker-compose.yaml

version: "2"

services:
host1:
image: ubuntu:14.04
container_name: host1
command: /bin/sh -c "tail -f /dev/null"
hostname: host1
host2:
image: ubuntu:14.04
container_name: host2
command: /bin/sh -c "tail -f /dev/null"
hostname: host2


$ docker-compose up -d

$ docker-compose ps

Name Command State Ports
----------------------------------------------------
host1 /bin/sh -c tail -f /dev/null Up
host2 /bin/sh -c tail -f /dev/null Up


(2) dockerコンテナ動作を確認する

$ docker exec -it host1 bash

root@host1:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:1b:00:03
inet addr:172.27.0.3 Bcast:172.27.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1408 (1.4 KB) TX bytes:280 (280.0 B)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

root@host1:/# ping 192.168.100.1

PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data.
64 bytes from 192.168.100.1: icmp_seq=1 ttl=64 time=0.116 ms
64 bytes from 192.168.100.1: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 192.168.100.1: icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from 192.168.100.1: icmp_seq=4 ttl=64 time=0.059 ms
64 bytes from 192.168.100.1: icmp_seq=5 ttl=64 time=0.059 ms
64 bytes from 192.168.100.1: icmp_seq=6 ttl=64 time=0.058 ms
^C
--- 192.168.100.1 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 4997ms
rtt min/avg/max/mdev = 0.054/0.066/0.116/0.024 ms


(3) docker構成を確認しておく

今回、起動したdockerコンテナが収容されているdocker-network構成を確認しておく

$ docker inspect sample-docker_default 

[
{
"Name": "sample-docker_default",
"Id": "0de2654c44bf4639f4bb599b9d9f800f8789bfd55aae702a378c19ba0efbdd9e",
"Created": "2018-10-11T07:23:42.069601379+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.27.0.0/16",
"Gateway": "172.27.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"1d86065eda54e3f3130a54f05038274db8b872b88672fc4e2797e42d245c1d41": {
"Name": "host2",
"EndpointID": "73e5807379a1fcde47e3c0222c52c6e93e36eedc4347994d367963decfdbd47b",
"MacAddress": "02:42:ac:1b:00:02",
"IPv4Address": "172.27.0.2/16",
"IPv6Address": ""
},
"f75fa1b14dca5fabe5ce925be832044071925be253e814814e5708ef874f28e3": {
"Name": "host1",
"EndpointID": "28945f60e55ddb20ba6ed53d2282fa43f5566d186355e880a917da31be114fa3",
"MacAddress": "02:42:ac:1b:00:03",
"IPv4Address": "172.27.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

dockerコンテナから、外部ネットワークに通信する場合には、通常のdockerコンテナ構成でも、特に手間をかけることなく、通信できます。しかしながら、外部ネットワークから、dockerコンテナに通信する場合には、このままのdocker環境では、実現できません。

強引に、iptablesを使って、dockerコンテナに割り当てられたIPアドレスを、外部ネットワークのIPアドレスにNAT変換すれば、実現できそうですが、docker環境が、かなり煩雑になりそうです。


◼️ Docker環境を構成変更する


(1) Linuxブリッジ"br0"を作成する

Linux Host環境において、"br0"を作成しておきます。以下のようにコンフィグファイルを修正して、Ubuntuを再起動しました。


/etc/network/interfaces

... (snip)

auto ens6
iface ens6 inet manual

auto br0
iface br0 inet static
address 192.168.100.201
netmask 255.255.255.0
network 192.168.100.0
broadcast 192.168.100.255
gateway 192.168.100.1
dns-nameservers 192.168.100.1
bridge_ports ens6
bridge_stp off
bridge_fd 0
bridge_maxwait 1



(2) docker-networkを作成して、linuxブリッジ"br0"を配備する

Dockerコンテナを収容できるように、docker-networkを作成しておきます。

なお、このとき、ssh等による遠隔ログインで作業すると、ログインターミナルが使用できなくなる恐れがあるので、consoleログインで作業してください。

$ docker network create \

--driver=bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.201 \
--opt "com.docker.network.bridge.name"="br0" \
sample-network


(3) UbuntuOSを再起動する

再起動後、linuxブリッジの構成を確認しておきます

$ brctl show

bridge name bridge id STP enabled interfaces
br0 8000.525400a8f626 no ens6
docker0 8000.02421684adc9 no


(4) dockerコンテナを起動する

先ほど使用したdocker-compose.yamlを一部カスタマイズして、dockerコンテナを起動します。


docker-compose.yaml

version: "2"

services:
host1:
image: ubuntu:14.04
container_name: host1
command: /bin/sh -c "tail -f /dev/null"
hostname: host1
networks:
sample-network:
ipv4_address: 192.168.100.221
host2:
image: ubuntu:14.04
container_name: host2
command: /bin/sh -c "tail -f /dev/null"
hostname: host2
networks:
sample-network:
ipv4_address: 192.168.100.222

networks:
sample-network:
external: true


$ docker-compose up -d

Creating host2 ... done
Creating host1 ... done

$ docker-compose ps

Name Command State Ports
----------------------------------------------------
host1 /bin/sh -c tail -f /dev/null Up
host2 /bin/sh -c tail -f /dev/null Up


(5) dockerコンテナ動作を確認する

$ docker exec -it host1 bash

root@host1:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:c0:a8:64:dd
inet addr:192.168.100.221 Bcast:192.168.100.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:54 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:13573 (13.5 KB) TX bytes:0 (0.0 B)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

root@host1:/# ping 192.168.100.1

PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data.
64 bytes from 192.168.100.1: icmp_seq=1 ttl=255 time=1.84 ms
64 bytes from 192.168.100.1: icmp_seq=2 ttl=255 time=1.04 ms
64 bytes from 192.168.100.1: icmp_seq=3 ttl=255 time=1.37 ms
64 bytes from 192.168.100.1: icmp_seq=4 ttl=255 time=1.32 ms
^C
--- 192.168.100.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.044/1.396/1.841/0.288 ms


(6) 外部ネットワーク側から、dockerコンテナにアクセスしてみる

dockerコンテナ"host1", "host2"に向けて、ping疎通性を確認してみる。

ttsubo@ubuntu:~$ ping 192.168.100.221

PING 192.168.100.221 (192.168.100.221) 56(84) bytes of data.
64 bytes from 192.168.100.221: icmp_seq=1 ttl=64 time=0.508 ms
64 bytes from 192.168.100.221: icmp_seq=2 ttl=64 time=0.275 ms
64 bytes from 192.168.100.221: icmp_seq=3 ttl=64 time=0.292 ms
64 bytes from 192.168.100.221: icmp_seq=4 ttl=64 time=0.285 ms
^C
--- 192.168.100.221 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.275/0.340/0.508/0.097 ms

ttsubo@ubuntu:~$ ping 192.168.100.222

PING 192.168.100.222 (192.168.100.222) 56(84) bytes of data.
64 bytes from 192.168.100.222: icmp_seq=1 ttl=64 time=0.316 ms
64 bytes from 192.168.100.222: icmp_seq=2 ttl=64 time=0.236 ms
64 bytes from 192.168.100.222: icmp_seq=3 ttl=64 time=0.252 ms
64 bytes from 192.168.100.222: icmp_seq=4 ttl=64 time=0.253 ms
^C
--- 192.168.100.222 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.236/0.264/0.316/0.032 ms

外部ネットワーク側から、dockerコンテナに向けて、通信できるようになりました。


(7) docker構成を確認しておく

$ docker inspect sample-network

[
{
"Name": "sample-network",
"Id": "e8d9426b605b9f1a33a1bba398f34648c7f63811fa0d36ab9eaba3b30daeaa1f",
"Created": "2018-10-12T20:56:23.04226508+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.100.0/24",
"Gateway": "192.168.100.201"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"41828c1fe2bd1e3478b8c4a836ac411cc032b23b38b31e38ead636b5986172b1": {
"Name": "host1",
"EndpointID": "59b969ac86263962681d84e484d33a13808b877cbf9f6d7bfd9f6cde236d0fc2",
"MacAddress": "02:42:c0:a8:64:dd",
"IPv4Address": "192.168.100.221/24",
"IPv6Address": ""
},
"53190efb688fa76d8c592838c8aec5f2a3b4e93992297055acfc0f16ad94a988": {
"Name": "host2",
"EndpointID": "f1346174c2cf92e8afb0fb7ae717cdbde5cb75571cc1547b4e8993d8e61dfa92",
"MacAddress": "02:42:c0:a8:64:de",
"IPv4Address": "192.168.100.222/24",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.name": "br0"
},
"Labels": {}
}
]

以上です。


◼️ 補足事項

上記のDockerネットワーク環境を作成した後、dockerイメージのbuildがうまくいかなくなるケースがあります。

(Dockerfileの中で、pipを用いて、packageインストールを実行しているような場合)

https://stackoverflow.com/questions/48277599/pip-inside-dockerfile-under-proxy

このような事象が発生した場合には、 --network=host オプションを指定すると回避できました。