机器环境

两台虚拟机器
node60 eth1 ip 10.5.7.60
node61 eth1 ip 10.5.7.61

vxlan 模式配置:

  • nolearning

模拟 flannel 集群网段: 10.239.0.0/16, 每个节点分配一个网段 10.239.x.0/24

node60 容器网络 10.239.1.0/16 vxlan flannel0 地址: 10.239.1.0/32 网桥cni0地址: 10.239.1.1/24
node61 容器网络 10.239.2.0/16 vxlan flannel0 地址: 10.239.2.0/32 网桥cni0地址: 10.239.2.1/24

flanneld 当前master 改进

之前每机器arp表目随着容器增加而增加。当前改进的是,采用路由模式, 每个节点只保存其他所有节点flannel0 网卡mac项目,以及vxlan fdb项目。

配置步骤

创建 vxlan 网卡 flannel0

node60:

  1. $ ip link add flannel0 type vxlan id 42 dstport 4789 dev eth1 nolearning
  2. $ ip link list flannel0
  3. 5: flannel0: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  4. link/ether 12:81:6d:d9:6c:df brd ff:ff:ff:ff:ff:ff
  5. $ ip addr add 10.239.1.0/32 dev flannel0
  6. $ ip link set flannel0 up

node60:
- flannel mac 地址是: 12:81:6d:d9:6c:df ip 地址是: 10.239.1.0/32

node61:

  1. $ ip link add flannel0 type vxlan id 42 dstport 4789 dev eth1 nolearning
  2. $ ip link list flannel0
  3. 4: flannel0: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  4. link/ether ae:e7:b9:16:44:08 brd ff:ff:ff:ff:ff:ff
  5. $ ip addr add 10.239.2.0/32 dev flannel0
  6. $ ip link set flannel0 up

node61: flannel mac 地址是:ae:e7:b9:16:44:08, ip 地址是: 10.239.2.0/32

创建网桥cni0

node60

  1. $ip link add cni0 type bridge
  2. $ip link set cni0 up
  3. $ip addr add 10.239.1.1/24 dev cni0

node61

  1. $ip link add cni0 type bridge
  2. $ip link set cni0 up
  3. $ip addr add 10.239.2.1/24 dev cni0

路由配置

网络数据传输路线

  1. node60 container veth_p1 -> veth_p2 -> cni0 (ip route) -> flannel0 -> node61: flannel0 ip route -> cni0

node60
10.239.1.0/24 由cni0 去转发 (配置bridge ip 后自动加上)

$ ip route add 10.239.1.0/24 via 10.239.1.1 dev cni0

按照flannel 数据动态增加节点路由
例如 :node61 网段是 10.239.2.0/24, 发送到node61 fannel0 上,

$ ip route add 10.239.2.0/24 via 10.239.2.0 dev flannel0 onlink

flannel 动态增删节点路由通过watch etch 实现的
node60

$ ip route add 10.239.1.0/24 via 10.239.1.0 dev flannel0 onlink

ARP 和 FDB 表配置

为了防止ARP风暴, vxlan 没有配置group 组播, flannel增加路由节点后, 同时需要告诉flannel vxlan 下一跳 10.239.2.0 路由器ip mac, vxlan发送什么主机上,需要通过配置arp, fdb。 这样的好处是一个节点一个arp, 一个fdb。arp和fdb表项目只会随主机增加而增加,不会随容器增加而增加。

node60 上配置

$ ip neigh add 10.239.2.0 lladdr ae:e7:b9:16:44:08 dev flannel0
$ bridge fdb append ae:e7:b9:16:44:08 dev flannel0 dst 10.5.7.61

node61 上配置

$ ip neigh add 10.239.2.0 lladdr ae:e7:b9:16:44:08 dev flannel0
$  bridge fdb append ae:e7:b9:16:44:08 dev flannel0 dst 10.5.7.60

创建容器网络

以 node60 为例子,创建容器网络过程。创建网络命名空间, 以及一对veth pair, 把 veth pair 一端放到容器网络空间上, 另外一端接到bridge0 上。 容器网络接口配置ip 地址为10.239.1.2

创建container1网络

  • 创建 container1 命名空间

    $ ip netns add container1
    
  • 创建容器网卡

创建veth对veth0-veth1, 把一端 veth1 移动到container1空间上。

# 创建 veth 对
$ ip link add veth0 type veth peer name veth1

# veth0 接到网桥 bridge0 上
$ ip link set dev veth0 master bridge0

# veth1 移动命名空间 container1
$ ip link set dev veth1 netns container1

# 启动 lo 接口, 否则ping 127.0.0.1 / 自己 ip 地址不通
$ ip netns exec container1 ip link set lo up

# 修改接口名字为 eth0
$ ip netns exec container1 ip link set veth1 name eth0

# 配置 eth0 地址 
$ ip netns exec container1 ip addr add 10.239.1.2/24 dev eth0

# 启动 eth0
$ ip netns exec container1 ip link set eth0 up
  • node62 进行同样的配置

在容器配置默认路由为 bridge0

$ ip netns exec container1 ip route add default via 10.239.1.1 dev eth0
$ echo "1" > /proc/sys/net/ipv4/ip_forward

测试

ip netns exec container1 ping 10.239.2.1

如果ping通基本算是联通网络了。

容器允许访问主机外网络

测试发现容器里面不能 ping 通主机外网络, 例如 10.5.7.61。 容器出去以后,还是10.239 网络, 其他机器返回包不能收到,所有需要在iptable net 给容器网络段 10.239.0.0/16 出外网的时候做地址伪装, 主要分段

node61

# flannel 10.239.0.0/16 网段内部通信不做snat伪装
$ iptables -t nat -A POSTROUTING -s 10.239.0.0/16 -d 10.239.0.0/16 -j RETURN
# flannel 10.239.0.0/16 网段出去外网,而且外网地址非组播地址,把flannel地址换主机地址
$ iptables -t nat -A POSTROUTING -s 10.239.0.0/16 ! -d 224.0.0.0/4 -j MASQUERADE
# 其他机器调转本主机flannel网段请求不用做地址伪装
$ iptables -t nat -A POSTROUTING ! -s 10.239.0.0/16 -d 10.239.1.0/24 -j RETURN
# 其他机器调转本进入flannel网段,但是不是本主机的网段,需要地址伪装(转发其他flannel节点,返回本几点,再转发回去)
$ iptables -t nat -A POSTROUTING ! -s 10.239.0.0/16 -d 10.239.0.0/16 -j MASQUERADE

node62

# flannel 10.239.0.0/16 网段内部通信不做snat伪装
$ iptables -t nat -A POSTROUTING -s 10.239.0.0/16 -d 10.239.0.0/16 -j RETURN
# flannel 10.239.0.0/16 网段出去外网,而且外网地址非组播地址,把flannel地址换主机地址
$ iptables -t nat -A POSTROUTING -s 10.239.0.0/16 ! -d 224.0.0.0/4 -j MASQUERADE
# 其他机器调转本主机flannel网段请求不用做地址伪装
$ iptables -t nat -A POSTROUTING ! -s 10.239.0.0/16 -d 10.239.2.0/24 -j RETURN
# 其他机器调转本进入flannel网段,但是不是本主机的网段,需要地址伪装(转发其他flannel节点,返回本几点,再转发回去)
$ iptables -t nat -A POSTROUTING ! -s 10.239.0.0/16 -d 10.239.0.0/16 -j MASQUERADE

容器网络出去以后,地址就会替换为主机ip地址,容器网络就可以访问外网了

ip netns exec container1 ping 123.58.180.7
PING 123.58.180.7 (123.58.180.7) 56(84) bytes of data.
64 bytes from 123.58.180.7: icmp_seq=1 ttl=61 time=27.6 ms
64 bytes from 123.58.180.7: icmp_seq=2 ttl=61 time=27.5 ms
64 bytes from 123.58.180.7: icmp_seq=3 ttl=61 time=27.2 ms
64 bytes from 123.58.180.7: icmp_seq=4 ttl=61 time=27.2 ms