linux Namespaces 提供了进程的资源隔离机制。在 Namespaces 机制下,运行的进程感觉使用的系统资源是独享的。docker 的实现也充分利用了这一机制。Linux 提供了6种 Namespaces, 包括 Mount, PID, UTS, IPC, User, Network。本文主要介绍 Network Namespaces 。
Network Namespaces 命令行配置
可以用 ip 工具来设置 network namespaces。 增加一个网络命名空间
1 2 3 |
ip netns add netns1 // 列出当前的命令空间 ip netns ls |
ip netns exec 可以在指定的命令空间下运行命令
1 2 3 4 5 |
sudo ip netns exec netns1 ip link list 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 sudo ip netns exec netns1 ping 127.0.0.1 connect: 网络不可达 |
我们看到当前 loop 设备是 DOWN 的状态,而且本地是不通的。
1 2 3 4 5 |
~ sudo ip netns exec netns1 ip link set dev lo up ~ sudo ip netns exec netns1 ping 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.042 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.052 ms |
但是现在还不能与 root namespaces 进行通讯。需要通过 veth 虚拟的网络设备,进行连接起来。veth 设置类似于管道,数据从一头流入另一头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
~ sudo ip link add veth0 type veth peer name veth1 ~ sudo ip link set veth1 netns netns1 // 把 veth0, veth1 状态改为 UP, 并设置veth1 IP ~ sudo ip link set dev veth0 up ~ sudo ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up ~ sudo ip netns exec netns1 ip link list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 6: veth1@if7: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT qlen 1000 link/ether 2a:33:df:d9:23:72 brd ff:ff:ff:ff:ff:ff link-netnsid 0 ~ sudo ip netns exec netns1 netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 veth1 |
可以看到,在 netns1 下面,veth1 作为虚拟的网络设备是 UP 状态,到 10.1.1.0 的默认路由会走 veth1。
网桥 bridge 类似于网络交换机,任何的真实或者虚拟的网络设备都可以与它连接。工具 brctl 来操作网桥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// 创建网桥 br0 ~ sudo brctl addbr br0 // 把 veth0 加入到网桥中 ~ sudo brctl addif br0 veth0 ~ sudo brctl show br0 bridge name bridge id STP enabled interfaces br0 8000.9e55f5c8f1d6 no veth0 // 设置网桥 IP ~ sudo ifconfig br0 10.1.1.100/24 up ➜ ~ sudo ifconfig br0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 10.1.1.100 netmask 255.255.255.0 broadcast 10.1.1.255 ether 9e:55:f5:c8:f1:d6 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 // veth1 与 br0 网络是通的 ~ sudo ip netns exec netns1 ping 10.1.1.100 PING 10.1.1.100 (10.1.1.100) 56(84) bytes of data. 64 bytes from 10.1.1.100: icmp_seq=1 ttl=64 time=0.053 ms 64 bytes from 10.1.1.100: icmp_seq=2 ttl=64 time=0.070 ms // 假设 host IP 为 172.16.185.133, 此时网络还是不通。 ~ sudo ip netns exec netns1 ping 172.16.185.133 connect: 网络不可达 // 设置默认路由,路由地址为 br0 IP ~ sudo ip netns exec netns1 ip route add default via 10.1.1.100 ➜ ~ sudo ip netns exec netns1 netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 10.1.1.100 0.0.0.0 UG 0 0 0 veth1 10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 veth1 ➜ ~ sudo ip netns exec netns1 ping 172.16.185.133 PING 172.16.185.133 (172.16.185.133) 56(84) bytes of data. 64 bytes from 172.16.185.133: icmp_seq=1 ttl=64 time=0.041 ms 64 bytes from 172.16.185.133: icmp_seq=2 ttl=64 time=0.056 ms |
此时在 netns1 中还无法 ping 通外网,先增加 dns server 试试。
1 2 3 4 5 6 7 |
~ sudo ip netns exec netns1 ping www.baidu.com ping: www.baidu.com: 未知的名称或服务 ~ sudo mkdir -p /etc/netns/netns1 # echo "nameserver 8.8.8.8" > /etc/netns/netns1/resolv.conf // 这里我们加上 nameserver, 发现网络还是不通 ~ sudo ip netns exec netns1 ping www.baidu.com ping: www.baidu.com: 未知的名称或服务 |
在 netns1 中 ping 外网,原始地址是 10.1.1.0 的网段,需要进行 NAT 转换,以宿主机的地址作为源地址访问外网。
1 2 3 4 5 6 7 8 9 |
~ sudo iptables -t nat -A POSTROUTING -s 10.1.1.1/24 -j MASQUERADE // ens33 是 host 上的设备名称,一般情况下是 eth0。 通过 ifconfig 来确定当前主机的名称 // 在 iptables filter 规则中,FROWARD 默认是 DROP, 这里保证网桥和主机设备是通的 ~ sudo iptables -A FORWARD -i ens33 -o br0 -j ACCEPT ~ sudo iptables -A FORWARD -o ens33 -i br0 -j ACCEPT // 再次测试,网络是通的 ~ sudo ip netns exec netns1 ping www.baidu.com PING www.wshifen.com (104.193.88.123) 56(84) bytes of data. 64 bytes from 104.193.88.123 (104.193.88.123): icmp_seq=1 ttl=127 time=180 ms |
以上过程,也是 docker 网络配置的基础。