淺談Docker之Docker網絡模式以及容器間通信


一、Docker的網絡模式介紹

docker默認提供3種網絡模式:bridge橋接模式、host主機模式、none無網絡模式

可以通過命令 docker network ls 查看

1.1、bridge橋接模式 

橋接模式是docker默認的網絡模式。當docker服務啟動后,會創建一個名字叫docker0的虛擬網橋,然后選一個與宿主機不一樣的網絡ip地址以及子網分配給docker0

另外每創建一個容器就會新增一個容器網卡,然后以橋接方式架到docker0網橋中,docker0會以NAT地址轉換的方式通過宿主機的網卡,從而與公網進行通信。

如下圖所示:

下面進行測試演示:

1、啟動docker服務后,通過命令 ip addr 發現docker0網卡ip為172.17.0.1

2、啟動一個docker容器 docker run -itd centos:7 /bin/bash ,再進行一次 ip addr 

發現新增一個網卡veth506a249@if6

3、執行命令 yum install -y bridge-utils 安裝工具,使用命令 brctl show 查看一下橋接情況

可以看到容器的網卡橋接到docker0上 

1.2、host主機模式

主機模式是指docker容器與公網通信時使用的是宿主機的ip與端口,同時容器自己不會有ip地址,所以在這模式下容器與宿主機之間並沒有隔離很分明。

在容器啟動命令時用參數--net=host指定當前容器網絡模式  docker run -itd --net=host centos:7 /bin/bash 

1.3、none無網絡模式

無網絡模式下相當於容器處於斷網狀態下,同樣沒有自己的ip地址。

創建容器時通過參數 --net=none 設置,這比較少使用。

1.4、總結

上面講了關於docker的網絡模式,主要關於以哪種方式讓服務器內部的容器與公網進行通信。

1、假如使用的是默認的橋接網絡模式,啟動容器的時候需要使用參數--p 宿主機端口:容器端口設置端口的映射。

2、假如使用的是host主機模式,因為使用的是宿主機的ip與端口,那就直接可以與公網通信。

 

二、Docker的內部通信

在實際的項目環境中,肯定會存在多個服務間通信的情況。也就是多個容器之間通信。

下面了解的是關於一個宿主機下多個服務間通信的情況。

舉個例子,例如多個服務訪問一個mysql數據庫。通常只需要在多個服務之間配置數據庫的地址就可以了。

因為它們都是通過默認的bridge進行通信的。

現在啟動兩個服務centos01和centos02

[root@localhost ~]# docker run -itd --name=centos01 mycentos:nettools /bin/bash
982a3d4cdb131bf33d217218c04aad278ac762376337e4180fd2eadc63599541
[root@localhost ~]# docker run -itd --name=centos02 mycentos:nettools /bin/bash
e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e

查看一下centos02的ip地址 docker inspect e1c43e2000915 ,發現是172.17.0.3

[
    {
        "Id": "e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e",
        "Created": "2020-02-18T08:17:13.893194133Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 19853,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-02-18T08:17:14.24517605Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:b92ca30f601cb7b594210e041eed8753aabb72dc5c2a18905b6272f5176ffdc0",
        "ResolvConfPath": "/var/lib/docker/containers/e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e/hostname",
        "HostsPath": "/var/lib/docker/containers/e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e/hosts",
        "LogPath": "/var/lib/docker/containers/e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e/e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e-json.log",
        "Name": "/centos02",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/fe38b48216b0e036c8a594635f6392d0f06f5da202e695a7052aa36ca510ddc1-init/diff:/var/lib/docker/overlay2/0dd6db3d6d6ee7fc48b4e13654a8d4414b545834df6e1524475649f2d67454de/diff:/var/lib/docker/overlay2/c9ac4844a5f33fad6a906ae9b4b86fa9f058c7ed1048bffad5b7a4aca454b33b/diff",
                "MergedDir": "/var/lib/docker/overlay2/fe38b48216b0e036c8a594635f6392d0f06f5da202e695a7052aa36ca510ddc1/merged",
                "UpperDir": "/var/lib/docker/overlay2/fe38b48216b0e036c8a594635f6392d0f06f5da202e695a7052aa36ca510ddc1/diff",
                "WorkDir": "/var/lib/docker/overlay2/fe38b48216b0e036c8a594635f6392d0f06f5da202e695a7052aa36ca510ddc1/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "e1c43e200091",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": true,
            "OpenStdin": true,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "mycentos:nettools",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20191001",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "e8d1342d5dab4b15608ef4be8cacc83c30ca579c8ce676c39a91683da5e662b5",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/e8d1342d5dab",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "f335c5cfcf7110d793f546ac44cf18bfd079f990ad3820646149f2adc28be692",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "76342053278e2345a41515f3c5728095c5a97f6230f7a3edf5e41017c67a0a9f",
                    "EndpointID": "f335c5cfcf7110d793f546ac44cf18bfd079f990ad3820646149f2adc28be692",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }
        }
    }
]
View Code

接下來進入centos01然后嘗試ping一下172.17.0.3,發現是ping成功的

[root@localhost ~]# docker exec -it centos01 /bin/bash
[root@982a3d4cdb13 /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.154 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.105 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.121 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.071 ms
64 bytes from 172.17.0.3: icmp_seq=5 ttl=64 time=0.070 ms
^C
--- 172.17.0.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3999ms
rtt min/avg/max/mdev = 0.070/0.104/0.154/0.032 ms
[root@982a3d4cdb13 /]# 

然后嘗試ping一下centos02,發現是ping失敗的

[root@982a3d4cdb13 /]# ping centos02
ping: centos02: Name or service not known

也就是說目前在默認bridge下是沒法通過容器名稱來進行通信的

回到宿主機查看一下bridge的信息,發現配置容器的相關網絡信息。

[root@localhost ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "76342053278e2345a41515f3c5728095c5a97f6230f7a3edf5e41017c67a0a9f",
        "Created": "2020-02-17T07:17:21.082636014+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": {
            "982a3d4cdb131bf33d217218c04aad278ac762376337e4180fd2eadc63599541": {
                "Name": "centos01",
                "EndpointID": "6d05788dc1e1ae12d6048879d5a0dc5012db828258e2de3ca91a7a1e1bc7cc33",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "e1c43e2000915b8256b1f0b6793b6f4bd1b2ff33ae1f32c6872ce21d4c5c8e4e": {
                "Name": "centos02",
                "EndpointID": "f335c5cfcf7110d793f546ac44cf18bfd079f990ad3820646149f2adc28be692",
                "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": {}
    }
]
View Code

在docker中容器間直接通過ip進行服務訪問是存在弊端的。假如上面例子中mysql的突然掛掉重啟也失敗,只能重新run一個。這時ip可能會發生變化,那就需要進去直接跟mysql通信的服務修改相關配置信息,就很不友好。

因此Docker也提供了基於容器名來與其它容器通信。

2.1、基於link實現單向通信

所謂單向通信是指只能單方面發起網絡請求。例如一個功能服務請求mysql服務器,通常mysql服務器不需要訪問功能服務。

同樣啟動兩個服務進行模擬操作。一個模擬mysql,一個模擬tomcat。tomcat服務通過 --link mysql link到mysql服務中

記住,mysql服務要首先啟動,不然會報錯!

[root@localhost ~]# docker run -itd --name mysql mycentos:nettools /bin/bash
97ad026117718a0524eec1eb7db04a0dc3317b228b44abcc2b65a857919d8589
[root@localhost ~]# docker run -itd --name tomcat --link mysql mycentos:nettools /bin/bash
14c127543930d9c992f38514ba1b3db30a9e350272f41800e3e6870be5357450

接着進入tomcat容器中,通過容器名mysql使用ping命令

[root@localhost ~]# docker exec -it 14c12754393 /bin/bash
[root@14c127543930 /]# ping mysql
PING mysql (172.17.0.2) 56(84) bytes of data.
64 bytes from mysql (172.17.0.2): icmp_seq=1 ttl=64 time=0.109 ms
64 bytes from mysql (172.17.0.2): icmp_seq=2 ttl=64 time=0.118 ms
64 bytes from mysql (172.17.0.2): icmp_seq=3 ttl=64 time=0.140 ms
^C
--- mysql ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.109/0.122/0.140/0.015 ms

在網絡中通過ping域名解析,無非就是通過本地hosts文件配置路由規則進行解析,還有就是通過DNS服務器解析

查看一下該hosts文件,發現配置了mysql容器的ip地址信息

[root@14c127543930 /]# 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      mysql 97ad02611771
172.17.0.3      14c127543930

接下來進入mysql容器嘗試ping一下tomcat容器,發現ping失敗

[root@localhost ~]# docker exec -it 97ad026117 /bin/bash
[root@97ad02611771 /]# ping tomcat
ping: tomcat: Name or service not known

也就是說通過--link實現單向通信,路由規則是通過改寫hosts文件實現。

2.2、利用bridge網橋實現雙向通信

從 Docker1.10 以后,docker daemon 實現了一個內嵌的 docker dns server,使容器可以直接通過“容器名”通信。

不過不能使用默認bridge,需要自定義網橋

創建一個新的網橋def_bridge:

[root@localhost ~]# docker network create -d bridge def_bridge
faeddc1fbfbf98f6572766003ff2cc27a023d43699fd994397013e09077c3784

啟動兩個容器名字分別為mysql和tomcat

[root@localhost ~]# docker run -itd --name mysql mycentos:nettools /bin/bash
6a9f1e9d0bb051ea31e5727193a1aed99b8039c2cde629fe2bd387def1abb5bd
[root@localhost ~]# docker run -itd --name tomcat mycentos:nettools /bin/bash
3e5950876d69712c3e2f8fd10268c9a21f1f21dd9937d1010ad2d5f709932831

然后將兩個啟動的容器都加入新增的網橋

[root@localhost ~]# docker network connect def_bridge mysql
[root@localhost ~]# docker network connect def_bridge tomcat

可以進入網橋查看一下,發現加入成功

[root@localhost ~]# docker network inspect def_bridge
[
    {
        "Name": "def_bridge",
        "Id": "faeddc1fbfbf98f6572766003ff2cc27a023d43699fd994397013e09077c3784",
        "Created": "2020-02-18T17:52:43.297517269+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": {
            "3e5950876d69712c3e2f8fd10268c9a21f1f21dd9937d1010ad2d5f709932831": {
                "Name": "tomcat",
                "EndpointID": "581356d1b23d64a76f0d83d1ee3416deea97e0c5d577070ac3f4d1bf94ee1dd9",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "6a9f1e9d0bb051ea31e5727193a1aed99b8039c2cde629fe2bd387def1abb5bd": {
                "Name": "mysql",
                "EndpointID": "6d06e5719fa26e2b0f2007a1cc2e25282faaa39d0347b02fdb63c823e49b20e5",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
View Code

分別進入兩個容器通過容器名互ping,發現ping成功

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
3e5950876d69        mycentos:nettools   "/bin/bash"         6 minutes ago       Up 6 minutes                            tomcat
6a9f1e9d0bb0        mycentos:nettools   "/bin/bash"         6 minutes ago       Up 6 minutes                            mysql
[root@localhost ~]# docker exec -it 6a9f1e9d0bb0 /bin/bash
[root@6a9f1e9d0bb0 /]# ping tomcat
PING tomcat (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat.def_bridge (172.18.0.3): icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from tomcat.def_bridge (172.18.0.3): icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from tomcat.def_bridge (172.18.0.3): icmp_seq=3 ttl=64 time=0.097 ms
64 bytes from tomcat.def_bridge (172.18.0.3): icmp_seq=4 ttl=64 time=0.060 ms
--- tomcat ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.057/0.078/0.100/0.021 ms
[root@6a9f1e9d0bb0 /]# exit
exit
[root@localhost ~]# docker exec -it 3e5950876d69 /bin/bash
[root@3e5950876d69 /]# ping mysql
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.def_bridge (172.18.0.2): icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from mysql.def_bridge (172.18.0.2): icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from mysql.def_bridge (172.18.0.2): icmp_seq=3 ttl=64 time=0.055 ms
64 bytes from mysql.def_bridge (172.18.0.2): icmp_seq=4 ttl=64 time=0.130 ms
--- mysql ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.040/0.073/0.130/0.034 ms

然后檢查一下tomcat容器的hosts文件以及resolv.conf文件

發現hosts文件沒有配置路由規則,而resolv.conf中配置了dns server 127.0.0.11

[root@3e5950876d69 /]# 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.3      3e5950876d69
172.18.0.3      3e5950876d69
[root@3e5950876d69 /]# cat /etc/resolv.conf 
nameserver 127.0.0.11
options ndots:0

也就是說通過自定義bridge雙向通信是通過內置的dns服務實現IP地址的解析工作

 

本文作者:hjjay
原文出處:https://www.cnblogs.com/jayhou/p/12319655.html
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM