2017年4月8日

Dcoker network - bridge

本篇是閱讀 docker network 官方相關文件後一些自己覺得重要的內容而做的筆記,主要是以 bridge 為主,其他詳細的內容可以參考 Docker container networking

network 簡介

network 為 docker 的一項功能,讓你可以建立虛擬網路,將 container 加到網路內,建立起屬於你自己應用程式的網路拓墣。另外 network 也可以橫跨多台主機,讓你實現分散式應用服務。

安裝 Docker 後,預設會有三個 network,分別為 bridge、none 以及 host, 你可以用以下指令查看相關資訊:

# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
1623cc36aeae        bridge              bridge              local
7039bb756843        host                host                local
564a81a95b49        none                null                local

bridge 是預設的 network,在你使用 docker run 指令啟動 container 時,如果你沒有下 --network 參數指定,則預設都會是 bridge。 你可以透過以下指令來觀察 bridge 的詳細參數:

[root@lzstg ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "1623cc36aeae8538c05780f86517dc07d6dc613c4b9d13ad6f949e33fced8f1e",
        "Created": "2017-03-06T11:35:35.006599348+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "5b7be3dc833e3b2a46d9f6510af70e507f0cb068653fca024da7df8d5c86276b": {
                "Name": "miniweb_lzstg",
                "EndpointID": "bd107fcd1fbe5fe269665797b4fbd6728bfd8df06afdf5871ca10d8d426d4888",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "f3aabba6c0a2bc1fac6a262854b0fb1980e5c3329552f63d1fbc61c1eb45ab7d": {
                "Name": "miniweb",
                "EndpointID": "7c8cd504316cd351784a6afee89a4eea48f079e522883322d3f7a253207acf55",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

在 IPAM -> Config 底下可以看見,Subnet 設定為 172.17.0.0/16,而 Gateway 為 172.17.0.1。

在 Containers 設定內,如果你已經有啟動 container 且它的 network 為 bridge,這邊就會有資料,否則會是 {};另外也可以看到這邊啟動了兩個 container,IP 分別為 172.17.0.3 與 172.17.0.2。

其他兩個預設建立的 network 分別為 host 與 none,設為 host 則 container 的網路會與你 docker host 主機的網路設定相同。舉例來說,如果你啟動一個 tomcat container,並且把它的 network 設為 host,當 container 啟動時,你就可以直接在瀏覽器上輸入你的機器 ip,port 為 8080,就能開啟 tomcat 管理頁面了。設定為 none 顧名思義就是 container 不使用任何網路介面卡。

預設的 bridge

上面有提到,在啟動 container 時如果沒有加上 --network 指令來指定網路設定,則都會使用預設的 bridge。在預設的 bridge 底下的 container,是可以透過 ip 互相 ping 對方的。

比如說我先啟動兩個 container,命名為 foo1 與 foo2,然後在使用 docker network inspect 指令觀察他們配到的 ip,如下:

$ docker run --name foo1 -d tomcat:8.5.11-jre8
$ docker run --name foo2 -d tomcat:8.5.11-jre8
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "f2a2d7dd6e4ab4edd774ef0d80f8b91f5b80a8f08b0f5162a35c02abf41ef4e1",
        "Created": "2017-03-31T11:30:40.628367278Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "70cdec387fc68128b9968689b9bf883150b180ff37134756a97fec2c881b62a4": {
                "Name": "foo2",
                "EndpointID": "3ed1dcee3d7805fd61cf5436b53d18563314c9abdb617f9d0665b19ff986fa6a",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "c52be8382496c30d735620a601167c1de527c47cbead841e747be2b3bec6843d": {
                "Name": "foo1",
                "EndpointID": "3601fcf1ea3b94d1150925e10238795eab2d7165394024006542516619a105fb",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

可以在 Containers 的設定內看到,foo1 配到的 ip 為 172.17.0.2,而 foo2 配到的 ip 為 172.17.0.3,接著我們使用 docker exec 指令進入到 foo1 的 bash,然後看看能不能 ping 到 foo2(172.17.0.3)

$ docker exec -it foo1 /bin/bash
root@c52be8382496:/usr/local/tomcat# ping 172.17.0.3 -c 4
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.171 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.094 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.115 ms
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.094/0.118/0.171/0.032 ms

透過 ip ping 的結果是能找到對方的,但是若是透過 container name 則無法找到對方,如下:

root@c52be8382496:/usr/local/tomcat# ping foo2
ping: unknown host

要能透過 container name 直接找到其他 container,有兩種方式,一種是 docker 比較早期的方法,在 docker run 時加上 --link,讓 container 連接在一起,此方法可以參考官網的這篇文件 Legacy container links,官方有說明 --link 最終可能會被棄用,有興趣的可以閱讀此篇文章,這邊不多做說明。另一種方式就是使用自己定義的 network 來達成。

自定義的 bridge network

我們可以使用 docker network create 指令來建立一個新的網路拓墣。

docker network create foonet

接著在使用 docker run 啟動 container 時,使用 --network flag 將 container 指定到此網路拓墣:

docker run -d --network foonet --name foobar1 tomcat:8.5.11-jre8
docker run -d --network foonet --name foobar2 tomcat:8.5.11-jre8

我們可以透過 docker network inspect 指令觀察目前網路狀態,可以在印出來的 Containers 設定內找到兩個加入到此網路拓墣的 container 網路資訊。

docker network inspect foonet
[
    {
        "Name": "foonet",
        "Id": "c15a5f50792fe854f7722d266ca4cc7e57ccf9ac3dfe479dd711959de55deb0d",
        "Created": "2017-03-25T02:37:24.164070946Z",
        "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,
        "Containers": {
            "8c5956967f3e9c0701a84aa868f08053a8f03d691c509c37c462f045dedaa827": {
                "Name": "foobar2",
                "EndpointID": "576f9ee3f923af8838d4ce126de16b0c576dcb2aa814f642a482b1b54dd6f01d",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "b219692bba64311507c23bf4ee69ff33f415ebfcffe3d412b28fa7a44b942356": {
                "Name": "foobar1",
                "EndpointID": "37138005c073250f90f94cad523fbab656155a68f9a238f7a529d116a1bf0833",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

最後我們進入到其中一個 container 內,然後使用 container name 來 ping 對方,看看找不找的到對方。可以從結果看出,若是在自己定義的網路拓墣內,是可以直接用 container name 來找到對方機器的。

docker exec -it foobar1 /bin/bash
root@b219692bba64:/usr/local/tomcat# ping foobar2
PING foobar2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: icmp_seq=0 ttl=64 time=0.151 ms
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.141 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.285 ms

參考

Docker container networking

Work with network commands