生产级高可用Kubernetes集群的部署,远不是几条kubeadm命令就能搞定的事情。深夜收到报警短信、API Server突然宕机、证书过期导致集群瘫痪,这些场景是每个运维人最不愿面对的噩梦,但往往源于部署时忽略的关键细节。
本文基于Kubernetes官方文档及多个生产环境的踩坑经验,从架构设计到部署实操,完整拆解一个真正可用的高可用集群该如何落地。文章聚焦于堆叠控制平面拓扑这一生产中最常用的方案,同时覆盖外部etcd、负载均衡配置、安全加固和灾备演练等生产级要素,帮助你从零搭建一套经得起考验的集群。
一、架构设计:先想清楚再动手
1.1 两种高可用拓扑的选择
在开始部署之前,需要先确定控制平面的架构方案。kubeadm支持两种高可用拓扑:
堆叠etcd拓扑是最常用的方案。etcd成员与控制平面节点部署在同一台机器上,每个控制平面节点同时运行kube-apiserver、kube-controller-manager、kube-scheduler和一个本地etcd成员。这种方式的优势是基础设施需求少、设置更简单、副本管理更容易。缺点是控制平面节点与etcd成员耦合,单个节点故障时两者同时丢失。
外部etcd拓扑将etcd集群独立部署在控制平面之外的节点上。每个控制平面节点仍然运行API Server、Controller Manager和Scheduler,但etcd成员分布在独立的主机上。这种方案解耦了控制平面和etcd,故障影响范围更小,但需要两倍于堆叠方案的主机数量。对于大多数生产环境,堆叠方案已足够满足需求,本文以此为主线。
1.2 节点规划的最低标准
对于生产级高可用集群,节点规划需要遵循以下原则:
控制平面节点至少3台。控制平面节点数量必须为奇数,这有助于在机器故障或分区故障时进行领导者选举。3台是堆叠方案的最低要求。如果只有2台控制平面节点,在选举时无法形成多数派,集群将无法正常工作。
工作节点至少2台。工作节点用于运行业务Pod,数量根据负载需求决定。生产环境建议至少2台以保证Pod调度的冗余性。
网络要求:所有节点之间必须实现全网络连接,包括控制平面节点之间、控制平面与工作节点之间。通信可以在公网或私网中进行,但所有节点需要能够通过端口6443访问API Server。
1.3 etcd的黄金法则
如果采用外部etcd方案,etcd集群同样需要奇数个节点,至少3台。有以下几条黄金法则需要牢记:
etcd节点必须使用独立磁盘,禁止与其他服务共享磁盘,避免I/O竞争导致心跳超时。
etcd对磁盘性能极为敏感,建议使用SSD。如果跨多个机房部署,考虑5节点配置,将节点分布在3个机房中,例如机房A部署2节点、机房B部署2节点、机房C部署1节点,以避免脑裂问题。
二、环境准备:所有节点的统一操作
以下步骤需要在集群中的每台机器上执行,包括控制平面节点和工作节点。
2.1 系统基础配置
关闭Swap分区是kubelet正常运行的前提条件。Swap会干扰kubelet的内存隔离能力,必须在所有节点上禁用:
bash
swapoff -a
sed -i '/swap/d' /etc/fstab
配置主机名和/etc/hosts文件,确保节点之间能够通过主机名互相通信。设置内核参数开启桥接转发和IP转发,这是网络插件正常工作的基础:
bash
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
时间同步同样不可忽视,集群中各节点时间差过大会导致证书验证失败。使用chrony或ntpdate确保系统时间一致。
2.2 容器运行时安装
Kubernetes需要容器运行时来运行Pod。containerd是目前最常用的选择,安装后需要配置systemd cgroup驱动:
bash
apt install -y containerd # Ubuntu/Debian
yum install -y containerd # CentOS/RHEL
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd
cgroup驱动配置为systemd,确保与kubelet使用的驱动一致,避免资源管理冲突。
2.3 安装kubeadm、kubelet、kubectl
在所有节点上安装这三个工具,并锁定版本以防止自动升级:
bash
# Ubuntu/Debian示例
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list
apt update
apt install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
建议将kubeadm、kubelet、kubectl的版本与要部署的Kubernetes版本匹配,版本不一致可能导致意外行为。
三、配置API Server负载均衡器
高可用集群的核心是让API Server具备容错能力。所有对API Server的请求,包括kubectl命令和kubelet心跳,都需要通过负载均衡器分发到多个控制平面节点。
3.1 为什么不建议直接使用云厂商HTTP负载均衡器
API Server需要的是TCP层负载均衡,而非HTTP(S)负载均衡。云厂商的HTTP负载均衡器在TCP长连接场景下可能引入不必要的连接中断。健康检查必须配置为API Server的/readyz端点,而非简单的端口检测。
3.2 使用HAProxy + Keepalived搭建本地负载均衡
在控制平面节点上部署HAProxy提供四层TCP转发,Keepalived提供VIP漂移,确保单点故障时的自动切换。
HAProxy配置示例:
bash
# /etc/haproxy/haproxy.cfg
frontend k8s-api
bind *:6443
mode tcp
default_backend k8s-api-backend
backend k8s-api-backend
mode tcp
balance roundrobin
option tcp-check
tcp-check connect port 6443
tcp-check send GET /readyz HTTP/1.0\r\nHost:\ k8s-api\r\n\r\n
tcp-check expect string ok
server master1 192.168.1.11:6443 check
server master2 192.168.1.12:6443 check
server master3 192.168.1.13:6443 check
Keepalived配置示例:
bash
# /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
interface eth0
state MASTER
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100
}
}
3.3 验证负载均衡器连通性
在配置完成后,使用以下命令测试VIP是否能正常通信:
bash
nc -zv -w 2 <VIP> 6443
连接拒绝是可以预期的,因为API Server尚未启动。但超时则意味着负载均衡器无法与控制平面节点通信,需要重新检查配置。
四、初始化第一个控制平面节点
4.1 kubeadm init命令详解
在第一个控制平面节点上执行初始化命令,关键参数说明如下:
bash
sudo kubeadm init \
--control-plane-endpoint "192.168.1.100:6443" \
--upload-certs \
--pod-network-cidr=10.244.0.0/16
control-plane-endpoint必须设置为负载均衡器的地址或DNS和端口,而非某个具体的控制平面节点IP。upload-certs标志将控制平面证书加密并上传到集群中的Secret,供其他控制平面节点加入时下载使用,这是多控制平面自动证书分发的关键。
注意:--config和--certificate-key不能同时使用,如果使用kubeadm配置文件,需要在InitConfiguration中添加certificateKey字段。
4.2 保存join命令输出
初始化成功后,kubeadm会输出两段关键信息:
控制平面节点加入命令,包含token、ca-cert-hash和certificate-key。工作节点加入命令,包含token和ca-cert-hash。
务必将这些命令保存下来,证书密钥可以访问集群敏感数据,需要妥善保管。同时注意,上传的证书在两小时后自动失效,如果超时需要使用kubeadm init phase upload-certs重新上传。
4.3 配置kubectl访问
在第一个控制平面节点上配置kubectl访问集群:
bash
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
五、加入其余控制平面节点
每个额外的控制平面节点需要执行与init输出中完全相同的join命令:
bash
sudo kubeadm join 192.168.1.100:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane \
--certificate-key <certificate-key>
control-plane标志告诉kubeadm要创建一个新的控制平面而非工作节点。certificate-key参数用于从集群的kubeadm-certs Secret中下载控制平面证书并解密。
多个控制平面节点可以并行加入,完成此步骤后,集群已具备3个API Server副本和3个etcd成员的容错能力。
六、安装CNI网络插件
在控制平面初始化后,工作节点加入前,必须部署网络插件,否则Pod无法跨节点通信。
6.1 网络插件选型
Calico是目前最常用的选择,功能全面,支持网络策略。适用于对安全策略和网络隔离要求较高的生产环境。
Flannel配置简单,适合对网络策略要求不高的场景。需确保Flannel的Pod CIDR与kubeadm init时指定的--pod-network-cidr一致。
Cilium是基于eBPF的新一代网络方案,在性能要求极高的场景中表现出色。某游戏公司从Calico迁移至Cilium后,网络延迟降低40%。但引入Cilium后建议关闭kube-proxy,并使用kubeProxyReplacement=strict。
6.2 部署Calico
bash
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
6.3 验证控制平面组件状态
部署网络插件后,查看控制平面组件的Pod状态,确保所有组件正常启动:
bash
kubectl get pod -n kube-system -w
七、加入工作节点
在工作节点上执行init输出中提供的工作节点join命令:
bash
kubeadm join 192.168.1.100:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
工作节点加入时不使用control-plane标志。token过期后可以通过kubeadm token create --print-join-command重新生成。
八、验证集群高可用性
8.1 集群状态检查
bash
kubectl get nodes
# 应看到所有控制平面节点状态为Ready,所有工作节点状态为Ready
kubectl get pods -n kube-system
# 应看到控制平面组件和网络插件的Pod均为Running状态
8.2 控制平面故障演练
在VIP所在的控制平面节点上停止kubelet,观察VIP是否漂移到其他控制平面节点:
bash
systemctl stop kubelet
# 检查VIP是否漂移
ip addr show | grep <VIP>
随后执行kubectl get nodes验证集群是否仍然可用。恢复kubelet后节点应重新加入集群。
九、生产环境的关键补充
9.1 证书生命周期管理
kubeadm默认签发的证书有效期为一年,过期将导致集群瘫痪。生产环境中必须关注证书续期:
bash
# 检查证书过期时间
kubeadm certs check-expiration
# 手动续期所有证书
kubeadm certs renew all
使用cert-manager实现证书自动管理是更稳妥的长期方案。
9.2 安全加固要点
禁用匿名访问:在kube-apiserver启动参数中添加--anonymous-auth=false。
RBAC精细化控制:避免将cluster-admin角色授予普通开发人员,按照命名空间分配最小权限。使用Role和RoleBinding定义具体命名空间内的操作权限,ClusterRole和ClusterRoleBinding仅用于需要跨命名空间管理的场景。
审计日志:记录所有敏感操作,包括对Secret的delete和patch操作,便于事后追溯。
9.3 监控与灾备
部署Prometheus + Grafana监控集群状态,关键指标包括API Server请求延迟、etcd磁盘同步延迟、节点CPU和内存使用率等。同时制定etcd备份计划,定期备份etcd数据是灾难恢复的最后防线。
十、常见问题排查
证书过期:集群突然不可用,kubectl报错证书过期。解决方案:使用kubeadm certs renew all续期所有证书,或通过cert-manager自动管理。
API Server健康检查失败:负载均衡器无法识别API Server的存活状态。解决方案:检查负载均衡器的健康检查配置,确保使用/readyz端点而不是简单的端口检测。配置tcp-check命令发送GET /readyz请求并期望返回ok。
etcd性能问题:etcd节点磁盘I/O竞争导致心跳超时。解决方案:为etcd节点配置独立SSD磁盘,禁止与其他服务共享磁盘。etcd的磁盘性能直接决定集群的稳定性。
Pod跨节点通信失败:网络插件未正确部署。解决方案:确保网络插件已成功部署且Pod处于Running状态。检查CNI配置文件是否正确生成,确认Pod CIDR与kubeadm init时指定的值一致。
结语
生产级高可用Kubernetes集群的搭建,关键不在于命令本身,而在于部署前对架构的充分思考和对细节的极致把控。从节点规划到负载均衡,从证书管理到灾备演练,每一个环节都可能在业务高峰时成为引发故障的薄弱点。
本文覆盖了堆叠etcd拓扑的完整部署流程,但对于超大规模集群或特殊场景,外部etcd、二进制部署、跨可用区容灾等方案同样值得深入研究。记住,真正稳定的集群不是靠某个工具获得的,而是靠对细节的敬畏和持续的迭代优化沉淀下来的。