一、Docker网络模型与跨主机的容器间通信原理与过程展示和分析
docker网络-host模式
优点:
- 每个容器没有独立的net namespace,而是直接使用宿主机网卡通信
- 服务器的端口只能被一个容器监听,其它容器再监听会出现端口冲突
- 网络吞吐性能强(不需要iptables做目标地址和源地址转换)
- 适用于在多台主机联合部署集群服务(redis cluster、elasticsearch cluster等)
缺点:
- 单台主机运行较多容器的时候端口分配不好记录
- 单台主机运行相同服务的时候端口的冲突问题
docker网络-bridge模式(网桥)
安装docker后 默认会创建 docker0 的网桥
优点
- 基于net namespace为每个容器实现独立的网络空间(每一个容器一个独立的IP)
- 同一个服务器的不同容器不会出现容器中的服务监听地址冲突
- 同一个服务器的不同容器不会出现容器中的服务监听端口冲突
- 适用于在单台主机运行多容器的场景(Harbor、LNMP以及基于docker-compsoe部署的由多容器组成的单机项目)
缺点
- 需要维护每个服务的通信端口
- 高并发的场景会有单节点瓶颈
- 横向扩容需要在每台节点部署相同的服务
- 进出宿主机的报文通过iptables进行转发,高并发的项目会有瓶颈 经验值: k8s相对 单机docker compose 网络损耗打8折
实验-创建测试容器
# 创建A
docker run -it -d -p 80:80 nginx:1.20.2-alpine
# 创建B
docker run -it -d -p 8080:8080 tomcat:7.0.93-alpine
iptables -vnL 可以看到添加了2个容器的IP的放行
多了2个veth设备
可以看到网桥上 多了2个接口
可以看到 会有两条DNAT的转换
containerA --> containerB 的网络走向(同一个宿主机)
- step1 containerA 向对端发起网络请求 到vethA
- step2 hostA 的docker0网桥
- step3 containerB的 vethB
containerA --> containerB 的网络走向(跨宿主机)?
containerA 向对端发起网络请求(请求对端的DNAT_PORT)
-
step1 containerA 的vethA
-
step2 hostA 的docker0网桥
-
step3 hostA 的物理网卡
-
step4 hostB 的物理网卡
-
step5 hostB 的docker0网桥
-
step6 containerB 的vethB
抓包方法
tcpdump -nn -vvv -i vethbd9b771 -vvv -nn ! port 22 and ! arp and ! port 53
同宿主机总结:
- 1、同宿主机的容器通信,在docker0实现报文转发,不需要经过宿主机的eth0。
跨宿主机通信
- 1、源容器产生请求报文发给网关docker0
- 2、docker0检查报文的目的IP,如何是本机就直接转发,如果不是本机就转发给宿主机。
- 3、目的宿主机收到报文后检查路由表,将源地址替换为本机IP并发送报文。
- 4、目的主机收到请求报文,检查目的IP后将报文转发给docker0。
- 5、docker0检查目的IP后匹配MAC地址表,将报文发送给目的MAC的容器。
创建测试容器
修改docker的默认IP地址范围
修改docker的默认IP地址范围:
root@docker-server1:~# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.0.1/24
root@docker-server1:~# systemctl daemon-reload && systemctl restart docker
root@docker-server2:~# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.20.0.1/24
root@docker-server2:~# systemctl daemon-reload && systemctl restart docker
注意 net.ipv4.ip_forward = 0 可能会导致网络转发有问题
容器的跨主机通信
在宿主机添加静态路由,将去往的目的容器网关(下一跳)指向目的容器所在的宿主机eth0网卡:
## 宿主机 172.31.6.202
root@docker-server1:~# route add -net 10.20.0.0/24 gw 172.31.6.202(宿主机的网卡地址) #去往10.20.0.0/24的下一跳是172.31.6.202
root@docker-server1:~# iptables -A FORWARD -s 172.31.0.0/21 -j ACCEPT #允许响应报文的转发
## 宿主机 172.31.6.201
root@docker-server2:~# route add -net 10.10.0.0/24 gw 172.31.6.201(宿主机的网卡地址)
root@docker-server2:~# iptables -A FORWARD -s 172.31.0.0/21 -j ACCEPT
创建自定义网络 创建新的网桥设备(默认安装时创建的是docker0)
root@docker-server2:~# docker network create -d bridge --subnet 10.200.0.0/24 --gateway 10.200.0.1 magedu-net
root@docker-server2:~# docker run -it -p 8080:8080 --name magedu-net-test --net=magedu-net alpine:3.16.2 sh