安装工具:
apt install bridge-utils net-tools
容器与宿主机的通信
创建一个新的网络命名空间,这里模拟容器内部的网络
$ ip netns add net1 # net1为该网络空间(容器内部网络空间)的名称
查看命名空间的iptable, 路由表,设备
$ ip netns exec net1 route # 查看容器内部路由表
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
$ ip netns exec net1 iptables -L # 查看容器内部iptable
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
$ ip netns exec net1 ip link list # 查看容器内部设备
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 目前只有本地回环设备, 并且状态为DOWN(未启动)
创建一对veth,并将veth的一头添加到net1中
Veth Pair 设备的特点是:它被创建出来后,总是以两张虚拟网卡(Veth Peer)的形式成对出现的。并且,从其中一个“网卡”发出的数据包,可以直接出现在与它对应的另一张“网卡”上,哪怕这两个“网卡”在不同的 Network Namespace 里。这就使得 Veth Pair 常常被用作连接不同 Network Namespace 的“网线”。
$ ip link add veth1 type veth peer name veth1_p
$ ip link set veth1 netns net1 # veth1设备被移动到容器中
查看主机上当前设备,只能看到veth1_p这个设备了
$ ip link list | grep veth
1284: veth1_p@if1285: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
查看net1容器网络命名空间,veth1在这个空间里面
$ ip netns exec net1 ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
1285: veth1@if1284: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 8a:b3:bb:2a:3a:92 brd ff:ff:ff:ff:ff:ff link-netnsid 0
为这对veth配置ip,并启动起来
$ ip addr add 10.68.0.100/24 dev veth1_p # 配置容器中的veth设备ip
$ ip netns exec net1 ip addr add 10.68.0.101/24 dev veth1
$ ip netns exec net1 ip link set dev veth1 up # 启动net1中的设备
$ ip link set dev veth1_p up # 启动宿主机中的设备
分别查看当前启动的网络设备
$ ifconfig | grep veth1 # 宿主机
veth1_p: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
$ ip netns exec net1 ifconfig # 容器
veth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.101 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::88b3:bbff:fe2a:3a92 prefixlen 64 scopeid 0x20<link>
ether 8a:b3:bb:2a:3a:92 txqueuelen 1000 (Ethernet)
RX packets 57 bytes 7088 (6.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10 bytes 796 (796.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
测试通信
$ ip netns exec net1 ping 10.68.0.100 -I veth1 # 从容器内部ping宿主机
PING 10.68.0.100 (10.68.0.100) 来自 10.68.0.101 veth1 56(84) 字节的数据。
64 字节,来自 10.68.0.100: icmp_seq=1 ttl=64 时间=0.040 毫秒
64 字节,来自 10.68.0.100: icmp_seq=2 ttl=64 时间=0.096 毫秒
64 字节,来自 10.68.0.100: icmp_seq=3 ttl=64 时间=0.057 毫秒
64 字节,来自 10.68.0.100: icmp_seq=4 ttl=64 时间=0.070 毫秒
64 字节,来自 10.68.0.100: icmp_seq=5 ttl=64 时间=0.070 毫秒
64 字节,来自 10.68.0.100: icmp_seq=6 ttl=64 时间=0.070 毫秒
^C
--- 10.68.0.100 ping 统计 ---
已发送 6 个包, 已接收 6 个包, 0% packet loss, time 5077ms
rtt min/avg/max/mdev = 0.040/0.067/0.096/0.016 ms
宿主机与宿主机上容器成功
宿主机上多个容器的通信
创建网桥
网桥(Bridge)。是一个工作在数据链路层(Data Link)的设备,主要功能是根据 MAC 地址学习来将数据包转发到网桥的不同端口(Port)上。
$ brctl addbr mybridge
设置网桥ip
$ ip addr add 10.68.0.1/24 dev mybridge
启动网桥
$ ip link set dev mybridge up
查看网桥
$ ip addr show mybridge
35: mybridge: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 7e:06:1f:5a:53:f5 brd ff:ff:ff:ff:ff:ff
inet 10.68.0.1/24 scope global mybridge
valid_lft forever preferred_lft forever
将设备插入网桥
一旦一张虚拟网卡被“插”在网桥上,它就会变成该网桥的“从设备”。从设备会被“剥夺”调用网络协议栈处理数据包的资格,从而“降级”成为网桥上的一个端口。而这个端口唯一的作用,就是接收流入的数据包,然后把这些数据包的“生杀大权”(比如转发或者丢弃),全部交给对应的网桥。
$ ip link set veth1_p master mybridge
查看是否插入成功
$ brctl show
bridge name bridge id STP enabled interfaces
mybridge 8000.7e061f5a53f5 no veth1_p
从veth对的另一端ping网桥
$ ip netns exec net1 ping 10.68.0.1 -I veth1
PING 10.68.0.1 (10.68.0.1) 来自 10.68.0.101 veth1 56(84) 字节的数据。
64 字节,来自 10.68.0.1: icmp_seq=1 ttl=64 时间=0.051 毫秒
64 字节,来自 10.68.0.1: icmp_seq=2 ttl=64 时间=0.063 毫秒
64 字节,来自 10.68.0.1: icmp_seq=3 ttl=64 时间=0.094 毫秒
^C
--- 10.68.0.1 ping 统计 ---
已发送 3 个包, 已接收 3 个包, 0% packet loss, time 2036ms
rtt min/avg/max/mdev = 0.051/0.069/0.094/0.018 ms
查看net1空间中的路由规则
$ ip netns exec net1 ip route
10.68.0.0/24 dev veth1 proto kernel scope link src 10.68.0.101
设置一条默认路由:
$ ip netns exec net1 route add default gw 10.68.0.1 dev veth1
当这条默认路由被设置,所有的网络包默认被发往网桥。此时如果有另一个容器网络命名空间,例如net2,其veth设备一端插在网桥上,对应的另一端在net2中,就可以实现从net1到net2的通信。现在为止,已经可以实现在一台宿主机上的两个容器的相互通信。
容器与外部通信
$ brctl addif mybridge eth0
配置路由和转发
sysctl net.ipv4.ip_forward=1
现在,应该可以从net1中的veth1向外界发送消息:
$ ip netns exec net1 ping 8.8.8.8 -I veth1
PING 8.8.8.8 (8.8.8.8) from 10.68.0.101 veth1: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=2 ttl=62 time=39.5 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=62 time=40.5 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=62 time=39.3 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=62 time=49.9 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=62 time=40.3 ms
64 bytes from 8.8.8.8: icmp_seq=7 ttl=62 time=39.1 ms
64 bytes from 8.8.8.8: icmp_seq=8 ttl=62 time=39.1 ms
^C
--- 8.8.8.8 ping statistics ---
8 packets transmitted, 7 received, 12.5% packet loss, time 7015ms
rtt min/avg/max/mdev = 39.062/41.081/49.859/3.620 ms
现在已经可以实现容器与外部网络环境的相互通信,但是,如何实现不同宿主机上的容器之间互相通信呢?请看下篇。
Refercences
Build your own bridgeHow to Configure Network Bridge on Linux? - zenarmor.comhttps://zhuanlan.zhihu.com/p/65566171https://time.geekbang.org/column/article/64948