Post content
# 手动实现 bridge 网络和 calico 网络 本质上要解决的问题是连通 host 和 netns, 来体会一下两者的不同思路. ## Bridge 用变量方便大家阅读, 否则区分不出语法和变量 NS=dock-ns3 VETH=vd3 BRIDGE=dock3 先创建 network namespace, 以下简称 netns ip netns add $NS 创建 veth pair: ip l add $VETH type veth peer name $VETH-peer veth 拉起来, 一端塞到 netns 里, 在 netns 里拉起来, 设置 ip ip l set $VETH-peer up ip l set $VETH netns $NS ip netns exec $NS ip l set $VETH up ip netns exec $NS ip a add 10.5.0.2/16 dev $VETH 创建 bridge, 拉起来 ip l add name $BRIDGE type bridge ip l set $BRIDGE up 把 veth 另一端加入 bridge ip l set $VETH-peer master $BRIDGE 最后把 bridge 也设置上 ip: ip a add 10.5.0.1/16 dev $BRIDGE 宿主机上的路由也会自动加上: # ip r | grep dock3 10.5.0.0/16 dev dock3 proto kernel scope link src 10.5.0.1 这时候就可以在宿主机 ping netns 里的 ip 了. 如果按照上面的流程再创建另一个 netns 和 veth pair 并加入 bridge, 那么两个 netns 已经可以互 ping 了. 不过还有问题, netns 里 ping 不了外面的世界, 这是因为 netns 里的路由没有默认 gateway: ip netns exec $NS ip r add default via 10.5.0.1 不过依然不可以, 这是因为没有 SNAT iptables -t nat -A POSTROUTING -s 10.5.0.0/16 -j MASQUERADE 完工. 这里的几个细节几乎和大家熟悉的 docker0 if 一模一样, 我枚举一下: 1. docker0 bridge 等价于 dock3 bridge 2. netns 里的 route 设置一模一样, default gw 指向 bridge, 相同网络的指向 veth 3. iptables nat 表 POSTROUTING chain 里把所在网络全部 SNAT ## Calico calico 的做法完全没有 bridge 这种妖艳贱货, 而是 veth 直通, 路由指路. 先设置变量: NS=cali VETH=v-cali 创建 netns 和 veth, veth 一端塞进去, 射 ip: ip netns add $NS ip l add $VETH type veth peer name $VETH-peer ip l set $VETH-peer up ip l set $VETH netns $NS ip netns exec $NS ip l set $VETH up ip netns exec $NS ip a add 10.2.0.1/32 dev $VETH 然后在宿主机直接路由 ip 到 veth: ip r add 10.2.0.1/32 dev $VETH-peer netns 里设置 default gw 到 veth: ip netns exec $NS ip r add default dev $VETH 这时候可以从 host ping netns, 但是反过来就不可达, 抓包发现是因为 arp 不知道 mac 地址, 加上 arp proxy echo 1 > /proc/sys/net/ipv4/conf/$VETH-peer/proxy_arp sysctl -p 发现还是不行, 抓包发现 arp 没问题了但是 ICMP 没有回复, 这是因为 SNAT: iptables -t nat -A POSTROUTING -s 10.6.0.1/32 -j MASQUERADE 这下可以和 host 互 ping 了, google.com 也没问题了, 功能上没问题. 不过有个优化的问题, arp proxy 会有一些问题, 比如这里会导致 netns 里的 arp cache 无限扩张, 所有的 outbound ip 都会产生一条 arp entry. 为了解决这个问题, 我们用一个假的 ip 169.254.1.1 作为 link-local address, 绕一下: ip netns exec $NS ip r del default dev $VETH ip netns exec $NS ip r add 169.254.1.1 dev $VETH scope link ip netns exec $NS ip r add default via 169.254.1.1 dev $VETH 这下所有的 outbound 都会变成对 169.254.1.1 arp, 也不会产生无数的 entry. 和 calico 比较一下, 要点有这么几个: 1. arp proxy 代替了 bridge 打通二层 2. 169.254.1.1 这个 ip 也是 calico 使用的 ip, 在 calico 创建的 netns 路由里这个迷一样的 ip 让无数人神魂颠倒 当然剩下的事情我就不说了, bird 监听到宿主机的新路由后用 BGP 广播 Update 消息, 从而在完成跨宿主机的路由建立. from https://gist.github.com/jschwinger23/a5cd21a5adf0ac0079e17fcc1179b37a#file-netns-integration-md