广告:Codex Token 低价中转站稳定接口 · 快速接入 · 开发者备用通道
Engineering article

Kubernetes集群高可用搭建 | 混沌工程

在搭建Kubernetes集群高可用架构时,我直接踩了三个大坑。第一是主控节点的负载均衡没配置好,导致流量集中在单个节点,第二是etcd的高可用没做对,cluster-state不一致导致集群崩溃,第三是网络策略没隔离,主控和工作节点之间流量被误删。我用的是Calico网络插件,配置了多层防火墙策略,还用了Prometheus监控etcd

Kubernetes集群高可用搭建 | 混沌工程
配图来源于网络和AI生成,仅供参考。
▌ 技术引导
在搭建Kubernetes集群高可用架构时,我直接踩了三个大坑。第一是主控节点的负载均衡没配置好,导致流量集中在单个节点,第二是etcd的高可用没做对,cluster-state不一致导致集群崩溃,第三是网络策略没隔离,主控和工作节点之间流量被误删。我用的是Calico网络插件,配置了多层防火墙策略,还用了Prometheus监控etcd状态,直接通过`etcdctl endpoint status`看状态是否同步。主控节点用了Keepalived+VRRP做VIP漂移,工作节点用的是Taint控制,让Pod只能调度到可用的Master节点。整个架构必须从设计开始就考虑多节点冗余、自动故障转移和快速恢复,这样才能保证Kubernetes服务不中断。

▌ 技术参考

一 实际部署高可用Kubernetes集群需要从底层开始,而非依赖上层工具。主控节点必须至少运行三个实例,才能实现真正的无单点故障。etcd集群至少三个节点,且必须是奇数,避免脑裂。使用`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379`检查状态时,每个节点的`peer`状态必须为`Connected`,否则集群会随机丢数据。主控节点上的`kube-apiserver`要配置`--server-cert-snake-in`和`--client-ca-file`参数,确保证书链正确。每个节点的`--etcd-servers`必须指向所有etcd节点,否则无法形成高可用。

二 高可用的负载均衡策略不能随便套用,需要根据实际场景调整。使用Nginx作为负载均衡器时,配置`upstream api`指向三个apiserver节点,权重分配要合理,避免某些节点负载过高。同时,要开启`proxy-read-timeout`和`proxy-send-timeout`,防止超时问题。在配置`kubectl config set-cluster`时,指定`server`为负载均衡器的IP,而不是单个节点。注意在负载均衡器上启用`x-forwarded-for`头,方便后续日志追踪。实际部署时,我用的是静态IP绑定,每个节点的`--bind-address`要设置为本机网卡IP,而不是127.0.0.1,否则流量会走环路。

三 工作节点的调度策略要结合Taint和Node Affinity。主控节点添加`node-role.kubernetes.io/control-plane:NoSchedule`标签,确保Pod不会被调度到主控节点。但要允许某些系统Pod比如`kube-proxy`运行,需要额外配置。在`node.spec.taints`里添加`node-role.kubernetes.io/control-plane:NoSchedule`,并在`pod.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution`中设置`nodeSelectorTerms`匹配标签。注意在GKE或EKS上,这些Taint可能已经预设,需要检查相关节点角色配置。此外,Pod的`toleration`字段必须包含`node-role.kubernetes.io/control-plane`,否则会调度失败。

四 保持所有主控节点的时间同步是关键,否则etcd可能因为时间不同步而无法形成共识。使用`chronyd`或`ntpd`配置NTP服务器,确保每个主控节点的时钟误差小于100ms。在`/etc/chrony.conf`中设置`server ntp1.example.com iburst`,并启用`driftfile`来记录偏移量。配置完成后运行`chronyc tracking`检查是否同步成功。如果时钟不同步,etcd集群可能会出现`raft: failed to reach consensus`错误,导致API Server无法访问。这种情况下,需要手动干预,通过`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 cluster-health`查看状态,再通过`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 --user=root:password member list`确认成员状态是否正常。

五 在实际部署中,etcd的高可用配置需要考虑数据同步和网络拓扑。使用三个etcd节点,每个节点都和另外两个节点建立peer连接。配置文件`/etc/etcd/etcd.conf`中,`peer-addr`要指向所有etcd节点的IP和端口,确保集群成员列表完整。启动命令`etcd --data-dir=/var/lib/etcd --name etcd1 --initial-advertise-url=http://etcd1:2380 --advertise-client-urls=http://etcd1:2379`必须正确,否则集群会无法形成。如果某个etcd节点宕机,要确保其他节点能继续处理请求,通过`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 cluster-health`确认是否仍有可用节点。同时,定期用`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 --user=root:password snapshot save /tmp/etcd-snapshot.db`保存快照,防止数据丢失。

六 使用Keepalived实现VIP漂移时,配置文件`keepalived.conf`必须包含`virtualrouter_id`和`priority`参数,确保多个节点之间能正确选举。例如,主控节点1配置优先级200,节点2和3配置150,让节点1在正常时作为主节点。在`track_script`部分,使用`check_apiserver`脚本来检查API Server是否响应,命令如`curl -k https://localhost:6443`,如果失败则触发`priority 0`,强制切换。注意在每个主控节点加入`--bind-address`参数到API Server启动命令,确保VIP能正确绑定。Keepalived的日志文件`/var/log/messages`是排查问题的关键,要定期查看是否有`NOTICE: State change to BACKUP`这样的信息。

七 在使用Calico网络插件时,确保每个节点的`calico-node`和`calico-main`容器的IP配置正确,避免因为IP冲突导致网络隔离。配置`--ip`参数时,要使用节点的网卡实际IP,而不是127.0.0.1或内部IP。在`/etc/cni/net.d/10-calico.conflist`中,`type`字段必须为`calico`,并且`etcdEndpoints`指向三个etcd节点。同时,`policy`部分要允许主控节点和工作节点之间的通信,比如`ingress`和`egress`策略要配置正确。如果出现Pod无法访问主机的问题,检查`ipam`配置是否允许`masquerade`,并确保`node_ip`字段正确。

八 高可用Kubernetes集群中的存储配置不能忽视。使用Ceph或GlusterFS作为后端存储时,每个节点必须有独立的存储卷,避免存储单点故障。在`kubeadm`部署时,`--storage`参数要设置为`local`,并确保每个节点的`/etc/kubernetes/manifests/kube-apiserver.yaml`中`--storage-backend`为`etcd`。同时,etcd的存储路径`--data-dir`要配置为`/var/lib/etcd`,并确保磁盘空间足够。如果存储盘突然宕机,etcd会进入只读模式,需要手动干预恢复,可以通过`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 --user=root:password member list`确认成员状态,再通过`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 --user=root:password --lease grant 10`获取lease信息,帮助恢复数据。

九 节点的网络隔离需要精细配置。主控节点和工作节点之间,使用`iptables`规则限制非必要端口,防止外部攻击。例如,在`/etc/iptables/rules.v4`中,添加`-A INPUT -p tcp -m tcp --dport 2380 -j DROP`,阻止非etcd节点访问etcd端口。同时,工作节点之间可以用`iptables`限制`kubelet`的端口,比如`-A INPUT -p tcp -m tcp --dport 10250 -j DROP`,确保只有主控节点能访问kubelet。如果网络策略配置错误,可能导致Pod无法访问主控节点,进而引发调度失败或服务中断。

十 监控是高可用架构的基石。推荐使用Prometheus+Grafana进行实时监控,同时集成Alertmanager来告警。在`/etc/prometheus/prometheus.yml`中,配置`scrape_configs`,设置`job_name: 'k8s-etcd'`,`static_configs`指向所有etcd节点的`--metrics-bind-address`地址。对于API Server,配置`job_name: 'k8s-apiserver'`,`static_configs`指向负载均衡器的IP。同时,用`kubectl top node`和`kubectl top pod`监控资源使用情况,确保节点负载可控。如果某个节点CPU或内存使用率过高,可能需要调整Pod的资源限制或进行自动扩缩容。

十一 安全加固方面,必须配置TLS证书和API Server访问控制。etcd的证书使用`etcdctl --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd1.pem --key=/etc/etcd/ssl/etcd1-key.pem`访问时,要确保所有节点的证书都正确绑定。API Server的`--tls-cert-file`和`--tls-private-key-file`要指向正确的证书路径,避免连接失败。同时,使用`kubectl auth can-i`检查用户权限是否受限,确保只有授权用户能操作集群。在RBAC配置中,`RoleBinding`和`ClusterRoleBinding`要严格限制操作范围,避免权限泄露。

十二 容器网络插件的选型需要结合具体场景。Calico适合大规模集群,而Flannel适合小规模。在使用Calico时,每个节点的`calico-node`容器需要配置`--etcd-endpoints`,确保指向所有etcd节点。如果网络策略配置不当,可能导致Pod间通信失败,比如`NetworkPolicy`中的`ingress`或`egress`规则未正确设置。在`/etc/cni/net.d/10-calico.conflist`中,`type`字段必须正确,否则容器无法获取IP。如果Pod无法获取IP,可能需要检查`ipam`配置和`node_ip`参数是否准确。

十三 节点的自动故障转移需要监控工具支持。用Prometheus监控每个节点的`node_status`和`node_capacity`,当某个主控节点出现异常,通过`kubectl get nodes`检查状态是否为`NotReady`。如果发现主控节点状态异常,立即用`kubectl get nodes -o wide`查看IP和状态,再用`kubectl api-resources`确认API Server是否存活。同时,使用`kubectl describe node`检查事件日志,快速定位问题。如果VIP漂移失败,检查Keepalived的日志和`curl -k https://localhost:6443`命令的响应,确保VIP能正确切换。

十四 在实际部署中,测试高可用性必须结合混沌工程。使用Chaos Mesh引入网络故障、节点宕机、etcd崩溃等场景,观察集群是否能自动恢复。比如在`chaos mesh`中设置`chaos experiment`为`network chaos`,模拟节点间的网络断开,确保主控节点能检测到故障并触发VIP切换。在etcd节点上,可以使用`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 --user=root:password --lease grant 10`创建lease,再通过`--lease revoke`模拟数据丢失。如果集群无法恢复,需要检查`etcdctl cluster-health`和`kubectl get nodes`的状态。

十五 高可用架构中的每一步都要有回退方案。例如,如果etcd节点出现脑裂,手动通过`etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 --user=root:password member list`查看成员状态,再通过`--member remove`移除异常节点,重启集群。如果API Server无法访问,检查`--server-cert-snake-in`是否正确,还有`--bind-address`是否指向本机网卡IP。同时,确保`kubectl`配置文件中的`server`指向负载均衡器,而不是单个节点。如果配置错误,可能导致所有Pod无法访问API Server,进而引发整个集群崩溃。