以下是 Kubernetes 三 Master 控制平面高可用(HA)集群的完整实现指南,并以 Nginx 项目为例演示应用部署。
一、架构设计原理
1. 为什么需要三 Master?
Kubernetes 控制平面包含四个核心组件:
- kube-apiserver:集群入口,所有操作都通过它
- etcd:分布式键值存储,保存集群所有状态数据
- kube-scheduler:负责 Pod 调度
- kube-controller-manager:运行各种控制器
单 Master 架构下,一旦该节点故障,整个集群将不可用。三 Master 架构通过以下机制实现高可用:
| 机制 | 说明 |
|---|---|
| etcd Quorum | etcd 使用 Raft 共识算法,3 节点可容忍 1 节点故障((3-1)/2 = 1),保证数据一致性 |
| API Server 多活 | 多个 kube-apiserver 同时对外提供服务,通过负载均衡器统一入口 |
| Controller/Scheduler 选主 | 通过 --leader-elect 机制,只有一个实例工作,故障时自动切换 |
2. 两种拓扑结构
Stacked etcd(堆叠式)——推荐用于大多数场景:
- etcd 运行在 Master 节点上,与控制平面组件共存
- 部署简单,由 kubeadm 自动管理
- 适合中小型集群
External etcd(外部 etcd):
- etcd 运行在独立节点上,与 Master 分离
- 更灵活,但部署复杂
- 适合大规模或对 etcd 有独立运维需求的场景
本指南采用 Stacked etcd 拓扑。
3. 负载均衡器设计
所有节点(包括 Master 自身)都通过负载均衡器访问 API Server,确保:
- 单一稳定的入口地址(
controlPlaneEndpoint) - 自动故障转移,屏蔽后端 Master 节点故障
- 健康检查,自动剔除不可用的 API Server
二、环境准备
节点规划
| 角色 | 主机名 | IP 地址 | 配置建议 |
|---|---|---|---|
| Master-1 | k8s-master-1 | 192.168.1.101 | 4C8G+ |
| Master-2 | k8s-master-2 | 192.168.1.102 | 4C8G+ |
| Master-3 | k8s-master-3 | 192.168.1.103 | 4C8G+ |
| Worker-1 | k8s-worker-1 | 192.168.1.201 | 4C8G+ |
| Worker-2 | k8s-worker-2 | 192.168.1.202 | 4C8G+ |
| LB (Nginx) | k8s-lb | 192.168.1.100 | 2C4G |
注意:LB 节点可以是独立服务器,也可以复用 Worker 节点。生产环境建议使用硬件负载均衡或云厂商 LB。
所有节点基础配置
# 1. 关闭 Swap
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab
# 2. 配置主机名(分别在对应节点执行)
sudo hostnamectl set-hostname k8s-master-1 # 或 master-2, master-3, worker-1...
# 3. 配置 hosts
cat <<EOF | sudo tee /etc/hosts
192.168.1.100 k8s-lb
192.168.1.101 k8s-master-1
192.168.1.102 k8s-master-2
192.168.1.103 k8s-master-3
192.168.1.201 k8s-worker-1
192.168.1.202 k8s-worker-2
EOF
# 4. 配置内核参数
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo 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
sudo sysctl --system
# 5. 安装容器运行时(containerd)
sudo apt-get update
sudo apt-get install -y containerd
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd
# 6. 安装 kubeadm, kubelet, kubectl
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo 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.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
三、负载均衡器配置(Nginx Stream 模块)
在 LB 节点(192.168.1.100)上配置 Nginx 作为四层负载均衡器,转发 TCP 6443 端口到三个 Master 节点。
# 安装 Nginx
sudo apt-get update
sudo apt-get install -y nginx
# 配置 Nginx Stream(四层负载均衡)
sudo tee /etc/nginx/nginx.conf <<'EOF'
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 4096;
}
stream {
upstream k8s_apiserver {
least_conn;
server 192.168.1.101:6443 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.102:6443 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.103:6443 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 6443;
proxy_pass k8s_apiserver;
proxy_timeout 300s;
proxy_connect_timeout 5s;
}
}
EOF
# 检查配置并重启
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl enable nginx
验证:从任意节点执行
curl -k https://192.168.1.100:6443/healthz,应返回ok(此时后端 Master 尚未启动,可能会失败,待 Master 启动后再验证)。
四、初始化第一个 Master 节点
在 k8s-master-1 上执行:
1. 生成证书密钥
# 生成用于共享证书的密钥,务必保存好
CERT_KEY=$(sudo kubeadm certs certificate-key)
echo $CERT_KEY
# 示例输出:f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
2. 创建 kubeadm 配置文件
cat <<EOF | sudo tee /root/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
certificateKey: ${CERT_KEY}
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: stable-1
controlPlaneEndpoint: "192.168.1.100:6443"
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16
apiServer:
certSANs:
- "192.168.1.100"
- "127.0.0.1"
- "k8s-lb"
timeoutForControlPlane: 4m0s
etcd:
local:
dataDir: /var/lib/etcd
EOF
3. 初始化集群
sudo kubeadm init --config=/root/kubeadm-config.yaml --upload-certs
关键参数说明:
--control-plane-endpoint:指向负载均衡器地址,这是 HA 的核心--upload-certs:将证书加密上传到集群,供其他 Master 节点加入时使用(2 小时内有效)certificateKey:解密证书所需的密钥
4. 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
5. 保存 join 命令
初始化完成后,终端会输出两个重要的 join 命令,务必保存:
# 控制平面节点加入命令(用于 Master-2, Master-3)
kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxx \
--control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
# Worker 节点加入命令(用于 Worker-1, Worker-2)
kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxx
五、安装 CNI 网络插件
在 Master-1 上执行,必须在加入其他节点之前完成:
# 使用 Calico 作为 CNI
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml
# 等待 Pod 启动
kubectl wait --for=condition=ready pod -l k8s-app=calico-node -n calico-system --timeout=300s
如果不先安装 CNI,后续加入的节点将一直处于
NotReady状态。
六、加入其他控制平面节点
在 Master-2 和 Master-3 上执行控制平面加入命令:
sudo kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 \
--control-plane --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07
执行完成后,在每个新 Master 上配置 kubectl:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
验证控制平面
kubectl get nodes
# 应看到 3 个 master 节点,状态为 Ready
kubectl get pods -n kube-system -l component=kube-apiserver
# 应看到 3 个 apiserver Pod
kubectl get pods -n kube-system -l component=etcd
# 应看到 3 个 etcd Pod
验证 etcd 集群健康
sudo kubectl exec -n kube-system etcd-k8s-master-1 -- \
etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
endpoint health
七、加入 Worker 节点
在 Worker-1 和 Worker-2 上执行:
sudo kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866
验证集群状态
kubectl get nodes
预期输出:
NAME STATUS ROLES AGE VERSION
k8s-master-1 Ready control-plane 10m v1.30.x
k8s-master-2 Ready control-plane 8m v1.30.x
k8s-master-3 Ready control-plane 6m v1.30.x
k8s-worker-1 Ready <none> 3m v1.30.x
k8s-worker-2 Ready <none> 2m v1.30.x
八、以 Nginx 项目为例部署应用
现在集群已就绪,我们来部署一个完整的 Nginx 应用,演示在 HA 集群上的工作负载分布。
1. 创建 Namespace
kubectl create namespace nginx-demo
2. 创建 Deployment
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
namespace: nginx-demo
labels:
app: nginx
spec:
replicas: 6
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
kubectl apply -f nginx-deployment.yaml
podAntiAffinity 配置尽量将 Nginx Pod 分散到不同节点,提升应用层高可用。
3. 创建 Service
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: nginx-demo
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
kubectl apply -f nginx-service.yaml
4. 创建 Ingress(使用 Gateway API)
注意:Kubernetes 社区已于 2026 年 3 月 24 日正式停止维护 Ingress NGINX 项目,新集群建议使用 Gateway API。
安装 Gateway API CRD:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
部署 Envoy Gateway:
helm repo add eg https://charts.envoyproxy.io/
helm repo update
helm install eg eg/gateway-helm -n envoy-gateway-system --create-namespace
创建 Gateway 和 HTTPRoute:
# nginx-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: nginx-gateway
namespace: nginx-demo
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
protocol: HTTP
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nginx-route
namespace: nginx-demo
spec:
parentRefs:
- name: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: nginx-service
port: 80
kubectl apply -f nginx-gateway.yaml
5. 验证应用部署
# 查看 Pod 分布
kubectl get pods -n nginx-demo -o wide
# 预期输出:6 个 Pod 分散在 5 个节点上
NAME READY STATUS NODE
nginx-app-7d8f9b2c5a-1x2y3 1/1 Running k8s-worker-1
nginx-app-7d8f9b2c5a-2a4b6 1/1 Running k8s-worker-2
nginx-app-7d8f9b2c5a-3c5d7 1/1 Running k8s-master-1
nginx-app-7d8f9b2c5a-4e6f8 1/1 Running k8s-master-2
nginx-app-7d8f9b2c5a-5g7h9 1/1 Running k8s-master-3
nginx-app-7d8f9b2c5a-6i8j0 1/1 Running k8s-worker-1
九、高可用验证测试
测试 1:控制平面故障容忍
# 在 Master-1 上停止 kubelet,模拟节点故障
sudo systemctl stop kubelet
# 在另一个终端继续操作集群
kubectl get nodes
# 应看到 k8s-master-1 变为 NotReady,但命令仍可执行
# 创建新的 Nginx Pod 测试
kubectl run nginx-test --image=nginx -n nginx-demo
# 应能成功创建,证明 API Server 仍通过 LB 由其他 Master 提供服务
测试 2:etcd Quorum 验证
# 查看 etcd 成员列表
kubectl exec -n kube-system etcd-k8s-master-2 -- \
etcdctl member list \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 停止一个 etcd 实例(模拟故障)
kubectl exec -n kube-system etcd-k8s-master-1 -- \
etcdctl endpoint health \
--endpoints=https://192.168.1.101:2379,https://192.168.1.102:2379,https://192.168.1.103:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 即使一个 etcd 挂掉,只要 2/3 存活,集群仍可用
测试 3:Worker 故障与 Pod 迁移
# 模拟 Worker-1 故障
kubectl cordon k8s-worker-1
kubectl drain k8s-worker-1 --ignore-daemonsets --delete-emptydir-data
# 观察 Pod 自动迁移
kubectl get pods -n nginx-demo -o wide -w
# 原 Worker-1 上的 Nginx Pod 会被重新调度到其他节点
十、关键最佳实践
-
证书备份:定期备份
/etc/kubernetes/pki目录,证书丢失将导致集群无法恢复 -
etcd 备份:每 6 小时执行一次快照:
sudo etcdctl snapshot save /backup/etcd-$(date +%Y%m%d%H%M).db \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key -
跨可用区部署:生产环境应将 3 个 Master 分布在不同 AZ/Rack
-
监控告警:使用 Prometheus 监控 etcd 集群健康、API Server 延迟、Controller Manager 选主状态
-
定期演练:每月执行一次故障注入测试(Chaos Engineering),验证自动恢复能力
总结
通过上述步骤,已成功构建了一个基于 kubeadm 的三 Master 高可用 Kubernetes 集群,并使用 Nginx 项目验证了工作负载的部署和调度。核心要点在于:
- 负载均衡器 提供稳定的
controlPlaneEndpoint,是所有节点访问 API Server 的统一入口 - Stacked etcd 自动形成三节点集群,通过 Raft 算法保证 (N-1)/2 的故障容忍
- 证书共享机制 通过
--upload-certs简化了多 Master 节点的加入流程 - 应用层反亲和性 配置确保工作负载分散,避免单点故障
这套架构可支撑生产级高可用需求,后续可根据业务规模扩展 Worker 节点或迁移到 External etcd 架构。