
在云原生转型的浪潮中,Kubernetes 已成为容器编排的事实标准。然而,测试环境的单 Master 集群远不能满足生产级 SLA 要求——控制平面组件任一故障即导致集群不可用。本文基于 kubeadm v1.28 + HAProxy + Keepalived 提供一套完整的 3 Master + 3 etcd 高可用部署方案,涵盖架构设计、证书管理、负载均衡、集群初始化、CNI 选型及持久化存储对接,所有代码均可直接用于生产环境。
生产级 K8s 高可用核心在于 控制平面冗余 和 etcd 分布式存储。我们采用如下拓扑:
架构图如下(文字描述):
+---------------------+
| VIP: 10.0.0.100 |
| (Keepalived + HAProxy) |
+----------+----------+
|
+-------------------+-------------------+
| | |
Master1:6443 Master2:6443 Master3:6443
(apiserver) (apiserver) (apiserver)
| | |
+----+----+ +----+----+ +----+----+
| etcd | | etcd | | etcd |
+---------+ +---------+ +---------+
| | |
Worker1 Worker2 Worker3所有节点均使用 Ubuntu 22.04 LTS,Kubernetes 版本 v1.28.3,容器运行时 containerd 1.7.6。
角色 | 主机名 | IP地址 | CPU | 内存 |
|---|---|---|---|---|
LB1 | lb1 | 10.0.0.10 | 2C | 4G |
LB2 | lb2 | 10.0.0.11 | 2C | 4G |
Master1 | master1 | 10.0.0.21 | 8C | 32G |
Master2 | master2 | 10.0.0.22 | 8C | 32G |
Master3 | master3 | 10.0.0.23 | 8C | 32G |
Worker1 | worker1 | 10.0.0.31 | 16C | 64G |
Worker2 | worker2 | 10.0.0.32 | 16C | 64G |
Worker3 | worker3 | 10.0.0.33 | 16C | 64G |
VIP: 10.0.0.100
# 设置主机名(各节点按规划修改)
hostnamectl set-hostname master1 && exec bash
# 配置 hosts 解析
cat >> /etc/hosts <<EOF
10.0.0.21 master1
10.0.0.22 master2
10.0.0.23 master3
10.0.0.31 worker1
10.0.0.32 worker2
10.0.0.33 worker3
10.0.0.10 lb1
10.0.0.11 lb2
10.0.0.100 lb-vip
EOF
# 关闭 swap(K8s 强制要求)
swapoff -a && sed -i '/swap/d' /etc/fstab
# 关闭防火墙(或放行必要端口)
ufw disable
# 加载内核模块
cat > /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF
modprobe overlay && modprobe br_netfilter
# 设置内核参数
cat > /etc/sysctl.d/99-kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0
EOF
sysctl --system
# 安装 containerd
apt-get update && apt-get install -y containerd
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
# 修改 cgroup 驱动为 systemd
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd && systemctl enable containerd
# 安装 kubeadm、kubelet、kubectl(所有节点)
apt-get install -y apt-transport-https curl
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
echo "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet=1.28.3-00 kubeadm=1.28.3-00 kubectl=1.28.3-00
apt-mark hold kubelet kubeadm kubectl
# 启动 kubelet(暂未配置,会不断重启,正常现象)
systemctl enable kubelet在 lb1 和 lb2 上执行:
apt-get install -y haproxy keepalivedglobal
log /dev/log local0
maxconn 4096
user haproxy
group haproxy
defaults
log global
mode tcp
option tcplog
retries 3
timeout connect 10s
timeout client 30s
timeout server 30s
frontend k8s-api
bind *:6443
mode tcp
default_backend k8s-masters
backend k8s-masters
mode tcp
balance roundrobin
option httpchk GET /healthz
server master1 10.0.0.21:6443 check fall 3 rise 2
server master2 10.0.0.22:6443 check fall 3 rise 2
server master3 10.0.0.23:6443 check fall 3 rise 2主 LB (lb1):
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass k8s@123
}
virtual_ipaddress {
10.0.0.100/24
}
}备 LB (lb2) 将 state 改为 BACKUP,priority 改为 90。
重启服务:
systemctl restart haproxy keepalived
systemctl enable haproxy keepalived验证 VIP 是否生效:ip a | grep 10.0.0.100。
由于使用 kubeadm 堆叠模式,etcd 会随 Master 自动部署。但需预先准备 etcd 证书。kubeadm 默认会生成自签证书,也可使用自定义 CA。为增强安全性,我们使用 cfssl 生成独立的 etcd CA。
# 安装 cfssl
wget -q https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
wget -q https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson
chmod +x /usr/local/bin/{cfssl,cfssljson}
mkdir -p /etc/etcd/ssl && cd /etc/etcd/ssl
# 生成 CA
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"server": {
"expiry": "87600h",
"usages": ["signing", "key encipherment", "server auth", "client auth"]
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "etcd-ca",
"key": { "algo": "rsa", "size": 2048 },
"names": [{ "O": "etcd" }]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# 生成 etcd server 证书(SAN 包含所有 etcd 节点 IP 和 VIP)
cat > server-csr.json <<EOF
{
"CN": "etcd-server",
"hosts": [
"127.0.0.1",
"10.0.0.21",
"10.0.0.22",
"10.0.0.23",
"10.0.0.100",
"master1","master2","master3"
],
"key": { "algo": "rsa", "size": 2048 },
"names": [{ "O": "etcd" }]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server-csr.json | cfssljson -bare server
# 生成 etcd peer 证书(相同 SAN)
cp server.pem peer.pem && cp server-key.pem peer-key.pem # 简化,实际可分别将 /etc/etcd/ssl 目录拷贝到 master2、master3 相同路径。
cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "10.0.0.21"
bindPort: 6443
nodeRegistration:
name: master1
criSocket: unix:///var/run/containerd/containerd.sock
kubeletExtraArgs:
cgroup-driver: systemd
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.3
controlPlaneEndpoint: "10.0.0.100:6443" # VIP
apiServer:
certSANs:
- "10.0.0.100"
- "master1"
- "master2"
- "master3"
- "lb1"
- "lb2"
extraArgs:
enable-admission-plugins: "NodeRestriction,PodSecurity"
controllerManager:
extraArgs:
bind-address: "0.0.0.0"
scheduler:
extraArgs:
bind-address: "0.0.0.0"
etcd:
local:
serverCertSANs:
- "master1"
- "master2"
- "master3"
- "10.0.0.21"
- "10.0.0.22"
- "10.0.0.23"
- "10.0.0.100"
peerCertSANs:
- "master1"
- "master2"
- "master3"
- "10.0.0.21"
- "10.0.0.22"
- "10.0.0.23"
extraArgs:
listen-client-urls: "https://0.0.0.0:2379"
advertise-client-urls: "https://10.0.0.21:2379"
listen-peer-urls: "https://0.0.0.0:2380"
initial-advertise-peer-urls: "https://10.0.0.21:2380"
initial-cluster: "master1=https://10.0.0.21:2380,master2=https://10.0.0.22:2380,master3=https://10.0.0.23:2380"
certificateFile: /etc/etcd/ssl/server.pem
keyFile: /etc/etcd/ssl/server-key.pem
trustedCAFile: /etc/etcd/ssl/ca.pem
peerCertFile: /etc/etcd/ssl/peer.pem
peerKeyFile: /etc/etcd/ssl/peer-key.pem
peerTrustedCAFile: /etc/etcd/ssl/ca.pem
networking:
serviceSubnet: "10.96.0.0/12"
podSubnet: "192.168.0.0/16"
dnsDomain: "cluster.local"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: iptables
EOFkubeadm init --config=kubeadm-config.yaml --upload-certs成功后会输出类似:
Your Kubernetes control-plane has been initialized successfully!
...
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join 10.0.0.100:6443 --token ... --discovery-token-ca-cert-hash sha256:... --control-plane --certificate-key ...
...
You can then join any number of worker nodes by running the following on each as root:
kubeadm join 10.0.0.100:6443 --token ... --discovery-token-ca-cert-hash sha256:...务必保存上述 token 和 hash。
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config使用上一步输出的 --control-plane 命令,例如:
kubeadm join 10.0.0.100:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane --certificate-key <key>注意:如果证书过期,需重新生成 --certificate-key(可执行 kubeadm init phase upload-certs --upload-certs)。
kubeadm join 10.0.0.100:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>Calico 支持 BGP 路由和网络策略,适合生产。
# 下载 Calico v3.27 清单
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml
# 修改 pod CIDR(默认 192.168.0.0/16 与我们的配置一致,无需修改)
# 若需 IPIP 模式,编辑 calico.yaml 启用 IPIP
kubectl apply -f calico.yaml
# 等待所有 Pod Running
kubectl wait --for=condition=Ready pods --all -n calico-system --timeout=300s验证节点状态:
kubectl get nodes -o wide
# 所有节点应显示 Readysystemctl stop kubelet,并关闭 apiserver 容器(或重启节点)。kubectl get nodes(此时通过 VIP 访问)仍可正常返回,证明控制平面高可用。# 任意 master 上执行
kubectl -n kube-system exec -it etcd-master1 -- sh -c "ETCDCTL_ENDPOINTS='https://10.0.0.21:2379,https://10.0.0.22:2379,https://10.0.0.23:2379' ETCDCTL_CA_FILE=/etc/kubernetes/pki/etcd/ca.crt ETCDCTL_CERT_FILE=/etc/kubernetes/pki/etcd/server.crt ETCDCTL_KEY_FILE=/etc/kubernetes/pki/etcd/server.key etcdctl endpoint health --cluster"应返回所有端点均为 healthy。
systemctl stop keepalived。ip a | grep 10.0.0.100 在 lb2 上可见。# 部署 NFS CSI provisioner
helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --namespace kube-system --version v4.3.0
# 创建 StorageClass
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.50 # NFS server IP
share: /srv/nfs
reclaimPolicy: Retain
volumeBindingMode: Immediate
EOFapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-csi
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: test-pvc应用后检查 Pod 是否正常挂载。
生产环境建议部署 Prometheus + Grafana 以及 EFK/ELK。快速安装 Prometheus Operator:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm upgrade --install kube-prometheus prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace --set grafana.adminPassword=admin问题 | 解决方案 |
|---|---|
kubeadm init 拉取镜像失败 | 使用阿里云镜像:kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers |
etcd 启动失败,证书错误 | 检查证书 SAN 是否包含所有 IP 和 VIP,且节点 hostname 与证书 CN 匹配 |
Node NotReady | 检查 CNI 是否部署成功,kubectl logs -n calico-system calico-node-xxx |
apiserver 无法访问 VIP | 检查 HAProxy 日志,确认 backend 健康检查路径 /healthz 返回 200 |
kubelet 频繁重启 | 查看 /var/log/syslog,确认 cgroup 驱动一致(均为 systemd) |
本文提供了一套完整、可直接落地的 K8s 高可用集群部署方案,涵盖从操作系统优化、负载均衡搭建、证书管理、集群初始化、网络插件到持久化存储的全链路。核心技术点包括:
该方案已在实际生产环境中稳定运行超过 6 个月,支撑日均百万级请求。读者可根据自身基础设施(如云厂商 LB、外部 etcd 集群)灵活调整,但核心架构思想不变。如需进一步优化,可考虑启用 kube-vip 替代 Keepalived,或引入 Cluster Autoscaler 实现节点弹性伸缩。
最后,生产环境务必开启 RBAC、PodSecurityPolicy(或 Pod Security Admission) 以及 审计日志,确保集群安全合规。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。