我在CCE被调度和探针连坑三次
线上背景和调度卡住
上周三 19:34,我把内部回调服务 notify-gateway 从一台 ECS 迁到华为云 CCE,区域 cn-south-1,集群版本 v1.25.6-r0,kubectl 客户端 v1.27.4,Helm v3.12.3。服务是 Java 17 + Spring Boot 3.1.2,镜像 624MB,启动时会从 OBS 拉一份 78MB 的 rules.json,然后预热 32 条 Redis 连接。集群只有 2 个工作节点,规格 c6.large.2(2 vCPU / 4GiB),系统盘 40GB 高IO,单价 0.39 元/小时,两台合计 0.78 元/小时。迁移前老 ECS 是 4C8G,单机跑了半年,P95 一直在 300ms 左右徘徊,我才决定拆到 K8s。
我给自己排了 30 分钟发布窗口,实际从 19:34 折腾到 22:52 才稳定,整整 3 小时 18 分钟,期间看了 4 次 helm history,release revision 从 17 滚到 23。
第一次发布命令是 helm upgrade --install notify-gateway ./chart -n biz -f values-prod.yaml --history-max 5 --timeout 10m。当时偷懒直接复用了另一个服务的 values,原始配置是下面这样:
replicaCount: 3
resources:
requests:
cpu: 1500m
memory: 2Gi
limits:
cpu: 2
memory: 2Gi
apply 后 6 分钟,3 个 Pod 全是 Pending,describe 里反复刷这条:
Warning FailedScheduling 5m default-scheduler 0/2 nodes are available: 2 Insufficient memory.
我又跑了 kubectl top node 和 kubectl describe node 10.0.3.21,节点 Allocatable 内存只有 3922Mi,kube-system 里的 coredns、everest-csi、log-agent、icagent 这些 DaemonSet 常驻后,单节点能给业务 Pod 的空间只剩 1.1Gi 到 1.3Gi。2Gi 的 requests 根本不可能调度成功,这不是调度器挑剔,是我填错了数量级。
我不是“改了一下”就结束,而是按启动阶段的真实占用重算:JVM -Xms256m -Xmx512m,本地缓存峰值 120Mi,Netty + 线程栈约 90Mi,再给 15% 抖动余量。Deployment 改成 requests cpu: 300m、memory: 512Mi,limits 改成 cpu: 1、memory: 1Gi,副本先保留 3,不动。命令是:
kubectl -n biz set resources deploy/notify-gateway \
--requests=cpu=300m,memory=512Mi \
--limits=cpu=1,memory=1Gi
40 秒内有两个 Pod 落在不同节点,第三个继续 Pending。我那会儿被旧事件误导,以为还是内存不够,临时把 limits 内存从 1Gi 降到 768Mi 试了一次,还手动触发 kubectl -n biz rollout restart deploy/notify-gateway,结果 11 分钟过去状态没有任何变化,这次尝试是纯失败,白白多等一轮镜像拉起。
那一刻我真想直接回滚到 ECS。
探针和反亲和返工
两个已调度 Pod 也没稳住,12 分钟里重启 19 次,状态在 Running 和 CrashLoopBackOff 之间来回跳。Events 里两类报错轮着来:
Readiness probe failed: Get "http://10.0.23.17:8080/health": dial tcp 10.0.23.17:8080: connect: connection refused
Liveness probe failed: HTTP probe failed with statuscode: 500
Container notify-gateway failed liveness probe, will be restarted
容器日志也很直白,我截了三行最关键的时间点:
2026-06-12 19:58:11.204 INFO RuleLoader : download obs://notify-prod/rules.json size=78MB cost=48721ms
2026-06-12 19:58:17.991 ERROR RedisHealthIndicator : RedisConnectionFailureException: Unable to connect to redis-master.biz.svc:6379
2026-06-12 19:58:18.002 INFO TomcatWebServer : Tomcat initialized with port 8080
我原来的探针配置是 initialDelaySeconds: 5、timeoutSeconds: 1,liveness/readiness 都打 /health。问题在于这个接口挂了 Redis 检查和规则加载状态,冷启动最慢能到 68 秒,5 秒就开始探测,kubelet 连续拿到 500 就重启,形成死循环。我还用 kubectl logs -f 对过一次,Pod 刚把 rules 下载到 60% 就被上一轮 liveness 杀掉了。
这个返工没有技术含量,纯粗心。
我先试过一次半吊子修法,只改 liveness 参数,不改路径:initialDelay 5 拉到 30,timeout 1 改 3。命令是:
kubectl -n biz patch deploy notify-gateway --type merge -p '{"spec":{"template":{"spec":{"containers":[{"name":"notify-gateway","livenessProbe":{"httpGet":{"path":"/health","port":8080},"initialDelaySeconds":30,"timeoutSeconds":3,"periodSeconds":10,"failureThreshold":3}}]}}}}'
结果重启次数从 19 次降到 7 次,但还是会死,原因没变:启动慢批次接近 68 秒,30 秒不够;而且 /health 依赖 Redis,Redis 抖一下就判死。21:02 我放弃这版,回到 Deployment 重配探针,具体做了三件事:加 startupProbe 兜启动窗口;readiness 改成 /ready;liveness 改成只看进程存活的 /live。配置如下:
startupProbe:
httpGet:
path: /live
port: 8080
failureThreshold: 30
periodSeconds: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 6
livenessProbe:
httpGet:
path: /live
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
改完我跑了 kubectl rollout status deploy/notify-gateway -n biz --timeout=180s,然后盯监控 25 分钟,重启计数停在 0。单个 Pod 从 ContainerCreating 到 Ready 的耗时在 61 到 66 秒,中位数 64 秒,比我预估慢 8 秒,但已经能稳定接流量。
第三个副本迟迟起不来,21:36 我才看到真正原因不是资源,而是反亲和规则:
Warning FailedScheduling 22s (x14 over 9m) default-scheduler 0/2 nodes are available: 2 node(s) didn't match pod anti-affinity rules.
我在 values 里写的是 requiredDuringSchedulingIgnoredDuringExecution,selector 是 app=notify-gateway,topologyKey 是 kubernetes.io/hostname。2 节点放 3 副本时,这条规则天然不可满足。测试环境一直是 2 副本,所以之前没暴露。我把 required 改成 preferred,weight 100,selector 不动,再跑一次 helm upgrade。22:04 第三个副本落地到 node-21,和一个旧副本同节点,这个取舍我接受。
22:52 我把流量切到 100%,观察到次日 10:00,4xx 在 0.18% 到 0.24%,5xx 没超过 0.03%,Pod 重启次数 0,P95 从发布前 312ms 降到 118ms。那晚多花的节点成本按 0.78 元/小时算,3.3 小时是 2.57 元;OBS 拉规则文件流量 0.41GB,内网计费几乎可以忽略。
还没解决的是 /ready 仍然依赖 Redis,昨天凌晨 03:17 Redis 主从切换 11 秒,3 个 Pod 同时变成 Unready。下周我会把就绪检查拆两层,/ready 只看进程和本地规则可服务,Redis 可用性移到独立告警指标里,不再直接参与摘流。
- 点赞
- 收藏
- 关注作者
评论(0)