目录
1、基于 Overlay 网络(适用于 Docker Swarm)
2、使用静态路由和 iptables 规则实现跨宿主机容器通信
一、同宿主机的通信
角色 | 操作系统 | IP地址 | Docker版本 |
服务端/客户端 | CentOS 7.8 | 10.4.7.11 | 26.1.4 |
1、基于网络模式的通信
1.1 Bridge 网络模式(默认模式)
- 原理
- Docker 在宿主机上创建一个名为docker0的虚拟网桥。当容器启动时,Docker 会为容器创建一对虚拟网络接口(veth pair),一端放在容器内,另一端连接到docker0网桥。
- 同一宿主机上的容器都连接到docker0网桥,它们在逻辑上处于同一个局域网中,网段通常为172.17.0.0/16(不同版本可能略有不同)。
- 通信方式
- 容器之间可以通过各自在这个局域网中的 IP 地址进行通信。例如,容器 A 的 IP 地址为172.17.0.2,容器 B 的 IP 地址为172.17.0.3,容器 A 可以直接通过172.17.0.3访问容器 B,反之亦然。
命令示例:
hostname -i
docker run -itd --name test-01 centos
docker run -itd --name test-02 centos
hostname -i
docker ps -a
docker exec -it test-01 hostname -i
docker exec -it test-02 hostname -i
docker exec -it test-01 ping -c1 172.17.0.3
docker exec -it test-02 ping -c1 172.17.0.2
docker exec -it test-01 ping -c1 test-02
docker exec -it test-02 ping -c1 test-01
docker rm -f $(docker ps -aq) &>/dev/null
输出结果:
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker run -itd --name test-01 centos
22034ee2b1a5b22d7aa3424af81370507d20474e66c684c30e7bf9a2a9c167e0
[root@MineGi ~]# docker run -itd --name test-02 centos
4d8014aa353042d9ec3405663dadd476d2216fd6799a407dcf5aa6a34aa60b07
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 fe80::74f6:eff:fe73:907f%vethc2eb1da fe80::bcb3:7ff:fe21:dba%veth8f5f4a4 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4d8014aa3530 centos "/bin/bash" 12 seconds ago Up 11 seconds test-02
22034ee2b1a5 centos "/bin/bash" 18 seconds ago Up 17 seconds test-01
[root@MineGi ~]# docker exec -it test-01 hostname -i
172.17.0.2
[root@MineGi ~]# docker exec -it test-02 hostname -i
172.17.0.3
[root@MineGi ~]# docker exec -it test-01 ping -c1 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.146 ms
--- 172.17.0.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.146/0.146/0.146/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.083 ms
--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.083/0.083/0.083/0.000 ms
[root@MineGi ~]# docker exec -it test-01 ping -c1 test-02
ping: test-02: Name or service not known
[root@MineGi ~]# docker exec -it test-02 ping -c1 test-01
ping: test-01: Name or service not known
[root@MineGi ~]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ~]#
1.2 Host 网络模式
- 原理
- 采用 Host 网络模式的容器共享宿主机的网络栈,容器没有自己独立的 IP 地址,而是直接使用宿主机的 IP 地址。
- 通信方式
- 容器内的网络进程就像宿主机上的普通网络进程一样。例如,宿主机 IP 为192.168.1.100,容器内的应用监听192.168.1.100上的端口,它可以和宿主机上其他监听相同 IP 端口的应用进行通信,就像它们是宿主机上的普通应用一样。
命令示例:
hostname -i
docker run -itd --name test-01 --net host centos
docker run -itd --name test-02 --net host centos
hostname -i
docker ps -a
docker exec -it test-01 hostname -i
docker exec -it test-02 hostname -i
docker exec -it test-01 ping -c1 10.4.7.11
docker exec -it test-02 ping -c1 10.4.7.11
docker exec -it test-01 ping -c1 test-02
docker exec -it test-02 ping -c1 test-01
docker rm -f $(docker ps -aq) &>/dev/null
输出结果:
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker run -itd --name test-01 --net host centos
1d2d6eab021a0d5498b7d086797b2e59567d6f25d3714887348946083c0ad58b
[root@MineGi ~]# docker run -itd --name test-02 --net host centos
33da82276ee4083e3208a2e568d5a964971f2eda5f5e1368d9dba64c6ed55771
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
33da82276ee4 centos "/bin/bash" 12 seconds ago Up 12 seconds test-02
1d2d6eab021a centos "/bin/bash" 18 seconds ago Up 18 seconds test-01
[root@MineGi ~]# docker exec -it test-01 hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker exec -it test-02 hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker exec -it test-01 ping -c1 10.4.7.11
PING 10.4.7.11 (10.4.7.11) 56(84) bytes of data.
64 bytes from 10.4.7.11: icmp_seq=1 ttl=64 time=0.045 ms
--- 10.4.7.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.045/0.045/0.045/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 10.4.7.11
PING 10.4.7.11 (10.4.7.11) 56(84) bytes of data.
64 bytes from 10.4.7.11: icmp_seq=1 ttl=64 time=0.078 ms
--- 10.4.7.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.078/0.078/0.078/0.000 ms
[root@MineGi ~]# docker exec -it test-01 ping -c1 test-02
ping: test-02: Name or service not known
[root@MineGi ~]# docker exec -it test-02 ping -c1 test-01
ping: test-01: Name or service not known
[root@MineGi ~]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ~]#
1.3 Container 网络模式
- 原理
- 多个容器可以共享同一个网络命名空间,这些容器在网络上类似于同一个主机内的不同进程。
- 通信方式
- 共享网络命名空间的容器可以直接通过本地回环接口(lo)进行通信。例如,容器 C 和容器 D 采用 Container 网络模式,它们可以通过127.0.0.1进行通信,就像它们是同一个操作系统内的两个进程。
命令示例:
hostname -i
docker run -itd --name test-01 centos
docker run -itd --name test-02 --net=container:test-01 centos
hostname -i
docker ps -a
docker exec -it test-01 hostname -i
docker exec -it test-02 hostname -i
docker exec -it test-01 ping -c1 127.0.0.1
docker exec -it test-02 ping -c1 127.0.0.1
docker exec -it test-01 ping -c1 test-02
docker exec -it test-02 ping -c1 test-01
docker rm -f $(docker ps -aq) &>/dev/null
输出结果:
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker run -itd --name test-01 centos
5f0be4ac9f40cc9167c8a7023e6b958ea6e004bca2e17ac61beb50cd3138744b
[root@MineGi ~]# docker run -itd --name test-02 --net=container:test-01 centos
96e364a9298337cf0189badd9e611f812e8266e097920b803a79b1d4e5c3b439
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 fe80::28e7:84ff:feb2:a688%vethf4202a9 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96e364a92983 centos "/bin/bash" 11 seconds ago Up 10 seconds test-02
5f0be4ac9f40 centos "/bin/bash" 17 seconds ago Up 16 seconds test-01
[root@MineGi ~]# docker exec -it test-01 hostname -i
172.17.0.2
[root@MineGi ~]# docker exec -it test-02 hostname -i
172.17.0.2
[root@MineGi ~]# docker exec -it test-01 ping -c1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.075 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.075/0.075/0.075/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.088/0.088/0.088/0.000 ms
[root@MineGi ~]# docker exec -it test-01 ping -c1 test-02
ping: test-02: Name or service not known
[root@MineGi ~]# docker exec -it test-02 ping -c1 test-01
ping: test-01: Name or service not known
[root@MineGi ~]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ~]#
2、使用--link选项
- 原理
- --link选项允许一个容器链接到另一个容器。当使用--link时,Docker 会在源容器的/etc/hosts文件中添加目标容器的信息,包括 IP 地址和容器名称等。
- 示例操作
- 在web-container中,可以通过db-alias(这里是db)这个名称来访问db-container。不过,这种方式有一些局限性,例如不支持容器的动态添加和删除,并且在较复杂的网络环境中可能会出现问题,现在更推荐使用自定义网络来实现容器互联。
命令示例:
hostname -i
docker run -itd --name test-01 centos
docker run -itd --name test-02 --link test-01:alias centos
hostname -i
docker ps -a
docker exec -it test-01 hostname -i
docker exec -it test-01 tail -2 /etc/hosts
docker exec -it test-02 hostname -i
docker exec -it test-02 tail -2 /etc/hosts
docker exec -it test-01 ping -c1 172.17.0.3
docker exec -it test-02 ping -c1 172.17.0.2
docker exec -it test-01 ping -c1 test-02
docker exec -it test-02 ping -c1 test-01
docker exec -it test-02 ping -c1 alias
docker rm -f $(docker ps -aq) &>/dev/null
输出结果:
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker run -itd --name test-01 centos
4247daa141b89b4e8956745696f942ba6b25d381f9ad0d2231d96f8c9a8ef055
[root@MineGi ~]# docker run -itd --name test-02 --link test-01:alias centos
0864be24ba98a79de2a305bc301a189bb04641b7523804f6ce8eeda1565a0de1
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 fe80::acd0:36ff:feab:12ec%veth9726747 fe80::b087:cbff:fe98:1373%vethf78f121 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0864be24ba98 centos "/bin/bash" 8 seconds ago Up 7 seconds test-02
4247daa141b8 centos "/bin/bash" 13 seconds ago Up 12 seconds test-01
[root@MineGi ~]# docker exec -it test-01 hostname -i
172.17.0.2
[root@MineGi ~]# docker exec -it test-01 tail -2 /etc/hosts
ff02::2 ip6-allrouters
172.17.0.2 4247daa141b8
[root@MineGi ~]# docker exec -it test-02 hostname -i
172.17.0.3
[root@MineGi ~]# docker exec -it test-02 tail -2 /etc/hosts
172.17.0.2 alias 4247daa141b8 test-01
172.17.0.3 0864be24ba98
[root@MineGi ~]# docker exec -it test-01 ping -c1 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.126 ms
--- 172.17.0.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.126/0.126/0.126/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.108 ms
--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.108/0.108/0.108/0.000 ms
[root@MineGi ~]# docker exec -it test-01 ping -c1 test-02
ping: test-02: Name or service not known
[root@MineGi ~]# docker exec -it test-02 ping -c1 test-01
PING alias (172.17.0.2) 56(84) bytes of data.
64 bytes from alias (172.17.0.2): icmp_seq=1 ttl=64 time=0.081 ms
--- alias ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.081/0.081/0.081/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 alias
PING alias (172.17.0.2) 56(84) bytes of data.
64 bytes from alias (172.17.0.2): icmp_seq=1 ttl=64 time=0.072 ms
--- alias ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.072/0.072/0.072/0.000 ms
[root@MineGi ~]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ~]#
3、自定义网络
- 创建自定义网络
- 可以使用docker network create命令创建自定义网络,如docker network create my-network。
- 连接容器到自定义网络
- 使用docker network connect命令将容器连接到自定义网络。例如,docker network connect my-network container1和docker network connect my-network container2。
- 通信方式
- 连接到同一自定义网络的容器之间可以通过容器名称进行通信,并且具有更好的网络隔离性和可管理性。例如,在上述创建的my- network中,container1可以直接通过名称访问container2。
命令示例:
hostname -i
docker network create -d bridge --subnet 172.25.0.0/16 demo_net
docker network ls |grep demo_net
docker network inspect demo_net |grep Subnet
docker run -itd --name test-01 --network=demo_net centos
docker run -itd --name test-02 --network=demo_net centos
hostname -i
docker ps -a
docker exec -it test-01 hostname -i
docker exec -it test-02 hostname -i
docker exec -it test-01 ping -c1 172.25.0.3
docker exec -it test-02 ping -c1 172.25.0.2
docker exec -it test-01 ping -c1 test-02
docker exec -it test-02 ping -c1 test-01
docker rm -f $(docker ps -aq) &>/dev/null
docker network rm demo_net
输出结果:
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 10.4.7.11 172.17.0.1
[root@MineGi ~]# docker network create -d bridge --subnet 172.25.0.0/16 demo_net
a31ac39d99da56ea2d1d292d001761b83e8b0a82d135cd38ec89200e0917da41
[root@MineGi ~]# docker network ls |grep demo_net
a31ac39d99da demo_net bridge local
[root@MineGi ~]# docker network inspect demo_net |grep Subnet
"Subnet": "172.25.0.0/16"
[root@MineGi ~]# docker run -itd --name test-01 --network=demo_net centos
73a6580925b2895f595258f88ecb4ac62b6b5e09c9ecc49ab5907125368163d7
[root@MineGi ~]# docker run -itd --name test-02 --network=demo_net centos
1d333ef3738f2b7a8f67a19dfc05225c2f32db6eaa36cb62a541381131dc2622
[root@MineGi ~]# hostname -i
fe80::ba86:d857:6fd6:ab2e%eth0 fe80::42:6dff:fefa:f3%docker0 fe80::42:4dff:fe1f:ca75%br-a31ac39d99da fe80::ec14:dcff:fef5:fb08%vethc34a79c fe80::10eb:b2ff:fe7c:3e7d%vethe3b950a 10.4.7.11 172.17.0.1 172.25.0.1
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d333ef3738f centos "/bin/bash" 14 seconds ago Up 13 seconds test-02
73a6580925b2 centos "/bin/bash" 19 seconds ago Up 18 seconds test-01
[root@MineGi ~]# docker exec -it test-01 hostname -i
172.25.0.2
[root@MineGi ~]# docker exec -it test-02 hostname -i
172.25.0.3
[root@MineGi ~]# docker exec -it test-01 ping -c1 172.25.0.3
PING 172.25.0.3 (172.25.0.3) 56(84) bytes of data.
64 bytes from 172.25.0.3: icmp_seq=1 ttl=64 time=0.087 ms
--- 172.25.0.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.087/0.087/0.087/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 172.25.0.2
PING 172.25.0.2 (172.25.0.2) 56(84) bytes of data.
64 bytes from 172.25.0.2: icmp_seq=1 ttl=64 time=0.080 ms
--- 172.25.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.080/0.080/0.080/0.000 ms
[root@MineGi ~]# docker exec -it test-01 ping -c1 test-02
PING test-02 (172.25.0.3) 56(84) bytes of data.
64 bytes from test-02.demo_net (172.25.0.3): icmp_seq=1 ttl=64 time=0.108 ms
--- test-02 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.108/0.108/0.108/0.000 ms
[root@MineGi ~]# docker exec -it test-02 ping -c1 test-01
PING test-01 (172.25.0.2) 56(84) bytes of data.
64 bytes from test-01.demo_net (172.25.0.2): icmp_seq=1 ttl=64 time=0.092 ms
--- test-01 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.092/0.092/0.092/0.000 ms
[root@MineGi ~]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ~]# docker network rm demo_net
demo_net
[root@MineGi ~]#
二、跨宿主机的通信
角色 | 操作系统 | IP地址 | Docker版本 |
服务端/客户端 | CentOS 7.8 | 10.4.7.11 | 26.1.4 |
客户端/客户端 | CentOS 7.8 | 10.4.7.12 | 26.1.4 |
1、基于 Overlay 网络(适用于 Docker Swarm)
1.1 步骤说明
(1)初始化 Swarm 集群
在一台宿主机(假设为宿主机 A)上执行以下命令来初始化 Swarm 集群:
docker swarm init
此命令会将该宿主机设置为 Swarm 的管理节点,并输出用于其他节点加入集群的命令。
(2)添加节点到 Swarm 集群
在其他宿主机(例如宿主机 B)上,使用在初始化时得到的令牌和 IP 地址,执行以下命令将其作为工作节点添加到 Swarm 集群:
docker swarm join --token <your_token> <manager_ip>:<port>
(3)创建 Overlay 网络
在 Swarm 管理节点(宿主机 A)上,创建一个 Overlay 网络:
docker network create -d overlay --attachable my-overlay-network
这里-d overlay指定网络类型为 Overlay,my-overlay-network是网络名称。
(4)部署容器到 Overlay 网络
在不同宿主机上的节点,将容器部署到创建好的 Overlay 网络中:
使用docker service create命令创建服务并加入网络,例如:
docker service create --name my-service --network my-overlay-network <image_name>
或者使用docker run命令(适用于单个容器):
docker run --name my-container --network my-overlay-network <image_name>
(5)容器间通信测试
容器部署完成后,不同宿主机上的容器可以通过在 Overlay 网络中分配的虚拟 IP 地址或者容器名称进行通信。
例如,可以在容器内使用ping或其他网络工具来测试通信。
1.2 实践操作
(1)宿主机A(10.4.7.11)操作
命令示例:
docker swarm init
docker network create -d overlay --attachable my-overlay-network
docker run -itd --name test-01 --network my-overlay-network alpine
docker exec -it test-01 hostname -i
输出结果:
[root@MineGi ~]# docker swarm init
Swarm initialized: current node (npxkc878d4kz8aa2v99tutigi) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-19ammhoxa4241y8u08g09jkz1k65t1wyuuzbu07woiumafdpvt-0c8pei0gysad7rm25lcbaz0d5 10.4.7.11:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
[root@MineGi ~]# docker network create -d overlay --attachable my-overlay-network
h9aiqa5uzun3iwhhyg3scv6ja
[root@MineGi ~]# docker run -itd --name test-01 --network my-overlay-network alpine
c87ba1c4f3099b6baf28e2d68a93ca5782f534aeba5763f94f01fba9e82bda95
[root@MineGi ~]# docker exec -it test-01 hostname -i
10.0.1.2
[root@MineGi ~]#
(2)宿主机B(10.4.7.12)操作
命令示例:
docker swarm join --token SWMTKN-1-19ammhoxa4241y8u08g09jkz1k65t1wyuuzbu07woiumafdpvt-0c8pei0gysad7rm25lcbaz0d5 10.4.7.11:2377
docker run -itd --name test-01 --network my-overlay-network alpine
docker exec -it test-01 hostname -i
输出结果:
[root@MineGi ~]# docker swarm join --token SWMTKN-1-19ammhoxa4241y8u08g09jkz1k65t1wyuuzbu07woiumafdpvt-0c8pei0gysad7rm25lcbaz0d5 10.4.7.11:2377
This node joined a swarm as a worker.
[root@MineGi ~]# docker run -itd --name test-01 --network my-overlay-network alpine
03659c74a25a1f47ceeccfddc11744c1288afcd29475f7c5a7520e09bd3f89e8
[root@MineGi ~]# docker exec -it test-01 hostname -i
10.0.1.4
[root@MineGi ~]#
1.3 验证互通
命令示例:
docker exec -it test-01 10.0.1.4
docker exec -it test-01 10.0.1.2
输出结果:
[root@MineGi ~]# docker exec -it test-01 hostname -i
10.0.1.2
[root@MineGi ~]# docker exec -it test-01 ping -c2 10.0.1.4
PING 10.0.1.4 (10.0.1.4): 56 data bytes
64 bytes from 10.0.1.4: seq=0 ttl=64 time=1.108 ms
64 bytes from 10.0.1.4: seq=1 ttl=64 time=0.838 ms
--- 10.0.1.4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.838/0.973/1.108 ms
[root@MineGi ~]#
[root@MineGi ~]# docker exec -it test-01 hostname -i
10.0.1.4
[root@MineGi ~]# docker exec -it test-01 ping -c2 10.0.1.2
PING 10.0.1.2 (10.0.1.2): 56 data bytes
64 bytes from 10.0.1.2: seq=0 ttl=64 time=1.324 ms
64 bytes from 10.0.1.2: seq=1 ttl=64 time=0.827 ms
--- 10.0.1.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.827/1.075/1.324 ms
[root@MineGi ~]#
2、使用静态路由和 iptables 规则实现跨宿主机容器通信
2.1 原理说明
使用静态路由和 iptables 规则实现跨宿主机容器通信的原理
- 静态路由原理:
- 静态路由是一种手动配置的路由方式。在跨宿主机容器通信的场景中,需要在每个宿主机上配置静态路由表,使得宿主机知道如何将数据包转发到其他宿主机上的容器。例如,如果宿主机 A 上的容器想要与宿主机 B 上的容器通信,宿主机 A 需要知道将数据包发送到宿主机 B 的下一跳地址(通常是连接两个宿主机的网络设备的接口地址)。
- iptables 规则原理:
- iptables 是 Linux 系统中的一个强大的防火墙工具,用于控制网络数据包的流入和流出。在这个场景中,iptables 可以用于设置网络地址转换(NAT)规则,使得容器的私有 IP 地址能够在不同宿主机之间进行通信。例如,可以将容器发出的数据包的源 IP 地址转换为宿主机的公网 IP 地址,以便在外部网络中传输,当数据包到达目标宿主机时,再将目标 IP 地址转换回目标容器的私有 IP 地址。
具体操作步骤
- 网络环境准备
- 假设存在两个宿主机(宿主机 A 和宿主机 B),每个宿主机都有一个公网 IP 地址(分别为 IP_A 和 IP_B),并且运行着 Docker 容器。容器的网络模式可以是自定义的网络或者默认的桥接网络,这里假设容器网络为172.17.0.0/16(这是 Docker 默认桥接网络的网段示例,具体根据实际情况而定)。
- 在宿主机上配置静态路由
- 宿主机 A:
- 假设宿主机 A 通过网络接口eth0连接到外部网络,要与宿主机 B 通信。如果宿主机 B 的公网 IP 地址是 IP_B,且通过网络接口eth1与宿主机 A 所在网络连接,那么在宿主机 A 上添加静态路由规则如下:route add -net 172.17.0.0/16 gw
- 例如,如果宿主机 B 的eth1接口的 IP 地址是192.168.1.2,则命令为route add -net 172.17.0.0/16 gw 192.168.1.2。这条规则告诉宿主机 A,当有数据包要发送到172.17.0.0/16网段(即宿主机 B 上的容器网段)时,将数据包发送到192.168.1.2这个下一跳地址。
- 宿主机 B:
- 类似地,在宿主机 B 上添加静态路由规则,将数据包发送到宿主机 A 上容器网段的下一跳地址。假设宿主机 A 通过eth0接口连接到共同网络,IP 地址为192.168.1.1,则在宿主机 B 上添加的规则为:route add -net 172.17.0.0/16 gw 192.168.1.1在宿主机上配置 iptables 规则实现 NAT(以宿主机 A 为例,宿主机 B 同理)
- 宿主机 A:
- 设置源 NAT(SNAT):
- 当容器从宿主机 A 发出数据包时,需要将容器的源 IP 地址(私有 IP)转换为宿主机 A 的公网 IP 地址(IP_A),以便在外部网络中传输。使用 iptables 的 SNAT 规则如下:iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -o eth0 -j SNAT --to-source IP_A
- 这条规则表示对于从172.17.0.0/16网段(容器网段)发出,并且从eth0接口离开宿主机 A 的数据包,将其源 IP 地址转换为宿主机 A 的公网 IP 地址(IP_A)。
- 设置目的 NAT(DNAT):
- 当数据包从外部网络返回宿主机 A 时,需要将目标 IP 地址(宿主机 A 的公网 IP 地址)转换回容器的私有 IP 地址。假设容器的目标 IP 地址是172.17.0.2,使用 iptables 的 DNAT 规则如下:iptables -t nat -A PREROUTING -d IP_A -p tcp --dport -j DNAT --to-destination 172.17.0.2:
- 这里需要根据实际容器开放的端口号进行配置,例如,如果容器开放了 80 端口,并且目标是这个容器,那么对于到达宿主机 A 公网 IP 地址且目标端口为 80 的 TCP 数据包,将其目标 IP 地址和端口转换为容器的私有 IP 地址和对应的端口。
测试通信
- 在宿主机 A 上的容器尝试通过ping或其他网络工具访问宿主机 B 上的容器的 IP 地址,检查是否能够正常通信。如果配置正确,容器之间应该可以成功通信。
需要注意的是,这种方法相对复杂,并且在实际应用中可能需要根据具体的网络环境和安全要求进行更多的调整和优化。例如,需要考虑网络的动态变化、安全性(如防止 IP 欺骗等)等因素。
2.2 实践操作
(1)宿主机A(10.4.7.11)操作
命令示例:
docker network create -d bridge --subnet 18.18.0.0/16 mynetwork
route add -net 19.19.0.0/16 gw 10.4.7.12
docker run -itd --name test11 --network mynetwork alpine
docker exec -it test11 hostname -i
iptables -P FORWARD ACCEPT
输出结果:
[root@MineGi ~]# docker network create -d bridge --subnet 18.18.0.0/16 mynetwork
cecf143727c181f98c0d261c5650e386c423fbecea8385d110aab8ca70491f6a
[root@MineGi ~]# route add -net 19.19.0.0/16 gw 10.4.7.12
[root@MineGi ~]# docker run -itd --name test11 --network mynetwork alpine
8d79698e691c0504a4b49f1af4bf025ecc4319b0ca02709e440c4d2ac4ea92de
[root@MineGi ~]# docker exec -it test11 hostname -i
18.18.0.2
[root@MineGi ~]# iptables -P FORWARD ACCEPT
[root@MineGi ~]#
(2)宿主机B(10.4.7.12)操作
命令示例:
docker network create -d bridge --subnet 19.19.0.0/16 mynetwork
route add -net 18.18.0.0/16 gw 10.4.7.11
docker run -itd --name test12 --network mynetwork alpine
docker exec -it test12 hostname -i
iptables -P FORWARD ACCEPT
输出结果:
[root@MineGi ~]# docker network create -d bridge --subnet 19.19.0.0/16 mynetwork
d8e569a46239f7c6e8000c641813d2eabc7572c118d66f83f611a7c6b4867ba3
[root@MineGi ~]# route add -net 18.18.0.0/16 gw 10.4.7.11
[root@MineGi ~]# docker run -itd --name test12 --network mynetwork alpine
20b6adf7017d07c618bcb99242c7d172e8c435e1078a070fdbe0df785159a2fe
[root@MineGi ~]# docker exec -it test12 hostname -i
19.19.0.2
[root@MineGi ~]# iptables -P FORWARD ACCEPT
[root@MineGi ~]#
2.3 验证互通
命令示例:
docker exec -it test11 ping -c2 19.19.0.2
docker exec -it test12 ping -c2 18.18.0.2
输出结果:
[root@MineGi ~]# docker exec -it test11 hostname -i
18.18.0.2
[root@MineGi ~]# docker exec -it test11 ping -c2 19.19.0.2
PING 19.19.0.2 (19.19.0.2): 56 data bytes
64 bytes from 19.19.0.2: seq=0 ttl=62 time=1.313 ms
64 bytes from 19.19.0.2: seq=1 ttl=62 time=2.087 ms
--- 19.19.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.313/1.700/2.087 ms
[root@MineGi ~]#
[root@MineGi ~]# docker exec -it test12 hostname -i
19.19.0.2
[root@MineGi ~]# docker exec -it test12 ping -c2 18.18.0.2
PING 18.18.0.2 (18.18.0.2): 56 data bytes
64 bytes from 18.18.0.2: seq=0 ttl=62 time=0.761 ms
64 bytes from 18.18.0.2: seq=1 ttl=62 time=0.702 ms
--- 18.18.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.702/0.731/0.761 ms
[root@MineGi ~]#
iptables -P FORWARD ACCEPT这条命令的作用如下:
1.命令解释
iptables是 Linux 系统中用于配置防火墙规则的命令行工具。
- -P(Policy 的缩写)用于设置链的默认策略。
- FORWARD是iptables中的一个链(chain)。在 Linux 防火墙中,有三个主要的链:INPUT(处理进入本机的数据包)、OUTPUT(处理从本机发出的数据包)和FORWARD(处理经过本机转发的数据包)。
- ACCEPT表示接受。将FORWARD链的默认策略设置为ACCEPT,意味着如果一个数据包没有匹配到FORWARD链中的任何规则,那么它将被允许通过。
2. 应用场景
- 容器网络:在处理 Docker 容器跨主机通信时,经常需要配置iptables规则来允许容器之间的网络流量通过。将FORWARD链默认策略设置为ACCEPT,可以简化容器网络的配置,使得容器间的网络流量能够更容易地通过宿主机进行转发。
- 路由器或网关配置:如果你的 Linux 系统充当路由器或网关角色,设置FORWARD链为ACCEPT可以确保在没有其他特定规则限制的情况下,数据包能够顺利地在不同网络接口之间转发。
3. 注意事项
- 安全风险:将FORWARD链默认策略设置为ACCEPT可能带来安全风险。因为这意味着任何经过本机转发的数据包,如果没有被其他规则明确拒绝,都将被允许通过。在生产环境中,通常建议更精细地配置iptables规则,根据实际需求明确地允许或拒绝特定类型的网络流量,而不是简单地将FORWARD链设置为ACCEPT。
- 规则冲突:这种设置可能会与其他现有的iptables规则产生冲突。例如,如果你之前已经有了一些基于源 IP、目标 IP、端口等条件来过滤转发数据包的规则,设置FORWARD链为ACCEPT可能会绕过这些规则,导致意外的网络行为。因此,在执行这条命令之前,需要充分考虑整个网络安全策略和现有的iptables配置。