前言
docker0是Docker默認網絡的核心組件, 通過虛擬網橋和NAT技術, 實現了容器間的通信以及容器與外部網絡的交互。然而, docker0網段是固定的(通常是172.17.0.0/16), 為了更靈活地管理容器網絡,Docker支持創建自定義網橋,允許用戶指定網段。
例如, 在我以前做的一個單板仿真項目里, 每個容器用來模擬一塊板, 單板的IP需要設置為172.16.0.0/16, 和docker0網段不一致。 由于這個項目部署在每個開發的工作機上, 我們決定不直接修改docker0配置, 選擇了創建自定義網橋這種更靈活的方式。
Docker網橋的工作機制
Docker在主機上創建一個虛擬網橋(docker0), 每當啟動一個容器,Docker會自動創建一對虛擬網卡(veth pair), 其中一端放在容器內部作為它的網絡接口, 另一端則連接到主機上的這個虛擬網橋。 通過這種方式,容器之間可以通過網橋直接通信,數據包在網橋內轉發,不經過主機的物理網絡接口。
如果容器訪問的是外部網絡, 容器發出的數據包會先通過網橋到達主機, 然后主機通過NAT將容器的私有IP替換為自己的公網IP,從而讓數據包能夠順利發送到外部網絡。
示例: 創建自定義網橋
創建自定義網橋br0, 網段為172.16.0.0/16, 創建一組容器連到網橋br0, 各容器通過eth1(172.16.0.0/16)可以互聯
創建自定義網橋br0
創建一個新的網橋br0, 為其分配子網172.16.0.254/24
sudo ip link add name br0 type bridge
sudo ip link set dev br0 up
sudo ip addr add 172.16.0.254/16 dev br0
啟動兩個容器并連接到docker0
啟動2個容器, 默認連接到docker0網橋
docker run -it -d --name container1 rockylinux:9.3 bash
docker run -it -d --name container2 rockylinux:9.3 bash
將容器的 eth1 連接到自定義網橋 br0
# 添加veth pair
ip link add veth1_a type veth peer name veth1_b
ip link set veth1_a master br0
ip link set veth1_a up# 把veth1_b移到容器的namespace
pid_container1=$(docker inspect -f '{{.State.Pid}}' container1)
ip link set veth1_b netns $pid_container1# veth1_b重命名為eth1
nsenter -t $pid_container1 -n ip link set veth1_b name eth1
nsenter -t $pid_container1 -n ip link set eth1 up# 為eth1分配地址
nsenter -t $pid_container1 -n ip addr add 172.16.1.1/16 dev eth1
另一個容器做類似操作
# 添加veth pair
ip link add veth2_a type veth peer name veth2_b
ip link set veth2_a master br0
ip link set veth2_a uppid_container2=$(docker inspect -f '{{.State.Pid}}' container2)
ip link set veth2_b netns $pid_container2nsenter -t $pid_container2 -n ip link set veth2_b name eth1
nsenter -t $pid_container2 -n ip link set eth1 upnsenter -t $pid_container2 -n ip addr add 172.16.1.2/16 dev eth1
效果:
容器A
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)RX packets 127 bytes 188687 (184.2 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 121 bytes 9040 (8.8 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.16.1.1 netmask 255.255.0.0 broadcast 0.0.0.0inet6 fe80::4a5:69ff:feb8:acc0 prefixlen 64 scopeid 0x20<link>ether 06:a5:69:b8:ac:c0 txqueuelen 1000 (Ethernet)RX packets 125 bytes 10982 (10.7 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 106 bytes 9476 (9.2 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0inet6 ::1 prefixlen 128 scopeid 0x10<host>loop txqueuelen 1000 (Local Loopback)RX packets 32 bytes 2688 (2.6 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 32 bytes 2688 (2.6 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default _gateway 0.0.0.0 UG 0 0 0 eth0
172.16.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth1
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0# ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
64 bytes from 172.16.1.2: icmp_seq=1 ttl=64 time=0.471 ms
容器B
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)RX packets 27 bytes 2006 (1.9 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 9 bytes 626 (626.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 172.16.1.2 netmask 255.255.0.0 broadcast 0.0.0.0inet6 fe80::10b0:1aff:fe2f:766d prefixlen 64 scopeid 0x20<link>ether 12:b0:1a:2f:76:6d txqueuelen 1000 (Ethernet)RX packets 119 bytes 10386 (10.1 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 105 bytes 9406 (9.1 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0inet6 ::1 prefixlen 128 scopeid 0x10<host>loop txqueuelen 1000 (Local Loopback)RX packets 0 bytes 0 (0.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# ping 172.16.1.1
PING 172.16.1.1 (172.16.1.1) 56(84) bytes of data.
64 bytes from 172.16.1.1: icmp_seq=1 ttl=64 time=0.091 ms
參考
淺析docker容器網橋的實現原理以及docker的四種網絡模式和bridge模式的具體原理