高可用集群
Kubernetes 高可用集群架构设计,包括 etcd 拓扑选择、多控制平面节点部署和负载均衡配置。
概述
高可用(HA)集群通过冗余控制平面组件消除单点故障,确保集群在部分节点故障时仍能正常工作。CKA 考试要求理解 HA 架构的基本概念和 kubeadm 配置方法。
1. HA 拓扑架构
1.1 Stacked etcd 拓扑
┌─────────────────────┐
│ Load Balancer │
│ (HAProxy/Nginx) │
│ 192.168.1.100 │
│ port 6443 │
└──────┬──────────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌───────┴───────┐ ┌───┴────────┐ ┌───┴────────┐
│ CP-1 │ │ CP-2 │ │ CP-3 │
│ API Server │ │ API Server │ │ API Server │
│ Scheduler │ │ Scheduler │ │ Scheduler │
│ Controller-Mgr│ │Controller-Mgr│Controller-Mgr│
│ etcd (member) │ │ etcd (member)│ etcd (member)│
└───────────────┘ └────────────┘ └────────────┘
特点:
- etcd 与控制平面在同一节点
- 节点数较少,成本低
- 需要至少 3 个控制平面节点(奇数)
- etcd 故障会影响该节点的控制平面
1.2 External etcd 拓扑
┌─────────────────────┐
│ Load Balancer │
│ (HAProxy/Nginx) │
│ 192.168.1.100 │
│ port 6443 │
└──────┬──────────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌───────┴───────┐ ┌───┴────────┐ ┌───┴────────┐
│ CP-1 │ │ CP-2 │ │ CP-3 │
│ API Server │ │ API Server │ │ API Server │
│ Scheduler │ │ Scheduler │ │ Scheduler │
│ Controller-Mgr│ │Controller-Mgr│Controller-Mgr│
└───────────────┘ └────────────┘ └────────────┘
│ │ │
└──────────────┼──────────────┘
│
┌──────┴──────┐
│ etcd nodes │
│ 3 or 5 │
│ dedicated │
└─────────────┘
特点:
- etcd 运行在独立节点上
- 控制平面和 etcd 故障隔离
- 需要更多节点,成本高
- 适合生产环境大规模集群
1.3 拓扑对比
| 特性 | Stacked etcd | External etcd |
|---|---|---|
| 节点数 | 3+(控制平面) | 3+(控制平面)+ 3(etcd) |
| 成本 | 较低 | 较高 |
| 故障隔离 | etcd 故障影响同节点控制平面 | 完全隔离 |
| 性能 | etcd 与控制平面争用资源 | 独立资源 |
| 运维复杂度 | 较低 | 较高 |
| 适用场景 | 中小规模集群 | 大规模生产集群 |
2. 多控制平面节点设置
2.1 初始化第一个控制平面
# 在第一个控制平面节点上
sudo kubeadm init --config=kubeadm-config.yaml
# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "192.168.1.10"
bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.31.0"
controlPlaneEndpoint: "192.168.1.100:6443" # 负载均衡器地址
networking:
serviceSubnet: "10.96.0.0/12"
podSubnet: "10.244.0.0/16"
dnsDomain: "cluster.local"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd"
# 初始化时生成证书上传密钥(用于其他控制平面加入)
kubeadm init --config=kubeadm-config.yaml --upload-certs
# 输出中会包含:
# - kubeadm join 命令(包含 token)
# - --certificate-key(用于控制平面节点加入)
2.2 添加额外的控制平面节点
# 在第二个控制平面节点上
sudo kubeadm join 192.168.1.100:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane \
--certificate-key <certificate-key>
# 在第三个控制平面节点上
sudo kubeadm join 192.168.1.100:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane \
--certificate-key <certificate-key>
2.3 验证 HA 集群
# 查看所有节点
kubectl get nodes
# 查看控制平面组件
kubectl get pods -n kube-system | grep -E "kube-apiserver|kube-scheduler|kube-controller"
# 查看 etcd 成员
kubectl exec -n kube-system etcd-cp-1 -- etcdctl member list
# 验证 API Server 高可用(通过负载均衡地址访问)
curl -k https://192.168.1.100:6443/version
# 模拟一个控制平面节点故障
# 关闭一个控制平面的 kubelet
# 验证集群仍然可用
kubectl get nodes
3. API Server 负载均衡配置
3.1 HAProxy 配置
# 安装 HAProxy
sudo apt install -y haproxy
# /etc/haproxy/haproxy.cfg
frontend kubernetes-frontend
bind *:6443
mode tcp
option tcplog
default_backend kubernetes-backend
backend kubernetes-backend
mode tcp
option tcp-check
balance roundrobin
server cp-1 192.168.1.10:6443 check fall 3 rise 2
server cp-2 192.168.1.11:6443 check fall 3 rise 2
server cp-3 192.168.1.12:6443 check fall 3 rise 2
# 重启 HAProxy
sudo systemctl restart haproxy
sudo systemctl enable haproxy
# 验证负载均衡
curl -k https://192.168.1.100:6443/version
3.2 Nginx 负载均衡
# /etc/nginx/nginx.conf
stream {
upstream kubernetes {
server 192.168.1.10:6443;
server 192.168.1.11:6443;
server 192.168.1.12:6443;
}
server {
listen 6443;
proxy_pass kubernetes;
proxy_connect_timeout 1s;
proxy_timeout 3s;
}
}
# 重启 Nginx
sudo systemctl restart nginx
sudo systemctl enable nginx
3.3 keepalived(虚拟 IP)
# 安装 keepalived
sudo apt install -y keepalived
# /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER # 主节点设为 MASTER,备节点设为 BACKUP
interface eth0
virtual_router_id 51
priority 100 # 主节点 100,备节点 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100/24 # 虚拟 IP
}
}
# 启动 keepalived
sudo systemctl restart keepalived
sudo systemctl enable keepalived
# 验证虚拟 IP
ip addr show | grep 192.168.1.100
4. 控制平面组件冗余
4.1 API Server 冗余
API Server 是无状态的,多个实例通过负载均衡对外提供服务。
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.1.10
- --etcd-servers=https://192.168.1.10:2379,https://192.168.1.11:2379,https://192.168.1.12:2379
# 注意:etcd-servers 指向所有 etcd 节点
4.2 Scheduler 冗余
Scheduler 通过 leader election 实现高可用,同一时间只有一个实例执行调度。
# /etc/kubernetes/manifests/kube-scheduler.yaml
spec:
containers:
- command:
- kube-scheduler
- --leader-elect=true
- --leader-elect-lease-duration=15s
- --leader-elect-renew-deadline=10s
- --leader-elect-retry-period=2s
4.3 Controller Manager 冗余
同样使用 leader election,同一时间只有一个实例执行控制器逻辑。
# /etc/kubernetes/manifests/kube-controller-manager.yaml
spec:
containers:
- command:
- kube-controller-manager
- --leader-elect=true
- --leader-elect-lease-duration=15s
- --leader-elect-renew-deadline=10s
- --leader-elect-retry-period=2s
4.4 查看 Leader Election 状态
# 查看谁是当前的 scheduler leader
kubectl get endpoints -n kube-system kube-scheduler -o yaml
# 查看谁是当前的 controller-manager leader
kubectl get endpoints -n kube-system kube-controller-manager -o yaml
# 输出示例(annotations 中显示当前 leader):
# annotations:
# control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"cp-1","leaseDurationSeconds":15,...}'
5. kubeadm 配置 HA 集群完整示例
5.1 配置文件初始化
# ha-cluster-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "192.168.1.10"
bindPort: 6443
nodeRegistration:
criSocket: "unix:///var/run/containerd/containerd.sock"
name: "control-plane-1"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.31.0"
controlPlaneEndpoint: "192.168.1.100:6443"
apiServer:
certSANs:
- "192.168.1.100" # 负载均衡器 IP
- "loadbalancer.example.com" # 负载均衡器域名
- "127.0.0.1"
controllerManager: {}
scheduler: {}
networking:
serviceSubnet: "10.96.0.0/12"
podSubnet: "10.244.0.0/16"
dnsDomain: "cluster.local"
etcd:
local:
dataDir: "/var/lib/etcd"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "iptables"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd"
6. 验证 HA 功能
# 1. 验证所有控制平面节点运行
kubectl get nodes -o wide
# 2. 验证 etcd 集群健康
kubectl exec -n kube-system etcd-cp-1 -- etcdctl \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
endpoint health --cluster
# 3. 验证 API Server 负载均衡
for i in {1..10}; do
curl -sk https://192.168.1.100:6443/version | jq .serverVersion
done
# 4. 模拟故障
# 停止一个控制平面节点的 kubelet
# 验证集群仍可正常操作
kubectl get pods --all-namespaces
CKA 考试要点
- controlPlaneEndpoint 必须配置为负载均衡地址 -- 而不是单个节点 IP
- --upload-certs -- 用于分享证书给其他控制平面节点
- etcd 需要奇数个节点(3 或 5)-- 确保 etcd 集群能选出 leader
- Scheduler 和 Controller Manager 默认开启 leader election -- 无需手动配置
- HA 集群至少需要 3 个控制平面节点 -- 2 个节点无法容忍单点故障(etcd 需要多数派)
🧪 完整操作实例:配置高可用控制平面(Stacked etcd)
场景描述
在已有第一个控制平面节点(control-plane-1)的基础上,添加第二个控制平面节点(control-plane-2)形成 stacked etcd 高可用架构,并通过负载均衡地址访问集群。
前置条件
- 已有一个初始化完成的控制平面节点(control-plane-1)
- 第二个控制平面节点(control-plane-2)已完成基础设施配置
- 至少配置了一个负载均衡器(如 HAProxy)地址
192.168.1.100:6443 - 两个控制平面节点之间网络互通
操作步骤
Step 1: 验证第一个控制平面节点
# 在 control-plane-1 上
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# control-plane-1 Ready control-plane 1h v1.31.0
kubectl get pods -n kube-system | grep -E "kube-apiserver|etcd"
# etcd-control-plane-1 1/1 Running 0 1h
# kube-apiserver-control-plane-1 1/1 Running 0 1h
Step 2: 在第一个控制平面创建 kubeadm-config.yaml
# kubeadm-config.yaml(在 control-plane-1 上)
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "192.168.1.10"
bindPort: 6443
nodeRegistration:
criSocket: "unix:///var/run/containerd/containerd.sock"
name: "control-plane-1"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.31.0"
controlPlaneEndpoint: "192.168.1.100:6443"
apiServer:
certSANs:
- "192.168.1.100"
- "control-plane-1"
- "control-plane-2"
networking:
serviceSubnet: "10.96.0.0/12"
podSubnet: "10.244.0.0/16"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd"
Step 3: 初始化第一个控制平面(带 --upload-certs)
sudo kubeadm init --config=kubeadm-config.yaml --upload-certs
# 输出中会包含:
# You can now join any number of control-plane nodes by running the following on each as root:
# kubeadm join 192.168.1.100:6443 --token <token> \
# --discovery-token-ca-cert-hash sha256:<hash> \
# --control-plane --certificate-key <certificate-key>
#
# 保存 token、hash 和 certificate-key!
Step 4: 在第二个控制平面节点加入集群
# 在 control-plane-2 上运行(从 Step 3 输出中获取)
sudo kubeadm join 192.168.1.100:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane \
--certificate-key <certificate-key>
# 输出示例:
# This node has joined the cluster and a new control plane instance was created
# ...
# To start using your cluster, you need to run the following as a regular user:
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
Step 5: 验证两个控制平面节点
# 在任意控制平面节点上
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# control-plane-1 Ready control-plane 1h v1.31.0
# control-plane-2 Ready control-plane 5m v1.31.0
# 验证 etcd 集群成员
kubectl exec -n kube-system etcd-control-plane-1 -- etcdctl \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
member list
# 8e9e05c52164694d, started, control-plane-1, https://192.168.1.10:2380, https://192.168.1.10:2379
# 6a4d1c8352a47abd, started, control-plane-2, https://192.168.1.11:2380, https://192.168.1.11:2379
验证结果
# 通过负载均衡地址访问集群
curl -k https://192.168.1.100:6443/version
# {
# "major": "1",
# "minor": "31",
# ...
# }
# 验证控制平面组件高可用
kubectl get pods -n kube-system | grep -E "kube-apiserver|kube-scheduler|kube-controller"
# kube-apiserver-control-plane-1 1/1 Running 0 1h
# kube-apiserver-control-plane-2 1/1 Running 0 5m
# ...
考试提示
controlPlaneEndpoint必须设置为负载均衡器地址,而非单个控制平面节点 IP--upload-certs用于将控制平面证书安全地分享给其他控制平面节点- etcd 需要奇数个节点(3 或 5)才能选出 leader
- 加入控制平面节点时必须使用
--control-plane和--certificate-key参数 - 如果 token 过期,使用
kubeadm token create --print-join-command重新生成