Kubernetes 集群节点生命周期管理实战:从扩容、调度管控到证书续期

Kubernetes 集群节点生命周期管理实战:从扩容、调度管控到证书续期

适用场景:基于 kubeadm 部署的生产级 K8s 集群(尤其适用于大规模 GPU / AI 计算集群)

操作风险:节点摘除涉及 Pod 驱逐,证书续期涉及控制面重启,务必在维护窗口执行

核心经验:多轮扩容必有 token 管理痕迹;证书续期必须所有 Master 节点都执行


一、背景与典型运维场景

在 AI/GPU 集群的日常运维中,节点的生命周期操作远比普通业务集群频繁:

  • 多轮扩容:业务增长导致需要分批加入大量 GPU 节点,每批使用不同 token
  • 节点维护:硬件故障、内核升级、驱动更新需要安全驱逐 Pod 并禁调度
  • 资源标记:不同批次、不同型号(如 A100-SXM4-80GB)的 GPU 需要精细化打标
  • 证书过期:kubeadm 集群运行一年后 API Server 证书过期,导致节点 NotReady

下面把实际用过的命令和手法按场景拆解。


二、节点加入:多轮扩容的正确姿势

2.1 标准 join 命令

bash 复制代码
kubeadm join api.k8s.local:8443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

2.2 多轮扩容的 token 管理

生产环境中经历过多次扩容,每轮都会生成新的 token。当 token 过期(默认 24 小时)或丢失时,需要在 Master 上重新生成:

bash 复制代码
生成新 token

kubeadm token create

获取 discovery-token-ca-cert-hash(如果没有现成的)

openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
  openssl rsa -pubin -outform der 2>/dev/null | \
  openssl dgst -sha256 -hex

💡 经验:大规模扩容时建议将 join 命令、token、hash 值按批次记录到运维文档中,方便回溯。


三、节点调度管控:cordon / drain / uncordon

3.1 禁止调度(Cordon)

维护前先让节点不再接收新 Pod:

bash 复制代码
#单节点
kubectl cordon <node-name>

#批量禁调度所有节点
kubectl cordon $(kubectl get nodes -o name)

#按 label 选择器批量禁调度
kubectl cordon -l gpu_type=nvidia_a100-80gb

3.2 安全驱逐(Drain)

bash 复制代码
节点下线或重启前的标准操作,驱逐现有 Pod 并确保服务不中断:

kubectl drain <node-name> \
  --delete-local-data \
  --force \
  --ignore-daemonsets

参数说明:

参数 作用
--delete-local-data 删除依赖本地存储的 Pod(如 emptyDir)
--force 强制驱逐不属于 RC/RS/DaemonSet 的裸 Pod
--ignore-daemonsets 忽略 DaemonSet 管理的 Pod(如 kube-proxy、日志采集)

3.3 恢复调度(Uncordon)

维护完成后重新开放节点:

bash 复制代码
kubectl uncordon <node-name>

四、节点标签管理:精细化资源标记

在 GPU/AI 集群中,标签是调度器识别硬件能力的关键依据。以下是实际环境中按批次、按硬件型号打标的完整示例:

#GPU 驱动与型号标记

bash 复制代码
kubectl label node <node-name> gpu_type=nvidia_a100-80gb

#网络加速能力标记

bash 复制代码
kubectl label node <node-name> accelerator/rdma=true

集群角色标记(多租户/多集群场景)

bash 复制代码
kubectl label node <node-name> ggg/role=eflops-gpu
kubectl label node <node-name> ggg/role=ai-cluster-gpu
kubectl label node <node-name> vgpu=true

扩容批次标记(用于按批次运维)

bash 复制代码
kubectl label node <node-name> kuorong=20240319

标签命名规范建议:

维度 示例 用途
硬件型号 gpu_type=nvidia_a100-sxm4-80gb 调度器按卡型分配任务
网络能力 accelerator/rdma=true 识别是否支持 RDMA 高速网络
业务角色 role=eflops-gpu 区分不同业务线的节点池
运维批次 kuorong=20240319 按扩容批次做批量操作

五、节点摘除与删除

节点彻底下线时的标准流程:

bash 复制代码
1. 先 drain 驱逐(如果节点还在线)
kubectl drain <node-name> --delete-local-data --force --ignore-daemonsets

2. 删除节点对象
kubectl delete node <node-name>

3. 在节点本机执行 kubeadm reset(如果节点还能登录)
kubeadm reset -f

六、kubeadm 证书续期(最容易翻车的维护项)

6.1 检查证书过期时间

bash 复制代码
kubeadm alpha certs check-expiration

输出会显示所有证书的过期时间,重点关注:

  • apiserver 证书(默认 1 年)
  • apiserver-kubelet-client
  • front-proxy-client
  • etcd-server / etcd-peer / etcd-healthcheck-client

6.2 执行续期

bash 复制代码
kubeadm alpha certs renew all

6.3 关键提醒:所有 Master 节点都要执行

这是生产环境最常见的坑:只在其中一台 Master 上续期证书,其他 Master 的 API Server 仍然使用旧证书,导致集群出现间歇性 NotReady。

正确流程:

bash 复制代码
1. 在每台 Master 上分别执行续期
kubeadm alpha certs renew all

2. 重启控制面组件(每台 Master 上)

如果是 static pod 方式(大多数 kubeadm 集群)
直接删除旧 pod 让 kubelet 重建
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/ && sleep 5 && mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/
mv /etc/kubernetes/manifests/kube-controller-manager.yaml /tmp/ && sleep 5 && mv /tmp/kube-controller-manager.yaml /etc/kubernetes/manifests/
mv /etc/kubernetes/manifests/kube-scheduler.yaml /tmp/ && sleep 5 && mv /tmp/kube-scheduler.yaml /etc/kubernetes/manifests/
  1. 验证
bash 复制代码
kubectl get nodes

七、踩坑清单

现象 排查方向
kubeadm join 报 token expired token 默认 24h 过期,重新 kubeadm token create
drain 卡住不动 有 Pod 没有 PodDisruptionBudget 或 PDB 限制太严,加 --pod-selector 缩小范围
uncordon 后 Pod 不回来 检查是否有其他 taint/toleration 限制,或资源不足
证书续期后 API Server 起不来 检查 /etc/kubernetes/pki 下证书是否真的更新了,确认所有 Master 都执行了
节点 join 后一直 NotReady 检查 CNI 插件是否正常、kubelet 是否运行、防火墙是否放行 10250
label 打了不生效 确认 label key 格式合规(DNS 子域名格式),检查调度器日志

八、小结

K8s 节点生命周期管理的核心经验:

  1. 扩容有痕:每轮 join 的 token 和节点清单做好记录,方便回溯和排错
  2. 摘节点先 cordon 再 drain:顺序不能反,参数不能省
  3. 标签是调度的基石:GPU 型号、RDMA 能力、批次信息全部通过 label 表达
  4. 证书续期要全量:所有 Master 节点都要执行,且要重启控制面组件

相关推荐
YYYing.4 小时前
【K8s系列 (一) 】Docker与容器(上篇)
docker·云原生·容器·kubernetes
csdn_aspnet4 小时前
使用 Docker 和 RedisInsight 设置 Redis 以进行本地开发
redis·docker·容器·redisinsight
AR-26710-5 小时前
Linux Day31——实操启停服务改端口重启
linux·运维
百度Geek说5 小时前
QCon上海2026:百度 SRE Agent 规模化落地实践解读
运维·自动化运维
叼烟扛炮5 小时前
Linux 学习笔记(五十八):IO 多路复用封神——epoll 底层原理揭秘
linux·运维·服务器·网络·笔记·学习·php
分布式存储与RustFS8 小时前
给 RustFS 桶加一层内存缓存:用 Alluxio 让热数据少跑一遍网络
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
余槐i9 小时前
MySQL 8.0 联合索引走错:为什么加了索引查询反而从 200ms 变成 8s
java·spring boot·mysql·docker·性能优化
csdn_aspnet9 小时前
如何在本地 Docker 容器中运行 Redis,并使用 Redis Insight 和 Redis CLI 进行管理
redis·docker·容器
Decay__10 小时前
22_MySQL 运维自动化平台 —— 部署编排 + 监控 + 巡检 + 告警 + 工单闭环一体化
运维·数据库·sql·mysql·架构