title: “K8s 系列 | 第 2 天(重访):从单节点到生产级高可用集群:kubeadm 部署进阶与踩坑指南”
tags:
– Kubernetes
– K8s系列
– DevOps
– kubeadm
– 高可用集群
– 集群部署
– 生产运维
第 2/30 天(重访)
本文是 K8s 系列的第 2 天重访篇。原版第 2 天介绍了使用 kubeadm 搭建单节点集群的入门步骤,本文则聚焦于生产级高可用 Kubernetes 集群的部署实战,涵盖 HA 架构设计、etcd 集群化、Control Plane 负载均衡、Worker Node 加入以及常见踩坑解决方案。
一、引言
在入门阶段,我们使用 kubeadm init 快速启动了一个单节点集群,这对于学习和开发测试绰绰有余。然而,一旦要将 K8s 集群推向生产环境,单点故障就是最大的敌人——Control Plane 挂了,整个集群不可用;etcd 挂了,所有数据丢失。
生产级 Kubernetes 集群的核心要求:
| 要求 | 说明 |
|---|---|
| Control Plane 高可用 | 至少 3 个 Master 节点,通过负载均衡器分发请求 |
| etcd 集群化 | 奇数节点(3/5/7),Raft 共识保证数据一致性 |
| Worker Node 弹性 | 可动态扩缩容,与 Control Plane 解耦 |
| 证书与安全 | 生产级证书管理,RBAC 权限控制 |
本文将手把手带你从零搭建一个3 节点 Control Plane + 3 节点 Worker + 负载均衡器的生产级 K8s 集群。
二、架构设计
2.1 节点规划
| 角色 | 主机名 | IP 地址 | 配置 |
|---|---|---|---|
| LB | k8s-lb | 192.168.1.100 | 2C4G |
| Master-1 | k8s-m1 | 192.168.1.101 | 4C8G |
| Master-2 | k8s-m2 | 192.168.1.102 | 4C8G |
| Master-3 | k8s-m3 | 192.168.1.103 | 4C8G |
| Worker-1 | k8s-w1 | 192.168.1.201 | 8C16G |
| Worker-2 | k8s-w2 | 192.168.1.202 | 8C16G |
| Worker-3 | k8s-w3 | 192.168.1.203 | 8C16G |
2.2 架构拓扑
┌─────────────┐
│ Nginx LB │ ← 192.168.1.100:6443
│ (HAProxy) │
└──────┬──────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Master-1 │ │ Master-2 │ │ Master-3 │
│ k8s-m1 │◄─────►│ k8s-m2 │◄─────►│ k8s-m3 │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└───────────────────┼────────────────────┘
│
┌────────┴────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Worker-1 │ │ Worker-2 │ ...更多 Worker
└──────────┘ └──────────┘
三、前置准备
3.1 所有节点通用初始化
在所有 7 台机器上执行以下初始化操作:
# 1. 关闭交换分区(kubelet 强制要求)
swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab
# 2. 加载内核模块
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
# 3. 设置内核参数
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
# 4. 安装 containerd
apt-get update && apt-get install -y containerd
mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml
# 关键:修改 SystemdCgroup 为 true
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd
# 5. 安装 kubeadm、kubelet、kubectl
apt-get update && apt-get install -y apt-transport-https curl
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/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.30/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list
apt-get update && apt-get install -y kubelet=1.30.0-1.1 kubeadm=1.30.0-1.1 kubectl=1.30.0-1.1
apt-mark hold kubelet kubeadm kubectl
3.2 配置负载均衡器(LB 节点)
在 k8s-lb 节点上安装 HAProxy:
apt-get install -y haproxy
编辑 /etc/haproxy/haproxy.cfg:
global
log /dev/log local0
maxconn 2000
defaults
log global
mode tcp
option tcplog
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend k8s-api
bind *:6443
default_backend k8s-masters
backend k8s-masters
balance roundrobin
server master1 192.168.1.101:6443 check fall 3 rise 2
server master2 192.168.1.102:6443 check fall 3 rise 2
server master3 192.168.1.103:6443 check fall 3 rise 2
启动 HAProxy:
systemctl restart haproxy
systemctl enable haproxy
# 验证
curl -k https://192.168.1.100:6443/healthz
# 应返回 "ok"
四、初始化 Control Plane 集群
4.1 在 Master-1 上初始化第一个 Control Plane
# 创建 kubeadm 配置文件
cat > kubeadm-config.yaml << 'EOF'
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.1.101
bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: 1.30.0
controlPlaneEndpoint: 192.168.1.100:6443
apiServer:
certSANs:
- "192.168.1.100"
- "192.168.1.101"
- "192.168.1.102"
- "192.168.1.103"
- "127.0.0.1"
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOF
# 初始化
kubeadm init --config kubeadm-config.yaml --upload-certs
初始化成功后,会输出两条关键信息:
1. kubeadm join 命令(用于 Worker 节点加入)
2. kubeadm join 命令 + --control-plane --certificate-key(用于其他 Master 节点加入)
请务必保存这些输出! 如果丢失,可在 Master-1 上通过以下命令重新获取:
# 重新生成证书密钥
kubeadm init phase upload-certs --upload-certs
# 获取 token
kubeadm token create --print-join-command
4.2 配置 kubectl(Master-1 上执行)
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 验证
kubectl get nodes
kubectl get pods -n kube-system
4.3 安装 CNI 网络插件(Calico)
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/tigera-operator.yaml
cat > custom-resources.yaml << 'EOF'
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
ipPools:
- blockSize: 26
cidr: 10.244.0.0/16
encapsulation: VXLANCrossSubnet
natOutgoing: Enabled
nodeSelector: all()
---
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
name: default
spec: {}
EOF
kubectl create -f custom-resources.yaml
4.4 加入其余 Control Plane 节点
在 Master-2 和 Master-3 上分别执行:
kubeadm join 192.168.1.100:6443
--token <token>
--discovery-token-ca-cert-hash sha256:<hash>
--control-plane
--certificate-key <key>
⚠️ 关键踩坑点:如果
--control-plane加入失败,最常见的原因是证书密钥过期(有效期 2 小时)。解决方案是回到 Master-1 重新生成:kubeadm init phase upload-certs --upload-certs
4.5 加入 Worker 节点
在 Worker-1、Worker-2、Worker-3 上分别执行:
kubeadm join 192.168.1.100:6443
--token <token>
--discovery-token-ca-cert-hash sha256:<hash>
五、验证集群
# 查看所有节点状态
kubectl get nodes -o wide
# 预期输出示例:
# NAME STATUS ROLES AGE VERSION INTERNAL-IP
# k8s-m1 Ready control-plane 10m v1.30.0 192.168.1.101
# k8s-m2 Ready control-plane 8m v1.30.0 192.168.1.102
# k8s-m3 Ready control-plane 7m v1.30.0 192.168.1.103
# k8s-w1 Ready <none> 5m v1.30.0 192.168.1.201
# k8s-w2 Ready <none> 4m v1.30.0 192.168.1.202
# k8s-w3 Ready <none> 3m v1.30.0 192.168.1.203
# 验证 Control Plane HA
kubectl get endpoints -n kube-system kube-scheduler -o yaml | grep -A 10 subsets
# 部署测试应用验证功能
kubectl create deployment nginx --image=nginx:alpine --replicas=3
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get svc,deploy,pod -o wide
# 模拟 Master 节点故障测试
# 在 Master-1 上停止 kubelet:
# systemctl stop kubelet
# 此时 kubectl 应仍能正常使用(通过 LB 路由到其他 Master)
六、常见踩坑与解决方案
6.1 初始化卡在 [wait-control-plane]
现象:kubeadm init 卡在 [wait-control-plane] 阶段很久
原因:API Server 的健康检查端口无法访问,通常是容器运行时配置问题
解决:
# 检查 containerd 配置
cat /etc/containerd/config.toml | grep SystemdCgroup
# 必须为 true
# 检查 cgroup 驱动一致性
kubeadm config migrate
6.2 Pod 网络不通(CNI 问题)
现象:CoreDNS Pending 或 CrashLoopBackOff
原因:Pod CIDR 与 CNI 插件配置不匹配,或节点间网络不通
解决:
# 检查 Pod CIDR 是否与 CNI 配置一致
kubectl cluster-info dump | grep -m 2 cluster-cidr
# 检查节点防火墙
iptables -L -n | grep FORWARD | grep DROP
# 确保 FORWARD 策略为 ACCEPT
iptables -P FORWARD ACCEPT
6.3 证书过期
现象:kubectl 命令报证书相关错误
解决:
# 检查证书有效期
kubeadm certs check-expiration
# 更新证书
kubeadm certs renew all
# 重启组件
systemctl restart kubelet
6.4 重启后 kubelet 无法启动
现象:节点重启后 kubectl get nodes 显示 NotReady
原因:kubelet 启动顺序早于 containerd
解决:
# 设置依赖关系
cat > /etc/systemd/system/kubelet.service.d/20-depends.conf << 'EOF'
[Unit]
After=containerd.service
Requires=containerd.service
EOF
systemctl daemon-reload
七、总结
本文从零搭建了一个生产级 3+3 高可用 Kubernetes 集群,核心要点回顾:
| 要点 | 说明 |
|---|---|
| HA 架构 | 至少 3 个 Control Plane 节点 + 负载均衡器 |
| etcd 集群 | kubeadm 自动管理,确保奇数节点 |
| CNI 网络 | Calico 提供 VXLAN 跨子网通信 |
| 证书管理 | 定期检查证书有效期,提前续期 |
| 故障切换 | 任意 Master 节点宕机不影响集群 |
生产环境 Checklist:
– [ ] 是否配置了 HAProxy/Nginx 健康检查?
– [ ] 是否设置了证书自动续期(cronjob)?
– [ ] 是否启用了 etcd 定期快照备份?
– [ ] 是否配置了 Pod 资源限额?
– [ ] 是否安装了日志和监控组件?
下期预告
第 3 天(重访) 将深入探讨 Pod 进阶设计模式,包括 Init Container、Sidecar 模式、Security Context 与 Pod Security Standards,以及高级调度约束(NodeSelector / NodeName / Tolerations)。敬请期待!
系列目录
- 第 1 天(重访):Kubernetes 核心架构再探:控制平面工作原理与组件通信深度解析
- 第 2 天(重访):从单节点到生产级高可用集群:kubeadm 部署进阶与踩坑指南 ← 本文
- 第 3 天(重访):Pod 进阶:设计模式、安全策略与高级调度约束















暂无评论内容