gozero服务需按kubernetes要求暴露/healthz和/readyz探针、监听0.0.0.0、禁用cgo构建轻量镜像、严格匹配labels与端口、配置合理探针及优雅关闭,否则pod易卡在containercreating或crashloopbackoff。

GoZero 服务不是“部署到 Kubernetes”,而是按 Kubernetes 要求写对服务、打轻镜像、配准探针、写严 YAML —— 否则 Pod 会卡在 ContainerCreating 或反复 CrashLoopBackOff。
必须暴露 /healthz 和 /readyz 探针端点
Kubernetes 的 livenessProbe 和 readinessProbe 不会猜你的健康逻辑,只 HTTP GET 某个路径并看状态码。没这两个端点,Pod 很可能起不来,或刚 Ready 就被杀掉。
-
/healthz应只返回200,不做 DB 查询、不连下游——它只回答“进程还活着吗” -
/readyz可查 DB 连通性、Redis 是否可写,但超时别超过timeoutSeconds: 10 - 路径名必须和 Deployment YAML 中的
httpGet.path完全一致(比如 YAML 写/health,代码却只注册了/healthz,探针就永远 404) - 端口也要匹配:代码监听
:8080,YAML 的containerPort却写80,探针连不上
Dockerfile 必须用多阶段构建 + CGO_ENABLED=0
镜像太大不是“浪费空间”那么简单——它直接导致 ImagePullBackOff、节点磁盘爆满、CI 流水线卡住。
- 第一阶段用
golang:1.22-alpine,关键命令是:RUN CGO_ENABLED=0 GOOS=linux go build -a -o main . - 第二阶段必须用
scratch或alpine:latest,绝不能FROM golang直接跑 - 如果用了 cgo(比如
sqlite3或某些加密库),就不能用scratch,得保留alpine并apk add对应依赖 - 入口命令必须是
./main,不是go run main.go——后者会把整个 Go 工具链打进镜像
Deployment YAML 的 label 和 selector 必须严格匹配
这是最常被忽略却最致命的一环:label 写错一个字母、selector 多一个空格、app 和 app.kubernetes.io/name 混用,Service 就找不到 Pod,流量进不去。
- Pod template 中的
labels必须和 Deployment 的selector.matchLabels完全一致 - Service 的
selector必须和 Deployment 的selector.matchLabels完全一致(不是 template.labels) - go-zero 项目若用
goctl kube deploy生成 YAML,默认用app: your-service,别手动改成name: your-service - StatefulSet 场景下(如 etcd),
serviceName字段必须存在且与 Headless Service 名字一致,否则 DNS 解析失败
go-zero 的优雅关闭和信号处理不能省
没注册 SIGTERM 处理,Kubernetes 发送终止信号后,进程不等连接关闭就退出,造成请求 5xx 或超时;尤其在蓝绿/金丝雀发布时,问题立刻放大。
- 启动 server 前,用
signal.Notify监听os.Interrupt和syscall.SIGTERM - 收到信号后,调用
server.Shutdown()(go-zero 的rest.Server或rpc.Server都支持) - Shutdown 超时建议设为
30s,并在日志里打印 “shutting down…” 方便排查是否卡住 - 别依赖
defer清理资源——它只在函数退出时触发,而 Shutdown 是异步的
真正卡住部署的,往往不是 YAML 写错字段,而是探针路径和代码不一致、镜像里跑了 go run、或者 SIGTERM 根本没接住——这些地方一错,Kubernetes 就只会默默重试、重启、拉取失败,不会告诉你哪行代码没配对。











