Kosmos 实战系列:有状态服务(MySQL)跨云灾备实战
作者:董卫国,中国移动云能力中心软件研发工程师,专注于云原生、微服务、算力网络等
出于容灾考虑,应用的部署可能会有跨云、云内跨地域可用区(跨 vpc)的多集群的需求,此时容器的通信就出现了一定的困难,如果没有专线,那么机器的内网 IP 一般无法直接通信,CNI 常用的隧道技术如 vxlan/ipip 在公网环境下也可能会失效。在此基础上,Kosmos 基于 IPsec 隧道实现了跨云公网传输场景下的容器网络通信方案,解决了跨公网通信的需求,也兼顾了传输安全问题,下面我们进行简单的演示说明。
1 原理介绍
IPsec 隧道介绍
我们在跨公网打通容器网络的时候使用了 IPsec 隧道的能力,Linux 内核 2.6 版本以上的版本就已经支持了,我们可以简单的使用 ip xfrm 相关的命令构建 IPsec 的转发规则。IPsec 隧道的规则主要是通过 ip xfrm policy 和 ip xfrm state 命令进行构建。ip xfrm policy 命令用于建立 IPsec 的匹配规则,用来定义哪些流量通过 IPsec 加解密处理,通过 tmpl 字段与 ip xfrm state 匹配,ip xfrm state 则用于定义如何加密解密数据包。
注意:由于一些云厂商无法在安全组放通 esp 协议,可能要在安全组中针对两端的公网 IP 设置全部协议全部端口(即填写 ALL 或者 ANY 等) 进行放通。
模拟容器网络通信
本小节,我们就用 IPsec 来模拟容器网络通信,实验环境是云主机,两台云主机的安全组访问对于各自挂载的弹性公网 IP 的放开策略都设置为 ALL
其他信息
我们模拟实现的目标:在 node1 节点上的容器内可以 ping 通 node2 节点的容器内 IP
首先,要模拟容器网络,创建一个网络命名空间并挂载一个 IP,node1 操作如下:
node2 做类似操作如下:
在 node1 和 node2 上设置如下环境变量
执行如下命令,node1 配置流量的加解密规则:
参数说明:
src 和 dst 是对应的包的源地址和目的地址,例如:对于 node1 节点发出去的包,源地址是自身的内网节点,目的地址为 node2 的公网地址。
proto esp spi $ID 表示使用 ESP 协议,$ID 可以按需要指定或者随机生成,加解密相关的参数。
mode tunnel 指定使用隧道模式。
aead 'rfc4106(gcm(aes))' $KEY 128 表示使用 aes-gcm 加密,最后的 128 表示 aes-gcm 的 Integrity Check Value (ICV) 长度。
node1 节点配置未加密流量的匹配规则:
参数说明:
src 和 dst,用来匹配未加密前的 IP 报文源地址和目的地址。
dir 表示 direction,有 out/fwd/in 三种方向。所有出站数据走 out 规则,入站数据走 fwd 和 in 规则。
tmpl 后面的内容表示匹配的 ip xfrm state 规则,以匹配对应的加解密处理。
同理,node2 配置加解密算法和匹配规则:
在 node1 测试 ping node2 的容器 IP,可以看到
注意点:
IPsec 隧道基于内核的规则来运行,并没有产生新的虚拟网卡设备,也无需创建路由。
有些环境 iptables 的默认规则会限制流量转发,可以使用 iptables -P FORWARD ACCEPT 命令临时放开转发,同时关闭防火墙
2 跨公网纳管集群实战
Kosmos 的新版本将封装使用 IPsec 隧道跨公网通信的能力,前面介绍过了 IPsec 隧道的原理,本节我们使用 Kosmos 实战纳管集群,并测试跨公网 Kubernetes 集群的容器网络通信。
环境准备
我们自建了两套 Kubernetes 集群,环境如下:
集群 1
集群 2
其他信息
开始测试
首先准备好集群 1 的 kubeconfig,将集群 1 作为主集群,执行如下命令进行主集群的安装操作
参数说明:
参数的 node-elasticip 的值,vm-0-7-rockylinux 和 vm-0-10-rockylinux 都是集群中节点的 nodename,124.220.61.33 和 150.158.88.185 都是对应节点上绑定的弹性公网 IP。
参数 cni 根据实际情况填写,如 calico、flannel 等,参数 default-nic 根据实际情况填写,云主机一般是 eth0。参数 private-image-registry 是测试私有镜像仓库的地址,需要提前下载 Kosmos 相关的镜像传入,如不配置此项则在公网拉取镜像。
参数 kubeconfig 的值/root/master 为集群 1 的 kubeconfig,要注意的是要把其中的 server 地址配置为公网的地址,在这个场景下为 124.220.61.33 ,另外在某些环境如果公网地址没有配置在 apiserver 的证书中,我们可以把 kubeconfig 文件中的 cluster 部分设置为 insecure-skip-tls-verify: true,类似如下形式:
install 命令执行完成后,如下所示
其中/root/slave 为集群 2 的 kubeconfig,要和/root/master 做同样的修改。结果如下所示
执行完以上操作之后,可以在主集群检查下 Pod 状态,如下所示
此时我们可以在任一集群内找一个非 hostnetwork 模式的 Pod,访问另一个集群内的非 hostnetwork 模式的容器的 IP,我们以 coredns 为例,参考如下命令找到 coredns 容器的主进程
使用 nsenter 命令进入容器的主进程的网络命名空间下,此时通过 ip a 命令可以看到 IP 地址为容器的 IP,而不是宿主机的 IP,如下所示
在该网络命名空间下测试 ping 另一个集群内的 coredns 的 Pod,可以成功 ping 通,如下所示
我们应该还记得 100.64.0.0/10 是属于集群 1 的网段,100.128.0.0/10 是属于集群 2 的网段,上面的测试用,IP 100.68.215.196 属于集群 1,IP 100.164.13.193 属于集群 2,至此,我们拉通了集群 1 和集群 2 的容器网络,并做了基本的验证。
IPsec 规则展示
前面我们已经验证了 Kosmos 跨公网容器通信的能力,本小节,我们通过抓包和 ip xfrm 相关命令来验证流量通过 IPsec 隧道转发。
在上面的测试环境中,我们可以在网关节点(Kosmos 网络模块中的概念)查看相关的配置,如下所示网关节点的 ROLE 被标注为"gateway":
通过 ip xfrm policy 和 ip xfrm state 命令查看已配置的内容。
在环境中查看 ip xfrm policy 内容如下所示:
查看 ip xfrm state 内容如下所示:
IPsec 通过 ESP 协议通信,我们在 ping 容器 IP 的同时在对端宿主机网卡上抓包效果如下:
代码实现简单介绍
本节,我们对 Komos 跨公网通信的代码实现做一些简单介绍。
我们在测试的时候,在执行 install 和 join 的时候会输入公网 IP 和节点的映射关系,这个映射关系会体现在 Cluster(Kosmos 网络模块的一个 CRD)中,clusterlink-controller-manager 模块会侦听 Kubernetes 集群的 node 的状态,并把相关的配置同步到 ClusterNode(Kosmos 网络模块的一个 CRD)中,相关代码如下:
network-manager 模块通过侦听 ClusterNode 的状态进行调和,根据源和目的两端是否都配置了公网 IP 决定是否配置通过 IPsec 隧道进行通信,我们配置 IPsec 规则的代码大致如下
配置完成后,最后会将 IPsec 隧道的规则写在 NodeConfig(Kosmos 网络模块的一个 CRD)中,Kosmos 的 agent 模块会侦听 NodeConfig,根据相关规则在节点上创建相应的规则。
相关代码大致如下
关于 IPsec 规则的创建,部分代码我们借鉴了 Flannel,有些区别的是 Flannel 部分借助了 Strongswan(配置 IPsec 规则的开源工具)的能力,而我们在 Kosmos 中直接进行 ip xfrm 相关的操作,这样无需把 Strongswan 的二进制工具打到镜像内,可以减少镜像包的大小,但如果引入 Strongswan 可以更加容易的应对复杂的网络场景,后续我们会考虑引入以处理复杂的跨公网集群网络拓扑。
3 跨云实战
前面我们介绍了 IPsec 模拟容器网通信和跨公网纳管自建集群,本小节,我们将演示一个跨云的多集群案例,纳管在云厂商订购的 Kubernetes 集群。我们将部署一个跨云的 MySQL 实例,其主备实例分别启动在两个云厂商的 Kubernetes 集群中,并测试主备数据同步。
跨云纳管集群
首先我们在移动云订购一个 KCS 集群作为主集群,参考上面章节的命令执行 kosmosctl install 相关的操作以部署主集群的 Kosmos 服务。
然后我们需要部署一套开源的 operator,并使用 Kosmos 的调度器替换 Kubernetes 原始的调度器,方案参考我们的公众号文章:Kosmos 实战系列:MySQL Operator 有状态服务的跨 AZ 集群平滑迁移
接下来我们需要在腾讯云订购一个 TKE 集群(测试中我们订购了 GlobalRouter 作为 CNI 的 TKE 集群)。
最后,在腾讯云和移动云的安全组中对两端公网弹性 IP 和容器网络的网段进行放通。
执行如下命令进行纳管腾讯 TKE 集群作为从集群:
参数 $EIP 是提前设置的环境变量,请根据实际情况配置、填写。
参数 cni 根据实际情况填写,本次测试中我们的 TKE 集群使用 Global Router 作为 CNI 插件。
cluster-pod-cidrs 是 TKE 容器网络的网段,可以在 TKE 的控制台查到,Global Router 是腾讯 TKE 自有的 CNI 插件,我们暂时没查到好的方式去获取 Pod CIDR,因此配置了纳管集群时人为输入,对于 Calico、Flannel 这种常见的开源 CNI 插件无需人为输入此参数。
执行完上面命令,就完成了集群的纳管,此时集群之间的容器网络就打通了,下面我们测试部署一套 MySQL 主备实例。
测试 MySQL 主备实例
在移动云 KCS 集群中创建如下 MySQL 实例和配套的 secret
这样我们就会创建一个 MySQL 主备实例,可以从上面实例的节点亲和性配置中可以看到,主备 MySQL 实例 Pod 分别启动在 KCS 集群中的 kcs-kosmos-s-gg5dg 节点和我们的从集群节点 kosmos-member-tencent(该节点为从集群在主集群中的映射)。
如下所示:
接下来我们登入到腾讯云 TKE 集群中,进入 MySQL 主实例中,在实例中写入数据,如下所示:
此时,在移动云 KCS 集群中登陆 MySQL 的备实例,可以正常查询到数据,如下所示:
前面的章节我们用 ping 命令简单验证了跨公网容器网络的连通性,本节我们部署了 MySQL 的主备实例并测试了数据同步,从应用的层面上实践了跨腾讯云 TKE 和移动云 KCS 的容器网络打通。
测试整体流程效果如下所示:
关于 CNI 插件的适配
除了 IPsec 隧道的构建,跨云容器网络通信还需要考虑到 CNI 的差异,主要有两个方面:
一个是对于不同的 CNI 插件的 Pod CIDR 的管理方式可能有所不同
一个是容器访问非本机器的容器网络地址会进行地址伪装。
对于第一点,一些常见的 CNI 如 Calico、Flannel,我们已经完成了适配。Calico 的 Pod CIDR 是通过 ippool 管理的,Flannel 的 cidr 是配置在 configmap 中的,Kosmos 的网络模块会根据 ippool 或者特定的 configmap 去配置容器网络的 CIDR。有一些网络插件并不是开源的,我们可能没有好的方法去获取 Pod CIDR,这个时候就需要手动输入了,因此我们配置了 cluster-pod-cidrs 这个参数。
对于第二点,calico 也是通过在 ippool 进行配置的,所以在 Calico 作为 CNI 的 Kubernetes 集群中,会看到 Kosmos 创建的 ippool,不要感到意外,我们会将其的 disabled 值设置为 true,所以 Calico 不会真的使用这个 ippool 去分配 Pod 的 IP。对于一些我们验证过的网络插件,如 Flannel 和 GlobalRouter,我们会在 iptables nat 表的 POSTROUTING 链中设置一条规则,使得发往目的地时不进行地址伪装以保持容器的 IP,这样在 Kosmos 的回程路由才能工作正常。Kosmos 添加的 iptables 规则如下所示:
4 总结
本文我们介绍了使用 Kosmos 打通多云环境下的跨公网通信的 Kubernetes 集群的容器网络,首先是对 IPsec 进行了简单的介绍,然后使用 Kosmos 实践了跨公网的容器网络通信,并对相关的原理和代码实现进行了简单说明,最后我们演示了一个跨移动云 KCS 和腾讯云 TKE 的实操案例。
当前我们的跨公网通信仅支持 IPv4,在未来我们会继续开发 IPv6 相关的适配,对于复杂的网络联通情况也会进行考虑,如 Strongswan 介绍中的 Roadwarrior 等网络拓扑模式,当前流量的加解密是通过 PSK(Pre-shared Key),后续也会考虑其他的加解密模式以适配不同的安全需求。
由于笔者能力所限,难免存在错漏,请各位批评指正。
5 联系我们
扫描二维码联系我们!
版权声明: 本文为 InfoQ 作者【畅聊云原生】的原创文章。
原文链接:【http://xie.infoq.cn/article/5136568731d0ed2b660e03a31】。文章转载请联系作者。










评论