农行信创之容器云适配踩过的大坑 - 努力呀 - twt企业IT交流平台
作者:
农行研发中心 郑宇光 周思远
当前国内的信息技术的核心和标准大多数都由国外公司掌握和制定,因此存在诸多的安全风险。随着我国加快推进信息网络等新型基础设施建设、网络主权概念的逐步明确,信息技术应用创新产业已经成为当前信息化部署的关键词。我国正在大力推动政府、国防、金融、交通等关键领域的信息化产品尽快实现国产化替代,并发布了多个重要政策来保障国产化的实施,加速实现信息核心技术的自主可控。
中国农业银行作为国有银行,是中国金融体系重要的组成部分,也是信创国产化布局的关键领域,在 IT 建设方面发展十分迅速,其中引入云计算平台基础设施来承载新建应用系统已经作为行内的一条刚性原则。信创国产化云的建设也是当下的重要任务,在云计算平台软件与国芯物理服务器、国产操作系统的适配方面也遇到不少的问题与挑战,下面就这个话题举几个典型的案例和大家分享一下。
农行信创云是采用容器及容器调度为核心技术栈的 PaaS 平台。容器引擎 docker 、容器编排调度组件 kubernetes 和容器网络插件等整体运行于银河麒麟或者 CentOS8 操作系统之上。服务器方面采用基于海光 x86 和鲲鹏 arm 处理器的国产服务器。
案例 1基于国芯海光 x86 服务器安装 Centos8 操作系统,部署并运行 Kubernetes 网络插件 flannel 时出现跨服务器容器网络不通的现象。
现象:当我们完成基于海光服务器和 CentOS8 操作系统的 kubernetes 集群搭建时意外发现从集群外无法访问发布到集群的应用程序,使用同样的发布方式将应用程序发布到非国产化 kubernetes 集群上可以从集群外进行访问。环境信息如下:
操作系统: CentOS Linux 8
内核版本: 4.18.0-147.el8.x86_64
kubernetes 版本: 1.17.4
flannel 版本: 0.11.0 ( vxlan 模式)
分析:我们从集群外访问到应用程序的流量路径上逐步进行排查,最后发现跨服务器节点访问应用容器 IP 和服务端口不可达。集群采用 flannel 的 vxlan 模式提供容器网络服务, flannel 会在每个集群节点上分配一个私有子网来分配该节点的容器 IP ,当跨节点容器互访时,源容器的数据包会通过 vxlan 隧道封装技术进行封装后再通过节点 UDP4789 端口发送到目标节点,完成解封装后送至目标容器。使用 tcpdump 对 flannel 的 UDP4789 端口抓包发现,每个 UDP 数据包都会出现下图所示的 bad udp cksum 并且该数据包被丢弃。
措施:查阅网上相关技术资料发现这个现象是由服务器网卡 Checksum offloading 引起的。这项功能旨在如果内核想通过物理网卡向外发送数据包时可以让硬件网卡代替 CPU 来完成 checksum 计算,以节省 CPU 资源。如果网卡支持,可以设置对发送 Tx 或接收 Rx 有效,或者两者都有效。临时的解决方案是关闭 flannel 网络接口的 Tx checksum 功能,通过 sudo ethtool -K flannel.1 tx-checksum-ip-generic off 命令关闭。可以通过 sudo ethtool -k flannel.1 查询当前 checksum 是否有效,如下图所示,可以看到 tx-checksumming 状态是 off 。
当然这并没有根本解决问题,从 kubernetes 社区上反馈的情况来看是由于 kernel packet checksum 的 bug 以及 kubernetes 的 kube-proxy 组件设置 Iptables 策略时引发的内核 double-NAT 进而设置了错误的 checksum 值的问题碰到一起就会出现 vxlan 跨节点网络丢包的现象,两者解决一个都可以解决此问题,详细内容可以具体参考以下链接:
Ø https://github.com/coreos/flannel/issues/1279
Ø https://github.com/kubernetes/kubernetes/pull/92035
一方面对于 kernel 的 bug 尚未查到明确的 fixed 版本,对于海光芯片的服务器来说我们是通过升级网卡驱动程序来解决的,服务器网卡为网讯的 Ethernet Controller RP2000 ,升级驱动程序及版本为 kmod-ngbe-1.0.4-1.el8.x86_64 和 kmod-txgbe-1.1.12-1.el8.x86_64 ,这个解决方法只针对网讯的这款网卡,另一方面在 kubernetes(v1.16.13 、 v1.17.9 、 v1.18.6) 版本中对进行了修复。请参考以下链接中针对 PR#92035 修复的说明:
案例 2基于国芯海光 x86 和鲲鹏 arm 服务器安装银河麒麟 V10 操作系统,部署并运行 Kubernetes 网络插件 flannel 时出现跨服务器容器网络不通的现象。
现象:当我们完成基于海光、鲲鹏服务器和银河麒麟 V10 操作系统的 kubernetes 集群搭建时,跨节点容器网络测试不通。环境信息如下:
操作系统: Kylin Linux Advanced Server V10 (Tercel)
内核版本: 4.19.90-17.ky10.x86_64
kubernetes 版本: 1.17.4
flannel 版本: 0.11.0 ( vxlan 模式)
分析:参考案例 1 中的经验使用 tcpdump 对 flannel 的 UDP4789 端口抓包发现每个 UDP 数据包并没有出现 bad udp cksum 并且该数据包没有被丢弃,目标节点可以收到 UDP 包,但是只能接收到 TCP 连接第一次握手包,没有返回 ACK ,抓包信息如下:
UDP 包进入目标节点后会通过路由表路由至 cni0 的网桥上,进而进入目标容器,对 cni0 设备抓包没有发现数据包流入,查询主机路由表,其中存在至 cni0 的路由条目,查询 iptables 表、 ipvs 表和非麒麟操作系统相比也未发现异常。排查方向转向 flannel, 开启 flannel debug 级别日志,启动过程中发现 flannel 会创建一个 flannel.1 的网卡,同时会将该卡的 MAC 地址以注释方式写入 k8s 节点信息中和主机 FDB 中,排查要点如下:
- flannel 将生成的 flannel.1 的 MAC 地址注释在节点信息中。
- 其他节点的 flannel 将此 MAC 地址写入本机的 FDB 中。
- 在操作系统层查询 flannel.1 的 MAC 地址。
复盘整个 flannel 启动过程发现银河麒麟节点信息中的 MAC 地址与 FDB 中的 MAC 地址一致,和服务器上观察 flannel.1 的网卡 MAC 不一致,这样就可以解释为什么无法正常建立跨节点的 TCP 链接。通过 ip monitor 观察 flannel.1 网卡的启动过程发现该网卡被赋了两次 MAC 地址,第一次为 flannel 进程赋值,第二次是操作系统赋值。复现方法可以手动删除 flannel.1 网卡后重新启动 flannel 容器,同时用 ip monitor 捕捉事件:
相应的 flannel 组件写入节点注释信息和 FDB 的 MAC 地址:
操作系统层观察到的 flannel 网卡 MAC 地址:
措施:解决方法为创建 /usr/lib/systemd/network/10-flannel.link 文件,在文件内设置 flannel* 网卡的 MACAddressPolicy=none ,也就是对 flannel.1 设置例外不进行 MAC 生成并赋值,这样在 flannel 启动时保证 flannel.1 网卡、 FDB 、节点信息中的 MAC 地址的一致,通过测试容器网络跨节点通信恢复正常。以下为 10-flannel.link 文件内容: