CCE发布卡住后我改了探针和调度

举报
yd_292017662 发表于 2026/11/06 10:25:42 2026/11/06
【摘要】 这次记录的是我在华为云 CCE 给一个 Java 风控服务做版本发布时踩的两个坑:调度条件冲突导致滚动更新卡住,探针参数沿用旧值把新容器反复打死。我把当晚用到的 kubectl 命令、报错事件、YAML 片段、节点规格、耗时和额外费用都列出来,方便团队复盘。

上线窗口里发生的事

周二 19:40,我在华北-北京四把 prod-risk 命名空间里的 rule-engine 从 v1.7.3 升到 v1.8.0。集群是 CCE Turbo,Kubernetes v1.25.10-r0,containerd 1.6.20,3 台工作节点都在可用区 1,规格 c6.2xlarge.2,单机 8 vCPU、16 GiB,可分配 CPU 我现场查到大约 7600m。发布前副本数 4,我怕晚高峰把 replicas 提到 6,镜像还是 612 MB。执行命令是 helm 3.11.2:helm upgrade rule-engine ./chart -n prod-risk --wait --timeout 20m,我当时觉得 20 分钟很宽裕。

结果上线窗口被我拖到了 1 小时 12 分。

20:02 第一轮 rollout 卡住,控制台一直刷同一行:

kubectl -n prod-risk rollout status deploy/rule-engine --timeout=10m
Waiting for deployment rule-engine rollout to finish: 3 out of 6 new replicas have been updated...
error: timed out waiting for the condition

我一开始误判成镜像拉取慢,去看了 Pod 事件后才知道方向错了。真正的报错在 ReplicaSet:

kubectl -n prod-risk describe rs rule-engine-7c9df7f8d5 | grep -A6 Events
Warning  FailedScheduling  2m50s (x37 over 18m)  default-scheduler
0/3 nodes are available: 1 Insufficient cpu, 2 node(s) did not match Pod node affinity/selector.
preemption: 0/3 nodes are available: 1 No preemption victims found for incoming pod.

这锅就是我自己背。

Deployment 里我手动写了 nodeSelector: workload=batch,本意是把批处理和在线流量分开跑,但 batch 标签只打在 cce-worker-az1-02 一台节点。更要命的是 v1.8.0 把 requests.cpu 从 500m 提到 1200m,requests.memory 从 768Mi 提到 1024Mi。滚动策略还是 maxSurge:25%、maxUnavailable:25%,6 个副本会临时到 7 个,新版本峰值请求 CPU 是 7 x 1200m = 8400m。那台 batch 节点上已有两个 Kafka consumer,占了 3200m,请求总额直接溢出。

20:07 我先做了一个错误修复,只改滚动参数,没动 selector。命令是:

kubectl -n prod-risk patch deploy rule-engine --type merge -p '
spec:
  strategy:
    rollingUpdate:
      maxSurge: 0
      maxUnavailable: 1'

20:15 再看还是 Pending,事件里还是那句 2 台节点不匹配 selector、1 台 CPU 不够,这 8 分钟纯返工。

那一刻我手已经放在回滚按钮上了。

20:18 我把硬约束拿掉,改成软偏好,思路是优先 batch 节点但不锁死。具体改动是删除 nodeSelector,加 preferredDuringSchedulingIgnoredDuringExecution,weight=80;滚动参数保留 maxSurge:0、maxUnavailable:1。20:31 我用 kubectl -n prod-risk get po -l app=rule-engine -w 盯着看,新 Pod 全部调度成功,至少不再卡在 Pending。

affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 80
      preference:
        matchExpressions:
        - key: workload
          operator: In
          values: [batch]
strategy:
  rollingUpdate:
    maxSurge: 0
    maxUnavailable: 1

卡住后的排查和改动

调度问题刚落地,第二个坑马上来。Pod 起得来但 3 分钟内循环重启,READY 一直 0/1。我查应用日志没看到 panic,都是启动阶段拉 OBS 规则文件。文件总量 178 MB,34 个 JSON,路径 obs://risk-prod/rule-bundle/2026-03-18/。我抓了 6 次启动日志,下载耗时从 43 秒到 79 秒波动,后面 JVM 热身和索引构建还要 35 到 52 秒。一次完整样本是:

2026-03-19 20:34:11 INFO RuleSync download start, fileCount=34 totalBytes=186744912
2026-03-19 20:35:04 INFO RuleSync download done, costMs=53122
2026-03-19 20:35:41 INFO EngineWarmup finished, costMs=36987
2026-03-19 20:35:41 INFO HttpServer started on 0.0.0.0:8080

我之前偷懒沿用了 v1.6 的探针,配置太激进,启动慢一点就会被 kubelet 判死:

livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  initialDelaySeconds: 5
  periodSeconds: 10
  timeoutSeconds: 1
  failureThreshold: 3
readinessProbe:
  httpGet: { path: /ready, port: 8080 }
  initialDelaySeconds: 5
  periodSeconds: 5
  timeoutSeconds: 1
  failureThreshold: 2
Warning  Unhealthy  36s (x11 over 3m) kubelet
Liveness probe failed: Get http://10.244.3.19:8080/healthz: context deadline exceeded
Warning  BackOff  15s (x9 over 2m40s) kubelet
Back-off restarting failed container

我先做了一个失败尝试,只把 initialDelaySeconds 从 5 调到 30,timeoutSeconds 改成 2。20:44 那轮看起来好了一会儿,4 分 17 秒后 restartCount 还是从 0 涨到 3。后来我算了下窗口,30 秒延迟加 3 次失败,最晚撑到 60 秒左右,而慢节点启动会到 70 到 110 秒,这个改法根本没碰到根因。

20:52 我把探针拆成 startup、readiness、liveness 三段。startupProbe 走 /startup,failureThreshold:30、periodSeconds:5,给 150 秒预算;liveness 只看存活,不再承担启动判定;readiness 继续看 /ready,timeout 固定 2 秒。改完我手动滚了一次:kubectl -n prod-risk rollout restart deploy/rule-engine。6 个 Pod 首次 Ready 时间是 88s、91s、93s、94s、101s、128s,中位数 94 秒,10 分钟内重启次数从 6 次降到 0。

startupProbe:
  httpGet: { path: /startup, port: 8080 }
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 30
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3
readinessProbe:
  httpGet: { path: /ready, port: 8080 }
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 2

发布当晚我还临时加了一台同规格 c6.2xlarge.2 节点托底,21:05 开机,23:14 删除,这段 CCE 账单 1.91 元。镜像也做了返工,我把 tcpdump、vim、jcmd 从主镜像挪到调试 sidecar,Dockerfile 从单阶段改成 multi-stage,基础镜像从 eclipse-temurin:17-jdk 换成 eclipse-temurin:17-jre。v1.8.1 镜像变成 389 MB,在冷节点拉取均值从 68 秒降到 41 秒,SWR 出网增加 0.27 元。

资源参数我也回调过一版,把 requests.cpu 从 1200m 降到 800m,limit 保持 2000m,HPA 仍是 autoscaling/v2,目标 CPU 利用率 65%,minReplicas=4、maxReplicas=10。昨天 20:00 到 22:00 副本峰值 7,P99 延迟 143ms,故障前是 134ms,多出来 9ms;网关日志里能对上的 503 有 418 次,集中在 20:06 到 20:29。现在还没解决的是启动耗时抖动,最慢我见过 137 秒。下周我会把 34 个规则文件拆成 8 个分片,构建阶段预编译索引,再看能不能把 startupProbe 窗口从 150 秒收回到 90 秒以内;HPA 只看 CPU 还是慢半拍,我准备把队列积压长度通过 prometheus-adapter 接进来再跑一轮压测。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。