为什么同一台机器上的两个容器IP可以互相通信?

在聊这个问题之前,我们先看一个日常生活中的例子来辅助理解,Docker Bridge网络在局域网中,多台电脑要想互相通信,需要一个交换机通过动态IP协议给每个机器分配一个IP地址(IP在同一网段),并且每台电脑都有一个默认的网关IP(交换机IP),通信的话先把数据包发送到交换机上面,通过转发规则转发到目标电脑上面。

同一网段多台电脑通信

docker创建的容器默认是连接到一个接口为docker0的Bridge网络上的,我们通过以下容器去分析。

首先我们先查看一下宿主机上的网络接口,是有一个接口为docker0的Bridge(网桥)的网络。IP是172.17.0.1/16(IP为172.17.0.1的16位掩码)

# 列出宿主机的网络接口
vagrant@swarm2:~$ ip a
...........
10: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:1a:21:8e:9f brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
...........

查看当前docker提供的网络模式,可以看到有一个DRIVER为bridge(网桥)的

vagrant@swarm2:~$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
f20354b70d12   bridge    bridge    local
d65e5e9c6cd0   host      host      local
da5483f547f5   none      null      local

创建两个容器(box1和box2),需要用到BusyBox这个镜像。

在创建之前,先介绍一下BusyBox,它是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令,也包含了 Linux 系统的自带的shell。

创建box1和box2容器,并且查看他们的IP。

# 创建容器box1
vagrant@swarm2:~$  docker container run -d --rm --name box1 busybox /bin/sh -c "while true; do sleep 3600; done"
30d22a0aeffa8631d9d6592d26b95176061d753bdbc25bcdf58be3ff90c26918

# 创建容器box2
vagrant@swarm2:~$  docker container run -d --rm --name box2 busybox /bin/sh -c "while true; do sleep 3600; done"
2a4a937afe9ff6903162dd0508d1151846431fbed3bdbd0da9eb47832409dafe

# box1的IP为 172.17.0.2/16
vagrant@swarm2:~$ docker exec -it box1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12629: eth0@if12630: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

# box2的IP为 172.17.0.3/16
vagrant@swarm2:~$ docker exec -it box2 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12631: eth0@if12632: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

# box1容器测试访问box2可通
vagrant@swarm2:~$ docker exec -it box1 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.122 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.098 ms
^C
--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.098/0.110/0.122 ms

# box2容器测试访问box1可通
vagrant@swarm2:~$ docker exec -it box2 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.086 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.059/0.072/0.086 ms

查看bridge的详情,IPAM->Config->Subnet、Gateway和宿主机接口docker0的IP一致,并且Options-> com.docker.network.bridge.name值也是docker0

可以看到Containers里有两个容器box1(172.17.0.2/16)和box2(172.17.0.3/16)

vagrant@swarm2:~$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "f20354b70d12a90c76c94b84ea78bc66688b794f7d62b538f525ebaad3151f7a",
        "Created": "2022-06-18T02:17:56.044977005Z",
        "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": {
            "2a4a937afe9ff6903162dd0508d1151846431fbed3bdbd0da9eb47832409dafe": {
                "Name": "box2",
                "EndpointID": "0b2a221a7f9498ad60bbc1c7fc21821e1bb48d2953b9a1a36d369f7310c517bb",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "30d22a0aeffa8631d9d6592d26b95176061d753bdbc25bcdf58be3ff90c26918": {
                "Name": "box1",
                "EndpointID": "97381c28d2e8381745ed8680bf1d104149f917938e8aa66795bd8452a06fcb38",
                "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": {}
    }
]

通过上面我们可以看的出来,如果创建容器的时候不指定网络,docker创建的容器会默认连接到docker0的bridge(网桥)接口上。即docker0的bridge就类似于现实生活中的交换机,box1和box2就当于连接同一网段交换机的两个电脑,他们可以通过docker0进行数据包的传递和通信

Last modification:June 19, 2022
如果觉得我的文章对你有用,请随意赞赏