docker容器網絡 - 同一個host下的容器間通訊

    對於複雜的應用,不可避免須要多個服務部署在多個容器中,而且服務間存在相互間通訊的狀況。好比服務A須要鏈接mysql的容器。本文將介紹docker的容器網絡,並經過實踐解決在同一個docker Host主機下的容器間通訊的問題。node

    在安裝好docker後,docker將建立一個linux網橋docker0,它在內核層連通了其餘的物理或虛擬網卡,也就是全部容器和本地主機都放到同一個物理網絡。咱們能夠經過 brctl 命令查看網橋的信息,brctl是須要自行安裝的。mysql

[root@localhost ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
br-1a83283cbf04		8000.0242123432ad	no		
br-70590112bbda		8000.0242927ea6d9	no		
docker0		8000.024232ccc082	no

    另外,docker還會給咱們建立三個網絡:bridge/host/none。咱們能夠經過network ls命令查看當前宿主機中全部的docker網絡。linux

[root@localhost ~]# docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
5a9ac72df73f        bridge              bridge              local
7d9eb4bd321c        host                host                local
4b740dab2aab        none                null                local

    其中,網橋bridge模式是在實際項目中經常使用的。接下來,以交互模式啓動兩個busybox容器。在沒有指定相關網絡的狀況下,容器都會鏈接到默認的bridge網絡。咱們能夠經過 --network 參數指定容器鏈接的網絡。sql

[root@localhost ~]# docker run -itd --name=busybox1 busybox
2813aba53acd688fa69807158830bef27b4ea8dc2ecfe13e7e357ce98a204f0b

[root@localhost ~]# docker run -itd --name=busybox2 busybox
83fbeeb4e0527ece0602729415a57383b474284143a381e0a27561a69d75b1f5

啓動容器後,檢查當前默認bridge網絡狀況。busybox1和busybox2容器已經鏈接到了bridge網絡,除此以外,還能夠獲取到兩個容器的IP地址。docker

[root@localhost ~]# docker network inspect bridge


[
    {
        "Name": "bridge",
        "Id": "5a9ac72df73f19beaade92a28d705509fd24c350497dd90ecae224fdb18214bc",
        "Created": "2018-12-25T16:30:26.58008782+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,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2813aba53acd688fa69807158830bef27b4ea8dc2ecfe13e7e357ce98a204f0b": {
                "Name": "busybox1",
                "EndpointID": "522f2b4b072098525939cc6b313f5673f82444d8ef6807bac0efcdce6a7c8418",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "83fbeeb4e0527ece0602729415a57383b474284143a381e0a27561a69d75b1f5": {
                "Name": "busybox2",
                "EndpointID": "e277940484662a341730766300149c2f63974d0b9e9cbd6c531bc7c8c37f31f9",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/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": {}
    }
]

接下來,咱們測試下兩個容器的互通狀況。bash

    進入busybox1容器,分別ping 容器busybox2的IP和容器名,能夠發現能夠經過IP地址ping通busybox2,可是不能經過容器ping通。其中,172.17.0.3是busybox2的IP地址。服務器

[root@localhost ~]# docker attach  2813aba53acd

/ # ping  172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.090 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.193 ms


/ # ping busybox2

在容器中,能夠查看容器的hosts文件,裏面沒有任何關於busybox2容器的信息。網絡

/ # cat /etc/hosts

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	2813aba53acd

    在計算機網絡中,想經過域名ping通其它網站,有兩種方法:一種是本地的hosts文件,裏面配置的是路由規則;另外一種是DNS服務,經過DNS服務器返回正確的IP地址。那麼docker是否也能夠經過容器名訪問其它容器的方式呢?oop

(1)link鏈接測試

默認的橋接網絡支持使用端口映射和 docker run --link 命令,實現容器間互相通訊。該方法已經在官方文檔中標識爲不推薦使用

https://docs.docker.com/network/links/

    下面,繼續介紹經過 --link 參數時間容器間通訊。咱們將建立busybox3和busybox4兩個容器,其中busybox4能夠經過busybox3容器名與busybox3容器進行通訊。

    新建busybox3和busybox4,其中busybox4經過 --link 參數指定鏈接到 busybox3容器。

[root@localhost ~]# docker run -itd --name=busybox3 busybox
a539a74a9ecad6782f88944604bbdd045f4a1fd6965a3484e04d1dbbec1e511d

[root@localhost ~]# docker run -itd --link busybox3  --name=busybox4 busybox
f6c470354b55300106a3a8960c4c935dcdd0cb0f7ad6c941c8f040fdb0cd0a04

從新進入容器busybox4,查看hosts文件,能夠看到host文件中已經出現busybox3容器,並配置了路由規則。

/ # cat /etc/hosts

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.4	busybox3 a539a74a9eca
172.17.0.5	f6c470354b55

測試busybox4鏈接容器busybox3

/ # ping busybox3
PING busybox3 (172.17.0.4): 56 data bytes
64 bytes from 172.17.0.4: seq=0 ttl=64 time=0.077 ms
64 bytes from 172.17.0.4: seq=1 ttl=64 time=0.125 ms
^C
--- busybox3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss

 

(2)自定義bridge網絡,實現容器間通訊

    從 Docker 1.10 版本開始,docker daemon 實現了一個內嵌的 DNS server,使容器能夠直接經過「容器名」通訊。使用默認的bridge網絡,不能經過DNS server實現經過容器名通訊,可是使用自定義bridge網絡能夠作到經過容器名互相通訊。

經過 docker network create 命令建立一個自定義的bridge網絡

[root@localhost ~]# docker network create --driver bridge busybox_bridge
1a83283cbf047fea14231daef7edb67e8a11383f61c176e5c4983e961e757a1e

[root@localhost ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
53c7e86fc3ec        bridge              bridge              local
1a83283cbf04        busybox_bridge      bridge              local
7d9eb4bd321c        host                host                local
4b740dab2aab        none                null                local

分別建立busybox5/busybox6容器,在run命令里加入--network參數使兩個容器綁定到前面自定義的網絡中。

[root@localhost ~]# docker run -itd --network busybox_bridge --name busybox5 busybox
ccd81a357cf48af2c01c64cd1ef7a4c463b415bd477d965f19a3b47be3760208

[root@localhost ~]# docker run -itd --network busybox_bridge --name busybox6 busybox
d3e5af0eeb86a480fe868bb9ea7cea2cb29b7f12b7f680cbd5b48288c15b10e9

查看busybox_bridge網絡狀況,能夠看到,busybox5/busybox6容器已經綁定到該網絡中。

[root@localhost ~]# docker network inspect busybox_bridge

[
    {
        "Name": "busybox_bridge",
        "Id": "1a83283cbf047fea14231daef7edb67e8a11383f61c176e5c4983e961e757a1e",
        "Created": "2018-12-25T22:17:10.981291803+08:00",
        "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": {
            "ccd81a357cf48af2c01c64cd1ef7a4c463b415bd477d965f19a3b47be3760208": {
                "Name": "busybox5",
                "EndpointID": "4da57d779c14bdee415eee69a92dd802250bf6e89cd744f8543c4498e32aebdc",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "d3e5af0eeb86a480fe868bb9ea7cea2cb29b7f12b7f680cbd5b48288c15b10e9": {
                "Name": "busybox6",
                "EndpointID": "6f130cc2055399c051cd556e20835793332605f9ee636885c602f2b257f9db80",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

接下來進入busybox5容器,測試是否能夠經過容器名ping通busybox6

[root@localhost ~]# docker attach busybox5


/ # ping busybox6
PING busybox6 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.107 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.149 ms

看下容器的hosts文件,文件裏是沒有busybox6的映射配置的。那麼它是怎麼經過容器名訪問到另外一個容器的呢?答案就是內嵌的dns服務器。

/ # cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.18.0.2	ccd81a357cf4

查看DNS服務,能夠看到指定了DNS解析服務地址:nameserver 127.0.0.11 。若是是鏈接到默認bridge網絡的容器,在resolv.conf文件是沒有127.0.0.11這個DNS服務器配置的

/ # cat /etc/resolv.conf 
nameserver 127.0.0.11
options ndots:0

容器中的DNS名稱解析優先級順序爲:

  • ​ 內置DNS服務器127.0.0.11。
  • ​ 經過--dns等參數爲容器配置的DNS服務器。
  • ​ docker守護進程的--dns服務配置(默認爲8.8.8.8和8.8.4.4)
  • ​ 宿主機上的DNS設置。

 

文章收錄於:

容器技術系列彙總

相關文章
相關標籤/搜索