Kubernetes已成为容器编排的事实标准,但构建一个可用于生产环境的K8s集群并非易事。初次部署时,许多人按照官方文档执行kubeadm init,表面看似顺利,但在上线后却面临各种棘手问题:证书过期导致集群瘫痪、etcd数据丢失无法恢复、选错网络插件致使性能低下、Master单点故障引发业务中断……本文将系统梳理在企业级实践中积累的经验,帮助您规避常见陷阱。
一、概述
1.1 企业级集群核心要求
- 高可用:部署多副本Master节点,消除单点故障风险。
- 可扩展:能够便捷地添加或移除Worker节点。
- 安全:实施RBAC权限控制、网络策略隔离及镜像安全扫描。
- 可观测:建立完善的监控、日志收集与告警体系。
- 灾备:制定etcd定期备份与恢复策略,规划多集群容灾方案。
1.2 架构设计
一个典型的高可用K8s集群架构如下:
┌─────────────────┐
│ LoadBalancer │
│ (VIP: 10.0.0.100)│
└────────┬────────┘
│
┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
│ Master-1 │ │ Master-2 │ │ Master-3 │
│ (API+ETCD) │ │ (API+ETCD) │ │ (API+ETCD) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Node-1 │ │ Node-2 │ │ Node-3 │ │ Node-N │
│ Kubelet │ │ Kubelet │ │ Kubelet │ │ Kubelet │
│ CNI │ │ CNI │ │ CNI │ │ CNI │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
1.3 环境与规划
组件版本:
- 操作系统: CentOS 7.9 / Ubuntu 20.04+
- Kubernetes: 1.28+
- Container Runtime: containerd 1.7+ (自K8s 1.24起,不再内置Docker支持)
- 网络插件: Calico 3.26+
| 服务器规划: |
角色 |
主机名 |
IP |
配置 |
| Master-1 |
k8s-master-1 |
10.0.0.11 |
4C8G 100G |
| Master-2 |
k8s-master-2 |
10.0.0.12 |
4C8G 100G |
| Master-3 |
k8s-master-3 |
10.0.0.13 |
4C8G 100G |
| Node-1 |
k8s-node-1 |
10.0.0.21 |
8C16G 200G |
| Node-2 |
k8s-node-2 |
10.0.0.22 |
8C16G 200G |
| Node-3 |
k8s-node-3 |
10.0.0.23 |
8C16G 200G |
| VIP |
- |
10.0.0.100 |
负载均衡 |
二、详细部署步骤
2.1 系统初始化(所有节点执行)
◆ 基础配置
# 设置主机名(每台机器执行对应的)
hostnamectl set-hostname k8s-master-1
# 配置hosts
cat >> /etc/hosts << 'EOF'
10.0.0.11 k8s-master-1
10.0.0.12 k8s-master-2
10.0.0.13 k8s-master-3
10.0.0.21 k8s-node-1
10.0.0.22 k8s-node-2
10.0.0.23 k8s-node-3
10.0.0.100 k8s-api # VIP
EOF
# 关闭防火墙与SELinux(生产环境建议配置安全组规则)
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
# 关闭swap
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
free -h # 验证Swap为0
◆ 内核参数优化
cat > /etc/modules-load.d/k8s.conf << 'EOF'
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
cat > /etc/sysctl.d/k8s.conf << 'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
# 性能优化参数
net.ipv4.tcp_max_syn_backlog = 65535
net.core.somaxconn = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
fs.file-max = 655360
fs.inotify.max_user_watches = 524288
EOF
sysctl --system
◆ 安装Container Runtime
从K8s 1.24开始,推荐使用containerd作为容器运行时。
# 安装containerd
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y containerd.io
# 生成并修改配置
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 国内用户可替换sandbox镜像地址
sed -i 's|registry.k8s.io/pause:3.8|registry.aliyuncs.com/google_containers/pause:3.9|' /etc/containerd/config.toml
systemctl enable containerd && systemctl start containerd
ctr version # 验证
◆ 安装Kubernetes组件
# 添加阿里云仓库
cat > /etc/yum.repos.d/kubernetes.repo << 'EOF'
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0
systemctl enable kubelet
2.2 配置高可用负载均衡(在Master节点)
高可用是生产集群的基石。常见的方案有云厂商SLB、HAProxy + Keepalived以及kube-vip。这里以自建的HAProxy + Keepalived方案为例,部署在Master-1和Master-2上。
yum install -y haproxy keepalived
◆ HAProxy配置 (/etc/haproxy/haproxy.cfg)
global
log /dev/log local0
log /dev/log local1 notice
daemon
defaults
mode tcp
log global
option tcplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend kubernetes-apiserver
bind *:6443
mode tcp
option tcplog
default_backend kubernetes-apiserver
backend kubernetes-apiserver
mode tcp
option tcp-check
balance roundrobin
server k8s-master-1 10.0.0.11:6443 check fall 3 rise 2
server k8s-master-2 10.0.0.12:6443 check fall 3 rise 2
server k8s-master-3 10.0.0.13:6443 check fall 3 rise 2
listen stats
bind *:8080
mode http
stats enable
stats uri /stats
stats auth admin:admin123
◆ Keepalived配置与健康检查
这是一个经典的运维/DevOps高可用方案。
Master-1 (MASTER角色) 配置 (/etc/keepalived/keepalived.conf):
global_defs {
router_id LVS_K8S
}
vrrp_script check_haproxy {
script "/etc/keepalived/check_haproxy.sh"
interval 3
weight -20
}
vrrp_instance VI_1 {
state MASTER
interface eth0 # 修改为实际网卡
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass K8SHA_KA
}
virtual_ipaddress {
10.0.0.100/24 # VIP
}
track_script {
check_haproxy
}
}
Master-2 (BACKUP角色) 配置文件类似,需修改state BACKUP和priority 90。
健康检查脚本 (/etc/keepalived/check_haproxy.sh):
#!/bin/bash
if ! pidof haproxy > /dev/null; then
systemctl restart haproxy
sleep 3
if ! pidof haproxy > /dev/null; then
exit 1
fi
fi
exit 0
chmod +x /etc/keepalived/check_haproxy.sh
systemctl enable haproxy keepalived && systemctl start haproxy keepalived
# 验证VIP
ip addr show | grep 10.0.0.100
2.3 初始化Kubernetes集群
◆ 准备kubeadm配置文件 (kubeadm-config.yaml)
在Master-1上创建配置文件,特别注意certSANs字段需包含所有可能的访问地址。
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.0
controlPlaneEndpoint: "10.0.0.100:6443" # VIP地址
imageRepository: registry.aliyuncs.com/google_containers # 国内镜像源
networking:
dnsDomain: cluster.local
serviceSubnet: "10.96.0.0/12"
podSubnet: "10.244.0.0/16"
etcd:
local:
dataDir: /var/lib/etcd
apiServer:
certSANs:
- "10.0.0.100"
- "10.0.0.11"
- "10.0.0.12"
- "10.0.0.13"
- "k8s-api"
- "k8s-master-1"
- "k8s-master-2"
- "k8s-master-3"
extraArgs:
audit-log-path: /var/log/kubernetes/audit.log
audit-log-maxage: "30"
audit-log-maxbackup: "3"
audit-log-maxsize: "100"
controllerManager:
extraArgs:
bind-address: 0.0.0.0
scheduler:
extraArgs:
bind-address: 0.0.0.0
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 10.0.0.11 # 当前Master的IP
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
◆ 初始化第一个Master节点
# 预拉取镜像
kubeadm config images pull --config kubeadm-config.yaml
# 初始化集群
kubeadm init --config=kubeadm-config.yaml --upload-certs
初始化成功后,会输出用于加入集群的命令,请妥善保存。
# 配置kubectl
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes # 验证
◆ 加入其他Master及Worker节点
- 加入其他Master (在Master-2, Master-3上执行):
kubeadm join 10.0.0.100:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane \
--certificate-key <certificate-key>
同样需要复制admin.conf以使用kubectl。
- 加入Worker节点 (在所有Node上执行):
kubeadm join 10.0.0.100:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
2.4 安装CNI网络插件
集群初始化后,节点状态为NotReady,需安装网络插件。
# 安装Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
# 如果Pod CIDR不是默认的192.168.0.0/16,需要设置环境变量
# kubectl set env daemonset/calico-node -n kube-system CALICO_IPV4POOL_CIDR="10.244.0.0/16"
kubectl get pods -n kube-system -w # 等待Pod就绪
kubectl get nodes # 所有节点应变为Ready状态
2.5 基础功能验证
# 查看集群状态
kubectl get nodes -o wide
kubectl get pods -n kube-system
# 创建测试应用
kubectl run nginx --image=nginx:alpine
kubectl expose pod nginx --port=80 --type=NodePort
kubectl get svc nginx # 获取NodePort,通过<NodeIP>:<NodePort>访问
# 清理测试资源
kubectl delete pod,svc nginx
三、关键配置与避坑指南
3.1 证书过期管理(坑1)
K8s组件证书默认有效期为1年,过期将导致集群不可用。
# 查看证书有效期
kubeadm certs check-expiration
# 手动更新所有证书
cp -r /etc/kubernetes/pki /etc/kubernetes/pki.bak # 备份
kubeadm certs renew all
# 重启控制平面静态Pod
crictl pods --namespace kube-system | grep -E 'kube-apiserver|kube-controller|kube-scheduler|etcd' | awk '{print $1}' | xargs crictl rmp -f
cp /etc/kubernetes/admin.conf $HOME/.kube/config # 更新kubeconfig
# 推荐:设置每月自动更新的Cron任务
# 文件 /etc/cron.monthly/k8s-cert-renew
#!/bin/bash
kubeadm certs renew all
crictl pods --namespace kube-system | grep -E 'kube-apiserver|kube-controller|kube-scheduler' | awk '{print $1}' | xargs crictl rmp -f
3.2 etcd数据备份与恢复(坑2)
etcd存储了集群所有状态数据,必须定期备份。
#!/bin/bash
# /opt/scripts/etcd_backup.sh
BACKUP_DIR="/data/etcd-backup"
DATE=$(date +%Y%m%d_%H%M%S)
ETCDCTL_API=3
mkdir -p ${BACKUP_DIR}
etcdctl snapshot save ${BACKUP_DIR}/etcd-snapshot-${DATE}.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
# 验证备份文件
etcdctl snapshot status ${BACKUP_DIR}/etcd-snapshot-${DATE}.db
# 清理旧备份(保留7天)
find ${BACKUP_DIR} -name "*.db" -mtime +7 -delete
通过Cron设置每日备份:0 2 * * * /opt/scripts/etcd_backup.sh >> /var/log/etcd-backup.log 2>&1
3.3 集群健康检查脚本
#!/bin/bash
# k8s_health_check.sh
echo "========================================"
echo "K8s集群健康检查 $(date)"
echo "========================================"
echo ""
echo "=== 节点状态 ==="
kubectl get nodes -o wide
echo ""
echo "=== 系统Pod状态 ==="
kubectl get pods -n kube-system -o wide | grep -v Running
echo ""
echo "=== 异常Pod ==="
kubectl get pods -A | grep -v Running | grep -v Completed
echo ""
echo "=== etcd健康状态 ==="
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
echo ""
echo "=== 证书有效期 ==="
kubeadm certs check-expiration 2>/dev/null
echo ""
echo "=== 资源使用 ==="
kubectl top nodes 2>/dev/null || echo "需要安装metrics-server"
echo "========================================"
3.4 10大常见避坑总结
| 坑 |
问题描述 |
解决方案 |
| 1 |
证书1年过期,集群瘫痪 |
设置自动更新Cron任务 |
| 2 |
etcd数据丢失,集群无法恢复 |
每日定时备份etcd数据 |
| 3 |
Master单点故障 |
部署3节点高可用架构 |
| 4 |
Flannel网络性能不佳 |
生产环境推荐改用Calico |
| 5 |
网络插件CIDR配置不匹配 |
确保kubeadm-config.yaml中podSubnet与CNI插件配置一致 |
| 6 |
containerd未配置SystemdCgroup |
配置文件中设置SystemdCgroup = true |
| 7 |
未关闭swap导致kubelet启动失败 |
初始化前务必关闭swap |
| 8 |
国内环境拉取官方镜像失败 |
使用阿里云等国内镜像源 |
| 9 |
证书SAN列表不全,API访问失败 |
初始化时在certSANs中列出所有IP和域名 |
| 10 |
跨大版本升级导致兼容性问题 |
遵循官方指南,逐次小版本升级 |
四、生产环境最佳实践
4.1 节点与资源规划建议
集群规模参考:
- 小型集群 (<50 Pods): 3 Master, 3+ Worker, etcd内置。
- 中型集群 (50-500 Pods): 3 Master, 10+ Worker, etcd内置。
- 大型集群 (>500 Pods): 3 Master, 50+ Worker,考虑外置5节点etcd集群。
资源配置:
- Master节点: 小型4C8G,中型8C16G,大型16C32G。
- Worker节点: 通用型8C16G,计算密集16C32G,内存密集8C64G。
4.2 基础安全加固
# 1. 应用最小权限RBAC
kubectl create clusterrolebinding ops-admin \
--clusterrole=admin \
--user=ops@example.com
# 2. 配置默认拒绝所有流量的网络策略
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
EOF
# 3. 启用Pod安全标准 (PSA)
kubectl label namespace default pod-security.kubernetes.io/enforce=restricted
4.3 版本升级注意事项
升级应遵循“先Master后Node,逐版本进行”的原则。
# 查看可升级版本
yum list --showduplicates kubeadm
# 升级流程示例 (1.28 -> 1.29)
# 1. 升级第一个Master的kubeadm
yum install -y kubeadm-1.29.0
# 2. 检查升级计划
kubeadm upgrade plan
# 3. 执行升级
kubeadm upgrade apply v1.29.0
# 4. 升级其他Master
kubeadm upgrade node
# 5. 升级所有节点的kubelet和kubectl
yum install -y kubelet-1.29.0 kubectl-1.29.0
systemctl daemon-reload && systemctl restart kubelet
4.4 故障排查与监控部署
◆ 常用排查命令
kubectl describe node <node-name> # 节点详情
kubectl describe pod <pod-name> # Pod详情与事件
kubectl logs <pod-name> [-c <container>] # 查看日志
kubectl exec -it <pod-name> -- sh # 进入容器
kubectl get events --sort-by='.lastTimestamp' # 查看集群事件
journalctl -u kubelet -f # 查看kubelet日志
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml
# 若因证书问题无法连接,可编辑部署添加 `--kubelet-insecure-tls` 参数(仅限测试或内网环境)
# kubectl edit deployment metrics-server -n kube-system
kubectl top nodes # 验证资源监控
五、总结
构建企业级Kubernetes集群是一项系统工程,关键在于前期规划与对细节的把握。牢记高可用是基础、数据备份是保险、证书管理需重视、网络选择要谨慎、升级过程应稳妥。在掌握本篇部署与避坑要点后,可进一步探索GitOps(ArgoCD)、服务网格(Istio)、多集群管理等进阶主题,构建更加强大和智能的云原生基础设施。
附录:常用端口与命令速查
资源查看
kubectl get pods -A -o wide
kubectl get svc,deploy,sts -A