Qingular

高可用集群

·CKAk8s练习

Kubernetes 高可用集群架构设计,包括 etcd 拓扑选择、多控制平面节点部署和负载均衡配置。

← 返回 CKA 练习目录

概述

高可用(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 etcdExternal 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 考试要点

  1. controlPlaneEndpoint 必须配置为负载均衡地址 -- 而不是单个节点 IP
  2. --upload-certs -- 用于分享证书给其他控制平面节点
  3. etcd 需要奇数个节点(3 或 5)-- 确保 etcd 集群能选出 leader
  4. Scheduler 和 Controller Manager 默认开启 leader election -- 无需手动配置
  5. 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 重新生成

官方文档