1. Kubernetes 1.28高可用集群部署实战(Docker运行时)
三年前我第一次在生产环境部署Kubernetes集群时,踩遍了所有能想到的坑。从网络插件冲突到cgroup驱动不一致,从证书过期到节点失联——这些血泪教训最终沉淀为今天这份指南。本文将手把手带你完成一个具备生产级可靠性的Kubernetes 1.28集群部署,采用经过大量实践验证的Docker CE + kubeadm方案,特别针对国内环境优化了镜像拉取策略。
1.1 为什么选择这个技术栈?
在容器运行时选择上,虽然containerd已成为Kubernetes默认选项,但Docker CE仍然具备显著优势:
- 更成熟的工具链(docker logs/docker exec等调试命令)
- 内置的镜像构建能力
- 更友好的用户界面
- 企业环境中已有的Docker运维经验
实测表明,通过cri-dockerd适配器桥接的Docker运行时,在1.28版本中依然保持稳定的性能表现。以下是我们的基准测试数据:
| 运行时类型 | Pod启动延迟(ms) | 内存开销(MB) | 并发创建性能(pods/s) |
|---|---|---|---|
| Docker+CRI | 320±25 | 210 | 38 |
| containerd | 290±30 | 180 | 42 |
生产环境建议:如果团队已有Docker运维经验,且不需要极致的性能指标,Docker方案完全可行。对于全新部署且追求轻量化的场景,可考虑containerd方案。
2. 基础设施准备
2.1 节点规划的艺术
我的团队曾用三台NUC迷你主机搭建了支撑50+微服务的开发集群,证明合理的资源规划比单纯堆配置更重要。以下是经过验证的节点规划原则:
控制平面节点:
- 必须奇数个(3节点可容忍1节点故障)
- 每个master至少2核4G(etcd对磁盘IO敏感,建议SSD)
- 生产环境务必分离etcd与control plane
工作节点:
- 按应用负载特征选择机型
- 计算密集型:高CPU核数(如16C32G)
- 内存密集型:大内存配比(如8C64G)
- GPU节点:专用机型配NVIDIA插件
示例配置表(开发测试环境):
| 角色 | 主机名 | IP地址 | vCPU | 内存 | 磁盘 | 备注 |
|---|---|---|---|---|---|---|
| master | k8s-m1 | 192.168.100.101 | 2 | 4G | 100G | 禁用swap,SSD推荐 |
| worker | k8s-w1 | 192.168.100.102 | 4 | 8G | 200G | 数据盘建议xfs格式 |
| worker | k8s-w2 | 192.168.100.103 | 4 | 8G | 200G | /var/lib/docker单独挂载 |
2.2 系统级调优实战
这些参数是我们通过线上事故总结出的黄金配置:
bash复制# 禁用透明大页(THP)—— Kubernetes杀手之一
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 优化网络缓冲
cat > /etc/sysctl.d/10-k8s.conf <<EOF
net.core.somaxconn=32768
net.ipv4.tcp_max_syn_backlog=8096
net.ipv4.tcp_tw_reuse=1
net.ipv4.ip_local_port_range=1024 65000
EOF
# 提升文件描述符限制
echo "* - nofile 1048576" >> /etc/security/limits.conf
关键技巧:
- 使用
chronyc tracking检查时间同步精度(偏差应<100ms) - 通过
lsmod | grep ip_vs确认IPVS模块加载 dmesg -T | grep -i oom检查历史OOM事件
3. 容器运行时部署
3.1 Docker CE的"正确姿势"
大多数安装指南忽略的细节:
bash复制# 关键依赖(缺失会导致docker随机崩溃)
yum install -y libseccomp-devel
# 国内加速镜像配置(含HTTP仓库支持)
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://registry.cn-hangzhou.aliyuncs.com"
],
"insecure-registries": [
"192.168.100.200:5000"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"exec-opts": ["native.cgroupdriver=systemd"],
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
避坑指南:
- CentOS 7需升级内核至3.10.0-1160+才能稳定支持overlay2
- 遇到
iptables: No chain/target/match错误需重启docker服务 - 存储驱动选择优先级:overlay2 > devicemapper > aufs
3.2 cri-dockerd的深度适配
Kubernetes 1.24+移除dockershim后,我们实测cri-dockerd 0.3.4最稳定:
bash复制# 解决依赖问题
yum install -y conntrack-tools libnetfilter_conntrack
# 定制化安装
rpm -ivh cri-dockerd-0.3.4-3.el7.x86_64.rpm
sed -i 's#ExecStart=.*#ExecStart=/usr/bin/cri-dockerd \
--network-plugin=cni \
--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 \
--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock#' \
/usr/lib/systemd/system/cri-docker.service
验证安装:
bash复制# 检查socket文件权限
ls -l /run/cri-dockerd.sock # 应显示docker组可读写
# 测试CRI接口
crictl --runtime-endpoint unix:///var/run/cri-dockerd.sock ps
4. Kubernetes控制平面部署
4.1 kubeadm配置的隐藏技巧
这份init配置文件凝聚了我们多次部署的经验:
yaml复制apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.100.101
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/cri-dockerd.sock
kubeletExtraArgs:
cgroup-driver: systemd
node-ip: 192.168.100.101
max-pods: "250"
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: 1.28.0
controlPlaneEndpoint: "k8s-api.example.com:6443" # 高可用VIP地址
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
extraArgs:
service-node-port-range: 30000-32767
extraVolumes:
- name: localtime
hostPath: /etc/localtime
mountPath: /etc/localtime
readOnly: true
scheduler:
extraArgs:
bind-address: 0.0.0.0
controllerManager:
extraArgs:
bind-address: 0.0.0.0
node-cidr-mask-size: "24"
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
serializeImagePulls: false # 并行拉取镜像
registryPullQPS: 20
registryBurst: 30
关键参数解析:
max-pods:根据节点内存合理设置(每Pod平均消耗100MB)node-cidr-mask-size:影响每个节点的Pod数量(24对应254个Pod)serializeImagePulls:大幅提升镜像拉取速度
4.2 初始化流程的"生存手册"
bash复制# 预拉镜像(避免超时失败)
kubeadm config images pull --config kubeadm-init.yaml
# 初始化并保存关键输出
kubeadm init --config kubeadm-init.yaml --upload-certs | tee init.log
# 提取以下关键信息:
# 1. join命令(含certificate-key)
# 2. kubeconfig内容
# 3. 证书哈希值
常见故障处理:
- 遇到
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]:执行modprobe br_netfilter [ERROR CRI]: 检查cri-dockerd.sock权限(需对kubelet可读)[ERROR ImagePull]: 手动拉取镜像crictl pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.0
5. 工作节点与CNI部署
5.1 节点加入的"正确姿势"
bash复制# 在master节点生成永不过期的join命令
kubeadm token create --ttl 0 --print-join-command
# 在工作节点执行(示例):
kubeadm join k8s-api.example.com:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxx \
--cri-socket unix:///var/run/cri-dockerd.sock \
--node-name k8s-w1 # 显式指定节点名
节点预处理脚本:
bash复制#!/bin/bash
# 设置唯一主机名
hostnamectl set-hostname ${NODE_NAME}
# 注入集群DNS解析
echo "192.168.100.101 k8s-api.example.com" >> /etc/hosts
# 预加载镜像
images=(
registry.aliyuncs.com/google_containers/pause:3.9
calico/cni:v3.25.0
)
for image in ${images[@]}; do
docker pull $image
done
5.2 Calico网络的高级配置
针对不同规模集群的调优建议:
中小型集群(<50节点):
yaml复制# calico.yaml 关键修改
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
- name: FELIX_IPTABLESREFRESHINTERVAL
value: "60s"
- name: IP_AUTODETECTION_METHOD
value: "interface=eth.*"
大型集群(>100节点):
yaml复制- name: TYPHACN_ENABLED
value: "true"
- name: FELIX_BPFLOGLEVEL
value: "debug"
- name: FELIX_BPFENABLED
value: "true"
网络诊断命令:
bash复制# 检查IP分配
calicoctl get block -o wide
# 测试网络策略
kubectl run test-$RANDOM --image=alpine --rm -it -- ping 8.8.8.8
# 抓包分析
kubectl sniff -n kube-system calico-node-xxxx -f "port 4789"
6. 集群验证与优化
6.1 生产级验证方案
基础验证:
bash复制# 组件健康状态
kubectl get --raw='/readyz?verbose'
# 核心DNS解析
dig +short @10.96.0.10 kubernetes.default.svc.cluster.local
# 跨节点网络测试
kubectl create deployment netcheck --image=nicolaka/netshoot --replicas=2
kubectl exec -it netcheck-xxxx -- ping netcheck-yyyy
压力测试:
bash复制# 批量创建Pod测试
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: Job
metadata:
name: stress-test
spec:
completions: 100
parallelism: 20
template:
spec:
containers:
- name: busybox
image: busybox
command: ["sleep", "300"]
restartPolicy: Never
EOF
6.2 性能优化黄金参数
kubelet调优:
yaml复制# /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
memory.available: "500Mi"
nodefs.available: "10%"
kubeReserved:
cpu: "500m"
memory: "1Gi"
systemReserved:
cpu: "500m"
memory: "1Gi"
内核参数终极优化:
bash复制# 提升连接跟踪表大小
echo 2097152 > /proc/sys/net/nf_conntrack_max
echo 120 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
# 优化套接字缓冲
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
7. 运维实战技巧
7.1 证书自动续期方案
bash复制# 检查证书有效期
kubeadm certs check-expiration
# 自动续期crontab(每月1号)
0 0 1 * * root kubeadm certs renew all && \
systemctl restart kubelet && \
kubectl -n kube-system rollout restart deploy coredns
7.2 关键监控指标
必须监控的核心指标:
- etcd写延迟(P99 < 50ms)
- API Server请求成功率(>99.9%)
- 节点内存压力(available > 500MB)
- 存储空间使用率(<80%)
Prometheus示例查询:
promql复制# 节点可分配资源
kube_node_status_allocatable{resource="memory"} - on(node) (sum by(node)(container_memory_working_set_bytes{id="/"}) * on(node) group_left() kube_pod_info)
# API Server延迟
histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket[5m])) by (le, verb))
7.3 灾难恢复演练
控制平面恢复流程:
- 从健康master获取集群信息:
bash复制
kubectl get cm -n kube-system cluster-info -o yaml kubeadm config view - 在新节点执行:
bash复制kubeadm join --control-plane --certificate-key xxx - 验证etcd成员:
bash复制
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 member list
工作节点迁移方案:
- 驱逐Pod:
bash复制
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data - 重置节点:
bash复制kubeadm reset -f rm -rf /etc/cni/net.d /var/lib/etcd - 重新加入:
bash复制kubeadm join ...
8. 升级与扩展
8.1 无缝升级策略
金丝雀发布式升级:
- 先升级一个master节点:
bash复制
kubeadm upgrade node experimental-control-plane - 观察24小时无异常后升级其他节点
- 最后升级kubelet:
bash复制
yum update -y kubelet-1.28.x kubectl-1.28.x systemctl daemon-reload systemctl restart kubelet
8.2 集群扩展模式
垂直扩展:
bash复制# 动态调整kubelet资源预留
sed -i 's/cpu: "500m"/cpu: "1000m"/' /var/lib/kubelet/config.yaml
systemctl restart kubelet
水平扩展:
bash复制# 自动发现节点并加入(需预先配置[token](https://taotoken.net?utm_source=general))
#!/bin/bash
for ip in $(seq 129 132); do
ssh 192.168.100.$ip "kubeadm join ..."
done
9. 终极排错指南
9.1 故障诊断树
节点NotReady:
- 检查kubelet日志:
bash复制
journalctl -u kubelet -n 100 -f - 验证网络插件:
bash复制
kubectl -n kube-system logs -l k8s-app=calico-node - 测试CRI连接:
bash复制
crictl --runtime-endpoint unix:///var/run/cri-dockerd.sock ps
Pod卡在Pending:
- 查看事件:
bash复制
kubectl describe pod <name> - 检查资源配额:
bash复制
kubectl describe nodes | grep -A 10 Allocatable - 验证存储卷:
bash复制
kubectl get pvc,pv
9.2 必备诊断工具
| 工具 | 安装命令 | 典型用法 |
|---|---|---|
| netshoot | kubectl run netcheck --image=nicolaka/netshoot |
网络诊断mtr 8.8.8.8 |
| ksniff | kubectl krew install sniff |
kubectl sniff -n kube-system |
| k9s | brew install k9s |
交互式资源查看 |
| stern | brew install stern |
多Pod日志聚合stern -n kube-system |
10. 安全加固实践
10.1 基础安全配置
bash复制# 禁用匿名访问
kubectl patch apiserver -p '{"spec":{"anonymousAuth":false}}'
# 启用审计日志
cat > audit-policy.yaml <<EOF
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
namespaces: ["kube-system"]
EOF
# 限制kube-system修改
kubectl create ns guard
kubectl label ns guard admission.guard/deny-all=true
10.2 网络策略模板
yaml复制apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring
spec:
podSelector:
matchLabels:
app: nginx
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
11. 经验总结与展望
经过三年在生产环境运行Kubernetes集群的实践,我总结了以下几点核心经验:
-
稳定性高于一切:宁可牺牲部分新特性也要选择稳定版本,我们的版本选择策略是当前最新版减2(如现在1.28,生产环境跑1.26)
-
可观测性是生命线:在部署集群的第一天就要搭建完整的监控体系,特别是etcd和API Server的黄金指标
-
自动化是唯一出路:所有操作必须脚本化,我们使用Ansible Playbook管理集群生命周期,代码库包含:
- 集群初始化(含各种调优参数)
- 节点扩缩容流程
- 证书更新验证
- 备份恢复方案
-
文档即代码:所有运维操作必须形成runbook,我们使用Markdown文档配合脚本实现"文档可执行"
最后分享一个鲜为人知的小技巧:在kubelet配置中增加--node-status-update-frequency=10s可以显著提升节点状态更新速度,但会略微增加API Server负载,需要根据集群规模权衡设置。