ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

集群排障中常见的配置误区

集群排障中常见的配置误区 集群排障中常见的配置误区Kubernetes 的配置项往往各自都说得通组合起来却可能引出可用性问题。比如节点平均 CPU 不高容器仍可能因限额被节流外部依赖变慢时错误的健康检查又会把本来还能处理请求的 Pod 反复重启。排障时不要只盯着某一个百分比或单条事件。需要把限额、探针、终止过程和应用自身的并发模型放在一起看。下面列出几类容易被误配的地方以及验证它们的办法。反模式一盲目设置 CPU Limit 导致严重的 CFS 节流CPU Throttling许多团队在编写 Deployment YAML 时习惯性地给每一个 Pod 加上严格的limits.cpu以为这样可以防止某个容器抢占宿主机资源。但这其实是对 Linux CFSCompletely Fair Scheduler调度器机制的误解。为什么 CPU 利用率不高却会变慢K8s 翻译limits.cpu: 2为 cgroups 里的cpu.cfs_quota_us限额和cpu.cfs_period_us时间周期通常为 100ms。如果limits.cpu 2意味着在每 100ms 的周期内该容器内的所有线程累计只能消耗 200ms 的 CPU 时间。如果应用是高并发多线程架构如 Java/Go可能在周期的前 15ms 内就把 200ms 配额用光了。在剩下的 85ms 里内核会**硬性挂起Throttle**该容器内的所有线程导致响应时间急剧飙升。诊断命令排查生产容器的 CPU Throttling不要只看kubectl top pod那只是平均值使用以下命令直接检查容器 cgroup 的底层统计# 进入 Pod 关联的 cgroup 目录 (cgroup v1 示例) kubectl exec -it payment-service-7d4b55c65f-x92zk -- cat /sys/fs/cgroup/cpu/cpu.stat # 输出示例 # nr_periods 10240 # 总周期数 # nr_throttled 3410 # 发生节流的周期数 # throttled_time 45200124100 # 被节流的总时间 (纳秒)这个比值只能作为线索还要结合请求延迟、运行队列和应用 CPU 使用情况判断不能用固定百分比直接定性。修正方案方案 A推荐只设置requests.cpu用于调度移除limits.cpu或者设置极高的 Limit依靠 Node 节点的 CPU 比例分配保障隔离性。方案 B引入 Kubernetes 1.22 的 CPU Manager对 latency-sensitive延迟敏感型 Pod 开启static策略实现独占 CPU 物理核。反模式二存活探针Liveness Probe配置误区与“死锁自杀循环”存活探针Liveness Probe的作用是当容器卡死死锁时让 kubelet 强行重启它。但在实际生产中很多团队误将 Liveness 探针配成了“依赖检查器”。生产失败案例某个 API 服务在/healthz接口中检查了下游 MySQL 和 Redis 的连接状态。当数据库由于慢查询导致连接池满时/healthz返回 500。kubelet 判定容器死亡执行kill -9并拉起新 Pod。新 Pod 启动后初始化再次尝试连接数据库探针再次返回 500。K8s 不断重启 Pod导致连接池彻底无机会恢复陷入死锁自杀循环。修正配置范例必须明确分工Liveness 只检查应用内部是否死锁Readiness 检查应用是否具备接流量能力Startup 负责慢启动掩护。apiVersion: apps/v1 kind: Deployment metadata: name: checkout-service spec: template: spec: containers: - name: app image: registry.internal.net/apps/checkout:v2.1.0 resources: requests: cpu: 2 memory: 4Gi limits: # 移除了 CPU limit防止 CFS 节流保留 Memory limit 防止 OOM 影响宿主机 memory: 4Gi # 1. 启动探针给 JVM / 深度学习模型加载预留足够时间 startupProbe: httpGet: path: /ping port: 8080 failureThreshold: 30 periodSeconds: 10 # 允许最多 300 秒的启动耗时 # 2. 存活探针仅探测内存死锁或 Goroutine 泄漏绝不检查外部数据库 livenessProbe: httpGet: path: /internal/health/liveness port: 8080 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3 # 3. 就绪探针检查数据库连接不就绪仅切断 Service 流量绝不重启 Pod readinessProbe: httpGet: path: /internal/health/readiness port: 8080 periodSeconds: 5 failureThreshold: 2反模式三忽略preStop钩子导致滚动更新时请求报错在进行 Deployment 升级时许多团队会收到前端反馈的零星502 Bad Gateway。产生根因当你执行kubectl apply时kubelet 接收到终止信号的同时K8s 也会从 Service 的 EndpointSlice 中异步移除 Pod IP。这两个动作是并行发起的。如果应用没有处理SIGTERM信号或者在收到信号时立即退出而上游 Nginx/Ingress Controller 还没来得及更新路由表后续流量依然会发送到已经死亡的 Pod 上修正方案增加preStop延时优雅停机停机逻辑应先停止接收新请求、等待在途请求结束再在终止宽限期内退出。固定sleep可以作为临时缓冲但应以实际摘流和连接排空的观测结果来调整lifecycle: preStop: exec: command: [/bin/sh, -c, sleep 15]生产排障极简命令行 CheckList当集群发生非预期 Pod 异常时请按顺序执行以下命令进行精确诊断# 1. 查看 Pod 状态变动历史与事件流 (重点看 Reason 和 Last State) kubectl get pod payment-service-xxx -o yaml | yq .status.containerStatuses # 2. 检索是否有因为 OOM 导致的强制 Kill 记录 kubectl describe node | grep -E OOMKilled|Out of memory # 3. 检查特定容器的优雅退出日志 kubectl logs payment-service-xxx --previous --tail200 | grep SIGTERM这些设置不能替代容量规划和演练但能让故障时的行为更可预测。每次调整后最好在预发布环境观察一次升级、依赖超时和资源紧张时的表现。
返回列表