Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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 オプションを指定すると回避できました。

ttsubo
SDN分野に興味があります。 ただいま、golangを勉強中です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away