系列说明本文是「K8s 避坑指南」系列第 3 篇。前两篇解决了环境搭建和开发阶段的问题这篇进入生产阶段专门对付那些能让整个集群直接挂掉的高危坑。生产环境的坑和开发不一样——开发踩坑顶多一个服务挂掉生产踩坑可能是整个集群不可用、数据丢失、凌晨三点电话打过来。这篇的 4 个坑每一个都是真实事故的来源。建议仔细读最好提前把预防措施做掉而不是等踩了再来看怎么恢复。坑 11节点变成 NotReady上面的 Pod 全被驱逐报错现象NAME STATUS ROLES AGE node-2 NotReady worker 15d某个节点突然变成 NotReady上面运行的 Pod 陆续出现Evicted或被调度到其他节点业务出现抖动。根本原因kubelet 无法在规定时间内默认 40s向 API Server 上报心跳节点被标记为 NotReady。实际根因排序如下根因占比特征节点磁盘满最常见/var/lib/containerd或/var/log撑满kubelet OOM 被杀常见dmesg 里有 OOM 记录网络中断偶发节点和 API Server 网络不通kubelet 进程崩溃较少systemctl status kubelet 显示 failed解决方案登录到问题节点上按顺序排查# 第一步检查 kubelet 状态和最近日志 systemctl status kubelet journalctl -u kubelet --since 1 hour ago | tail -200 # 第二步检查磁盘最常见 df -h # 重点关注以下路径所在分区的使用率 du -sh /var/lib/containerd # 镜像和容器层 du -sh /var/lib/kubelet # Pod 数据 du -sh /var/log # 系统日志 # 磁盘满了清理 containerd 悬空资源 crictl rmi --prune # 清理无用镜像 crictl rm $(crictl ps -a -q --state exited) 2/dev/null # 清理已退出容器 # 第三步检查内存和 OOM 记录 free -h dmesg | grep -i oom | tail -20 # 第四步检查网络连通性 curl -k https://apiserver-ip:6443/healthz # 处理完根因后重启 kubelet systemctl restart kubelet预防配置提前配好避免磁盘满了才发现# /var/lib/kubelet/config.yaml # kubelet 主动驱逐 Pod避免节点完全崩掉 evictionHard: memory.available: 200Mi # 内存剩余不足 200Mi 开始驱逐 nodefs.available: 10% # 磁盘剩余不足 10% 开始驱逐 nodefs.inodesFree: 5% imagefs.available: 15% # 镜像存储剩余不足 15% 开始驱逐坑 12etcd 磁盘写满集群进入只读模式报错现象所有写操作create、delete、apply、patch全部报错Error from server: etcdserver: mvcc: database space exceeded集群进入只读状态kubectl get还能用但任何变更操作全部失败相当于集群瘫痪。根本原因etcd 使用 boltdb 存储默认数据库文件上限是2GB写满后拒绝写入。常见导致写满的原因K8s Event 对象堆积默认每个 namespace 无限制频繁 apply 导致大量历史版本revision积累etcd 长期未做碎片整理已删数据占用的空间没有释放解决方案紧急恢复先让集群能写入# 设置 etcdctl 环境变量避免每次都写一长串参数 export ETCDCTL_API3 export ETCDCTL_CACERT/etc/kubernetes/pki/etcd/ca.crt export ETCDCTL_CERT/etc/kubernetes/pki/etcd/server.crt export ETCDCTL_KEY/etc/kubernetes/pki/etcd/server.key export ETCDCTL_ENDPOINTShttps://127.0.0.1:2379 # 查看当前数据库大小 etcdctl endpoint status --write-outtable # 消除告警让集群先恢复可写 etcdctl alarm disarm # 碎片整理释放已删数据占用的空间 etcdctl defrag --cluster # 再次确认大小已减小 etcdctl endpoint status --write-outtable清理 K8s Event最大的空间消耗源之一# 清理所有 namespace 的 Event kubectl delete events --all -A # 查看 etcd 里 events 占用情况 etcdctl get /registry/events --prefix --keys-only | wc -l长期预防配置# kube-apiserver 参数限制 Event 保留时间 --event-ttl2h # 默认 1h按需调整 # etcd 参数扩大数据库上限 --quota-backend-bytes8589934592 # 8GB # 生产建议每周执行一次碎片整理 # 写入 crontab 0 3 * * 0 etcdctl defrag --cluster /var/log/etcd-defrag.log 21坑 13证书过期集群突然完全不可用报错现象集群运行了大约一年某天所有 kubectl 命令突然报Unable to connect to the server: x509: certificate has expired or is not yet validAPI Server、etcd、控制器、调度器之间互相无法认证整个集群瘫痪。根本原因kubeadm 生成的 k8s 组件证书默认有效期是1 年。大多数团队安装完集群后就不管了直到一年后证书过期才发现集群挂了。这个坑非常阴——平时什么症状都没有过期那天直接宕。解决方案查看证书状态# 查看所有证书的过期时间kubeadm 1.15 kubeadm certs check-expiration # 输出示例 # CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY # admin.conf Nov 01, 2025 08:00 UTC invalid ca ← 已过期 # apiserver Nov 01, 2025 08:00 UTC invalid ca # apiserver-etcd-... Nov 01, 2025 08:00 UTC invalid etcd-ca续期证书# 一键续期所有证书kubeadm 1.15 kubeadm certs renew all # 续期后重启控制面组件static pod 会自动重启等待即可 # 手动确认重启完成 kubectl -n kube-system get pods | grep -E apiserver|controller|scheduler|etcd # 更新 kubeconfig续期后证书变了旧 config 失效 cp /etc/kubernetes/admin.conf ~/.kube/config预防提前告警不要等过期了才处理# 加入 crontab每月 1 日检查剩余不足 30 天则发告警 cat EOF /etc/cron.d/k8s-cert-check 0 9 1 * * root \ EXPIRE$(kubeadm certs check-expiration 21 | grep apiserver | grep -oP \dd); \ [ ${EXPIRE%d} -lt 30 ] \ echo K8s 证书将在 ${EXPIRE} 后过期请尽快续期 | \ mail -s [告警] K8s 证书即将过期 opsexample.com EOF重要kubeadm 1.21 的集群每次执行kubeadm upgrade时会自动续期证书。如果集群长期不升级就一定要手动续期或加自动续期脚本。坑 14滚动更新期间出现 502/503发布必然有抖动报错现象执行kubectl rollout restart deployment或部署新版本时监控上出现持续约 530s 的 502/503 报错尖刺客户端偶发请求失败。根本原因默认滚动更新配置下有两个导致请求失败的时间窗口旧 Pod 被删时仍在接流量kube-proxy 更新 iptables 规则有延迟约几秒旧 Pod 已收到 SIGTERM 开始关闭但 Service 还在把流量打过来。新 Pod 未就绪就接流量没配readinessProbePod 刚启动就被 Service 纳入但应用还没 ready。解决方案一个完整的「零抖动」Deployment 配置spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 # 不允许任何 Pod 不可用先起新的再删旧的 maxSurge: 1 # 允许多出 1 个 Pod保证容量不下降 template: spec: # 给 Pod 关闭留足时间排干存量请求 terminationGracePeriodSeconds: 60 containers: - name: app # readinessProbe 通过后才接流量这是零抖动的核心 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 3 failureThreshold: 3 lifecycle: preStop: exec: # 在进程收到 SIGTERM 之前先 sleep 等 kube-proxy 完成 iptables 更新 # 这 10s 是让 Service 把这个 Pod 摘掉所需的时间 command: [sleep, 10]为什么preStop: sleep 10有效Pod 删除流程是并行的kubelet 发 SIGTERM 和 Endpoint Controller 摘掉 Pod 是同时进行的但 Endpoint → kube-proxy → iptables 这条链路有延迟。preStop让进程在真正收到 SIGTERM 之前先等 10s这段时间 kube-proxy 的 iptables 更新已经完成新流量不再打进来再关闭进程处理存量请求就不会有 502 了。快速检查清单生产运维篇节点健康检查 □ df -h → 磁盘使用率 80% □ free -h → 内存有余量 □ systemctl status kubelet → 状态 active (running) □ kubectl get nodes → 所有节点 Ready etcd 健康检查 □ etcdctl endpoint health → 所有节点 healthy □ etcdctl endpoint status → db size quota 的 80% □ 是否有定期 defrag 计划 证书检查 □ kubeadm certs check-expiration → 所有证书剩余时间 30 天 □ 是否有证书到期告警机制 发布配置检查 □ maxUnavailable 0 □ readinessProbe 已配置 □ preStop sleep 已配置 □ terminationGracePeriodSeconds preStop sleep 时间小结这 4 个坑有一个共同特点平时没有任何征兆出事的时候影响面极大。证书过期、etcd 写满、节点磁盘满都是能让整个集群挂掉的级别。建议现在就去检查一下你的集群证书剩余时间和 etcd 数据库大小。下一篇预告系列收官最后一篇收录剩余 4 个坑——PVC 卡在 Terminating 删不掉、HPA 不生效、RBAC 权限踩坑、NetworkPolicy 配错服务不通。同时附上全系列的快速检查清单和高频 QA建议收藏。
K8s 生产集群炸了才知道的 4 件事:证书、etcd、节点、发布【系列三】
系列说明本文是「K8s 避坑指南」系列第 3 篇。前两篇解决了环境搭建和开发阶段的问题这篇进入生产阶段专门对付那些能让整个集群直接挂掉的高危坑。生产环境的坑和开发不一样——开发踩坑顶多一个服务挂掉生产踩坑可能是整个集群不可用、数据丢失、凌晨三点电话打过来。这篇的 4 个坑每一个都是真实事故的来源。建议仔细读最好提前把预防措施做掉而不是等踩了再来看怎么恢复。坑 11节点变成 NotReady上面的 Pod 全被驱逐报错现象NAME STATUS ROLES AGE node-2 NotReady worker 15d某个节点突然变成 NotReady上面运行的 Pod 陆续出现Evicted或被调度到其他节点业务出现抖动。根本原因kubelet 无法在规定时间内默认 40s向 API Server 上报心跳节点被标记为 NotReady。实际根因排序如下根因占比特征节点磁盘满最常见/var/lib/containerd或/var/log撑满kubelet OOM 被杀常见dmesg 里有 OOM 记录网络中断偶发节点和 API Server 网络不通kubelet 进程崩溃较少systemctl status kubelet 显示 failed解决方案登录到问题节点上按顺序排查# 第一步检查 kubelet 状态和最近日志 systemctl status kubelet journalctl -u kubelet --since 1 hour ago | tail -200 # 第二步检查磁盘最常见 df -h # 重点关注以下路径所在分区的使用率 du -sh /var/lib/containerd # 镜像和容器层 du -sh /var/lib/kubelet # Pod 数据 du -sh /var/log # 系统日志 # 磁盘满了清理 containerd 悬空资源 crictl rmi --prune # 清理无用镜像 crictl rm $(crictl ps -a -q --state exited) 2/dev/null # 清理已退出容器 # 第三步检查内存和 OOM 记录 free -h dmesg | grep -i oom | tail -20 # 第四步检查网络连通性 curl -k https://apiserver-ip:6443/healthz # 处理完根因后重启 kubelet systemctl restart kubelet预防配置提前配好避免磁盘满了才发现# /var/lib/kubelet/config.yaml # kubelet 主动驱逐 Pod避免节点完全崩掉 evictionHard: memory.available: 200Mi # 内存剩余不足 200Mi 开始驱逐 nodefs.available: 10% # 磁盘剩余不足 10% 开始驱逐 nodefs.inodesFree: 5% imagefs.available: 15% # 镜像存储剩余不足 15% 开始驱逐坑 12etcd 磁盘写满集群进入只读模式报错现象所有写操作create、delete、apply、patch全部报错Error from server: etcdserver: mvcc: database space exceeded集群进入只读状态kubectl get还能用但任何变更操作全部失败相当于集群瘫痪。根本原因etcd 使用 boltdb 存储默认数据库文件上限是2GB写满后拒绝写入。常见导致写满的原因K8s Event 对象堆积默认每个 namespace 无限制频繁 apply 导致大量历史版本revision积累etcd 长期未做碎片整理已删数据占用的空间没有释放解决方案紧急恢复先让集群能写入# 设置 etcdctl 环境变量避免每次都写一长串参数 export ETCDCTL_API3 export ETCDCTL_CACERT/etc/kubernetes/pki/etcd/ca.crt export ETCDCTL_CERT/etc/kubernetes/pki/etcd/server.crt export ETCDCTL_KEY/etc/kubernetes/pki/etcd/server.key export ETCDCTL_ENDPOINTShttps://127.0.0.1:2379 # 查看当前数据库大小 etcdctl endpoint status --write-outtable # 消除告警让集群先恢复可写 etcdctl alarm disarm # 碎片整理释放已删数据占用的空间 etcdctl defrag --cluster # 再次确认大小已减小 etcdctl endpoint status --write-outtable清理 K8s Event最大的空间消耗源之一# 清理所有 namespace 的 Event kubectl delete events --all -A # 查看 etcd 里 events 占用情况 etcdctl get /registry/events --prefix --keys-only | wc -l长期预防配置# kube-apiserver 参数限制 Event 保留时间 --event-ttl2h # 默认 1h按需调整 # etcd 参数扩大数据库上限 --quota-backend-bytes8589934592 # 8GB # 生产建议每周执行一次碎片整理 # 写入 crontab 0 3 * * 0 etcdctl defrag --cluster /var/log/etcd-defrag.log 21坑 13证书过期集群突然完全不可用报错现象集群运行了大约一年某天所有 kubectl 命令突然报Unable to connect to the server: x509: certificate has expired or is not yet validAPI Server、etcd、控制器、调度器之间互相无法认证整个集群瘫痪。根本原因kubeadm 生成的 k8s 组件证书默认有效期是1 年。大多数团队安装完集群后就不管了直到一年后证书过期才发现集群挂了。这个坑非常阴——平时什么症状都没有过期那天直接宕。解决方案查看证书状态# 查看所有证书的过期时间kubeadm 1.15 kubeadm certs check-expiration # 输出示例 # CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY # admin.conf Nov 01, 2025 08:00 UTC invalid ca ← 已过期 # apiserver Nov 01, 2025 08:00 UTC invalid ca # apiserver-etcd-... Nov 01, 2025 08:00 UTC invalid etcd-ca续期证书# 一键续期所有证书kubeadm 1.15 kubeadm certs renew all # 续期后重启控制面组件static pod 会自动重启等待即可 # 手动确认重启完成 kubectl -n kube-system get pods | grep -E apiserver|controller|scheduler|etcd # 更新 kubeconfig续期后证书变了旧 config 失效 cp /etc/kubernetes/admin.conf ~/.kube/config预防提前告警不要等过期了才处理# 加入 crontab每月 1 日检查剩余不足 30 天则发告警 cat EOF /etc/cron.d/k8s-cert-check 0 9 1 * * root \ EXPIRE$(kubeadm certs check-expiration 21 | grep apiserver | grep -oP \dd); \ [ ${EXPIRE%d} -lt 30 ] \ echo K8s 证书将在 ${EXPIRE} 后过期请尽快续期 | \ mail -s [告警] K8s 证书即将过期 opsexample.com EOF重要kubeadm 1.21 的集群每次执行kubeadm upgrade时会自动续期证书。如果集群长期不升级就一定要手动续期或加自动续期脚本。坑 14滚动更新期间出现 502/503发布必然有抖动报错现象执行kubectl rollout restart deployment或部署新版本时监控上出现持续约 530s 的 502/503 报错尖刺客户端偶发请求失败。根本原因默认滚动更新配置下有两个导致请求失败的时间窗口旧 Pod 被删时仍在接流量kube-proxy 更新 iptables 规则有延迟约几秒旧 Pod 已收到 SIGTERM 开始关闭但 Service 还在把流量打过来。新 Pod 未就绪就接流量没配readinessProbePod 刚启动就被 Service 纳入但应用还没 ready。解决方案一个完整的「零抖动」Deployment 配置spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 # 不允许任何 Pod 不可用先起新的再删旧的 maxSurge: 1 # 允许多出 1 个 Pod保证容量不下降 template: spec: # 给 Pod 关闭留足时间排干存量请求 terminationGracePeriodSeconds: 60 containers: - name: app # readinessProbe 通过后才接流量这是零抖动的核心 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 3 failureThreshold: 3 lifecycle: preStop: exec: # 在进程收到 SIGTERM 之前先 sleep 等 kube-proxy 完成 iptables 更新 # 这 10s 是让 Service 把这个 Pod 摘掉所需的时间 command: [sleep, 10]为什么preStop: sleep 10有效Pod 删除流程是并行的kubelet 发 SIGTERM 和 Endpoint Controller 摘掉 Pod 是同时进行的但 Endpoint → kube-proxy → iptables 这条链路有延迟。preStop让进程在真正收到 SIGTERM 之前先等 10s这段时间 kube-proxy 的 iptables 更新已经完成新流量不再打进来再关闭进程处理存量请求就不会有 502 了。快速检查清单生产运维篇节点健康检查 □ df -h → 磁盘使用率 80% □ free -h → 内存有余量 □ systemctl status kubelet → 状态 active (running) □ kubectl get nodes → 所有节点 Ready etcd 健康检查 □ etcdctl endpoint health → 所有节点 healthy □ etcdctl endpoint status → db size quota 的 80% □ 是否有定期 defrag 计划 证书检查 □ kubeadm certs check-expiration → 所有证书剩余时间 30 天 □ 是否有证书到期告警机制 发布配置检查 □ maxUnavailable 0 □ readinessProbe 已配置 □ preStop sleep 已配置 □ terminationGracePeriodSeconds preStop sleep 时间小结这 4 个坑有一个共同特点平时没有任何征兆出事的时候影响面极大。证书过期、etcd 写满、节点磁盘满都是能让整个集群挂掉的级别。建议现在就去检查一下你的集群证书剩余时间和 etcd 数据库大小。下一篇预告系列收官最后一篇收录剩余 4 个坑——PVC 卡在 Terminating 删不掉、HPA 不生效、RBAC 权限踩坑、NetworkPolicy 配错服务不通。同时附上全系列的快速检查清单和高频 QA建议收藏。