行至水穷处

坐看云起时

DOCKER容器跨宿主机通信方法(4):Flannel-UDP

Flannel简介

Flannel是一个开源的用于管理和组织跨主机间容器网络的一套工具,其原理是通过在所有宿主机上建立一个flannel0网卡,将所有宿主机设置为同一个大的网段,并改写每个docker0的桥IP(通过改写docker daemon启动命令)为其一个子网IP,从而实现,整体网络在一个大的网段,各个docker0分配不同的子网网段。各个docker0网络内的容器数据包最终通过flanneld进程来将数据包进行封装,通过UDP包外层封装(缺省),或者vxlan隧道,实现跨主机容器通信(主机底层物理网络只要路由可达就行),另外flannel还支持host-gw,aws,gec等网络,本实验使用缺省udp封装。

安装前提条件

系统先需正确安装etcd服务,本实验已安装好etcd三节点集群
系统先需正确安装docker服务

Flannel安装

可以到https://github.com/coreos/flannel/releases下载最新编译后版本,或者使用操作系统工具直接按照,下载编译后的版本只需将flanneld以及mk-docker-opts.sh拷贝到系统path的某个目录下,但需要手工创建相关配置文件,较为麻烦,本实验使用centos系统,故直接使用yum安装

Fannel配置

安装完毕后,编辑/etc/sysconfig/flanneld  文件,设置 FLANNEL_ETCD_PREFIX如下,设置FLANNEL_OPTIONS,是为了指定让flannel通过哪个物理接口封装数据包。注意etc endpoints设置,由于本环境中etcd集群在每个节点上都有,因此使用了本地127.0.0.1地址,否则应修改为正确的etcd服务url

在启动flannel之前,在etcd中设置flannel希望使用的大网络:

启动flannel:

查看more /run/flannel/docker 文件是否被自动生成,类似:

修改docker.service启动配置文件,增加After=flanneld.service以及EnvironmentFile=/run/flannel/docker,修改dockerd启动配置行为:ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS

完成上述工作后,重启docker服务:
systemctl daemon-reload
systemctl restart docker

检查确认docker0以及flannel0网络输出,应看到docker0之前配置config时候的一个子网地址,类似如下输出:

设置flanneld服务开机自动启动:
[root@docker3 ~]# systemctl enable flanneld.service

上述配置安装工作应在所有节点上都完成,但是etcdctl设置 config步骤无需重复

容器互联测试

网络数据path分析

  • 当在宿主机2上ping宿主机3内容器IP时候,容器本身根据自身路由将数据包发送到缺省网关即docker0上:

docker0上抓包可以看到如下包,注意此时Dst MAC是docker0的MAC:

  • docker0发现目的IP不是本网段,系统查找路由表,发现去往10.1.0.0/16网络的需要经过flannel0设备,于是将数据包发送给flannel0:

flannel0抓包可以发现,flannel将数据包的以太网包头剔除,并将源IP修改为其自己的IP地址10.1.37.0

  • flanneld进程捕捉到该包,在etcd中查找10.1.33.2属于哪个网络,且查找获得该子网所对应的宿主机IP地址,执行相应的包封装操作

在物理接口上抓包可以看到, flanneld将flannel0上看到的包作为UDP payload,UDP包头使用8285端口,三层再封装宿主机IP,并通过宿主机自身以太网地址封装源和目的mac

flannel-udp抓包文件下载

数据path图:

附,官方github上的图:

附2:
在刚配置完flannel后发现无法ping通外部容器,排错发现数据包到目的主机的flannel0后没有被发送到docker0上,主要是由于forward chain中ACTION为 DOCKER的规则阻断了数据包进入docker0,ping不通时候的的iptable类似如下:

可以看到上述规则中FORWARD中的规则:

该规则将数据包交给DOCKER chain处理,而docker chain没有放行,就是说,缺省情况下docker service是不容许docker0外部数据经过docker0进入docker内部,所以在docker chain中增加规则:

但是重启后,由于docker服务自身会刷新该规则,会导致增加的丢失, 所以直接增加到FORWARD chain中

 

检查输出:

随后可以ping通

如果想暴力的放行数据,可以执行:

iptable里的规则在容器网络功能里来说是比较重要的,有些规则是为了隔离网络实现安全,如果简单的全部删除docker自身添加的规则有可能会导致问题,需要仔细处理。

附3:将firewalld服务改为iptables service服务:
systemctl stop firewalld
systemctl disable firewalld

yum install iptable-services

强制在机器启动时候在forward 链中增加一条全转发规则:

  1. 写一个脚本
  2. 在systemd中增加一个service并开机启动


     
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注