我在CCE被调度和探针连续绊倒

举报
yd_272744321 发表于 2026/11/04 11:16:11 2026/11/04
【摘要】 我把一个 Go 小服务迁到华为云 CCE,连续踩到调度和探针两个坑:反亲和写成硬约束导致 Pod 卡 Pending,探针又把启动中的容器反复杀掉。这里是我当晚的排查命令、配置差异、耗时和账单变化。

这次上线的基础环境和调度卡住

7月12日 20:41,我把内部短链服务 short-api 从两台 ECS 挪到华为云 CCE,集群在广州三区,版本 CCE v1.25.16-r0,containerd 1.6.28,节点池是 2 台 c6.large.2,2 vCPU/4 GiB,系统盘 40 GiB ESSD,按量单价 0.39 元/小时/台。镜像是 swr.cn-south-1.myhuaweicloud.com/team/short-api:v0.9.3,Go 1.21.6 编译,发布分支提交号 8e4c9d1,Deployment 里副本数写死 3,progressDeadlineSeconds 保持默认 600,没有改。我的目标就是把手工重启替换成滚动升级,别再靠凌晨 ssh 上去拉进程。

我那天晚上把自己值班时间从30分钟写成了2小时19分。

20:46 开始盯 rollout,连跑三次都卡住,我还把 --timeout 从 180 秒加到 300 秒,结果一样。命令和报错是这两段:

kubectl -n prod-short rollout status deploy/short-api --timeout=180s
Waiting for deployment 'short-api' rollout to finish: 1 out of 3 new replicas have been updated...
error: deployment 'short-api' exceeded its progress deadline

kubectl -n prod-short get deploy short-api -o wide
NAME        READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES
short-api   2/3     3            2           9m    short-api     ...:v0.9.3

我第一反应是镜像拉取慢,方向直接跑偏。20:49 到 20:51 我上节点看了 kubelet 和 containerd 的日志,Pulling image 到 Successfully pulled image 单次 10.8 秒和 11.3 秒,两个节点都差不多,根本不是瓶颈。这个误判白白浪费了 6 分钟。

20:52 我做了一个失败尝试,临时把副本缩到 2,想先把服务恢复再排查:

kubectl -n prod-short scale deploy/short-api --replicas=2
kubectl -n prod-short get deploy short-api -w

26 秒后 availableReplicas=2,我当时真以为结束了。21:03,HPA 同步周期到了,把副本重新拉到 3。我那时才想起来 HPA 配的是 minReplicas: 2、maxReplicas: 6、CPU target 55%,当前 CPU 61%,它把我的手工缩容覆盖掉完全合理。第三个 Pod 继续 Pending,故障原样返回,这 11 分钟也是白忙。

我去看事件才看到关键报错,调度器写得很直接:

kubectl -n prod-short describe pod short-api-7f5d9dff68-pt8rz

Warning  FailedScheduling  11m  default-scheduler
0/2 nodes are available: 2 node(s) didn't match pod anti-affinity rules.
preemption: 0/2 nodes are available: 2 No preemption victims found for incoming pod.

Deployment 里的反亲和是我自己写成了硬约束,两个节点最多放两个副本,第三个永远上不去。出问题的配置是:

affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchLabels:
          app: short-api
      topologyKey: kubernetes.io/hostname

这个方案我一开始是拒绝的。

我没马上扩节点,原因很现实,变更窗口只剩 40 分钟,我不想同时动集群容量和应用配置。21:18 我改 YAML,把 requiredDuringSchedulingIgnoredDuringExecution 改成 preferredDuringSchedulingIgnoredDuringExecution,加 weight: 100,语义从“必须分散”改成“尽量分散”。提交是 1f0a7bc,kubectl apply -f deploy.yaml 返回 configured。21:22 第三个 Pod 进入 ContainerCreating,21:23 变成 Running。单看调度这段,从第一次 rollout 卡住到恢复,用了 37 分钟。

探针返工、费用和还没收尾的部分

调度刚恢复,我又被探针绊住。Pod 状态在 Running 和 CrashLoopBackOff 之间来回跳,18 分钟里 restartCount 从 0 到 43。我用 kubectl -n prod-short get pod -w 盯着看,几乎每 70 到 90 秒重启一次,和 migration 耗时正好重叠。

kubectl -n prod-short logs short-api-7f5d9dff68-5kgpn --previous
2024-07-12T21:31:04.122+08:00 INFO db connected dsn=rds-mysql:3306
2024-07-12T21:31:04.124+08:00 INFO migration start version=202407101015
2024-07-12T21:32:16.873+08:00 INFO migration done cost=72.7s
signal: terminated

Warning Unhealthy: Liveness probe failed: Get 'http://10.247.2.19:8080/healthz': context deadline exceeded (Client.Timeout exceeded while awaiting headers)

Warning Unhealthy: Readiness probe failed: HTTP probe failed with statuscode: 404

问题有两个,都是我自己埋的。应用启动会跑 migration,最近 30 次启动平均 68 秒,最慢 91 秒;探针却是 initialDelaySeconds: 10、timeoutSeconds: 1、failureThreshold: 3,算下来 25 秒左右就会被判死。另一个是路径写错了,代码里只有 /readyz 和 /livez,没有 /healthz。我翻了 commit 记录,探针路径是从旧服务 copy 过来的,没对过路由表。

21:36 我做过一次小修,这次是明确失败的:把 readiness 路径改成 /readyz,把 initialDelaySeconds 从 10 拉到 45,其他参数没动,特别是 liveness 还在打 /healthz。我当时觉得“45 秒应该够了”,实际完全不够。6 分钟后 restartCount 从 43 涨到 57,事件里还是 context deadline exceeded 和 404 混在一起,说明我只修了一半。

现在回头看,这里有更稳的做法,我当晚选了发布风险最小的一条,把 migration 从主容器启动流程挪走,改成发布前 Job 单跑一次:

apiVersion: batch/v1
kind: Job
metadata:
  name: short-api-migrate-20240712
  namespace: prod-short
spec:
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: migrate
        image: swr.cn-south-1.myhuaweicloud.com/team/short-api:v0.9.3
        command: [./short-api, migrate, up]

这个 Job 跑了 74 秒,kubectl -n prod-short get job short-api-migrate-20240712 -o jsonpath='{.status.succeeded}' 返回 1,容器 exitCode 是 0,我才继续 rollout。探针我拆成 startup、liveness、readiness 三段,startup 给 150 秒窗口;liveness 和 readiness 全部改到真实存在的路径。资源也一起调高,requests 从 100m/128Mi 提到 300m/384Mi,limits 提到 1000m/768Mi,因为我在冷启动抓到过 930m CPU 峰值,旧 limits 把启动期压得很死。

startupProbe:
  httpGet:
    path: /livez
    port: 8080
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 30
livenessProbe:
  httpGet:
    path: /livez
    port: 8080
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3
readinessProbe:
  httpGet:
    path: /readyz
    port: 8080
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 2

我还在发布脚本里补了一条预检,避免再把不存在的路径写进探针:

kubectl -n prod-short run curl-tmp --rm -it --image=curlimages/curl:8.7.1 -- \
  curl -sS short-api.prod-short.svc.cluster.local:8080/readyz

整段故障从 20:41 到 23:00 才稳定,对内不可用 46 分钟。为保证副本先补齐,我在 21:40 把节点池临时扩到 3 台,第二天 23:50 缩回 2 台,多跑了 26 小时。账单上多出节点费用 10.14 元,CCE 管理费对应时段 4.68 元,LTS 新增日志 1.7 GiB 花了 0.61 元。排障群里我把截图贴出去的时候,心情确实不太好。

排查和回滚合计 2 小时 19 分,我手工敲了 28 条 kubectl 命令,Deployment 改了 4 次,HPA 改了 1 次,节点池改了 2 次。

现在调度和探针已经稳住,但 HPA 还是 CPU 单指标,流量突增时扩容慢 2 到 3 分钟。我下一步会把 QPS 和 p95 延迟接进自定义指标,再做一轮压测;另一个没收尾的是 PodDisruptionBudget,节点维护窗口还不敢开自动排空。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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