应优先用 docker-compose 快速验证服务基础行为,再迁移到 kubernetes;需确保端口监听、健康探针、信号处理等逻辑正确,镜像构建须用多阶段+cgo_enabled=0,资源限制需配 gomemlimit。

用 docker-compose 快速验证服务行为,别一上来就写 YAML
本地开发阶段硬套 Kubernetes YAML 是低效的。Kubernetes 的 Deployment、Service、ConfigMap 等资源在测试环境里要反复改、反复 apply,而 docker-compose 可以 5 秒内启停、改配置不重装、天然支持多服务联调。
关键不是“跳过 Kubernetes”,而是把验证环节前移:先确保 Go 服务本身能正确监听端口、响应 /healthz 和 /readyz、接受 SIGTERM 并完成 http.Server.Shutdown() —— 这些逻辑跟 Kubernetes 无关,但错一个,上线后就是 CrashLoopBackOff 或流量中断。
-
docker-compose.yml中直接映射8080:8080,用curl -v http://localhost:8080/readyz手动触发检查,比等 kubectl wait 更快 - 在
main.go启动前加log.Printf("listening on %s", addr),避免因端口被占或 bind 失败却无日志 - 用
kill -TERM $(pidof main)模拟 Kubernetes 发送的信号,确认Shutdown()是否真正阻塞并等待请求结束
Deployment YAML 必须填满这 4 个字段,少一个 Pod 就起不来
Kubernetes 不会猜你要什么。Deployment 资源一旦创建,spec.selector.matchLabels 就不可变;如果 Pod template 里的 labels 缺字段、值不一致,新 Pod 永远不会被纳入 Service 流量,也不会被旧 ReplicaSet 清理。
-
spec.selector.matchLabels和template.metadata.labels必须完全相同(包括字段名和值),例如都写{app: "user-svc"} -
containers[].ports[].containerPort必须和 Go 代码中http.ListenAndServe(":8080")的端口一致,且Service.spec.ports.targetPort要和它对齐 -
resources.requests和resources.limits必须显式设置,否则调度器无法分配节点,尤其在测试集群资源紧张时容易卡在Pending -
livenessProbe.initialDelaySeconds至少设为5,否则探针在 server 还没 bind 完就发起请求,直接失败 → 重启循环
健康探针路径和语义必须严格分离,共用一个端点是线上事故高发区
livenessProbe 和 readinessProbe 不是“写两个一样的 HTTP 接口”就行。Kubernetes 对它们的处置逻辑完全不同:liveness 失败会强制杀 Pod 并重建,readiness 失败只是摘流量——但如果你把 DB 连通性检查塞进 /healthz,一次数据库抖动就会触发全量 Pod 重启,进而压垮 DB。
-
livenessProbe指向/healthz:只返回200,不做任何依赖检查(连日志都不建议打) -
readinessProbe指向/readyz:可查db.Ping()、redis.Conn().Ping(),但别做耗时操作(如长事务、大查询) - 两者
timeoutSeconds应不同:liveness设为2,readiness设为10,防止滚动更新时 readiness 延迟导致流量被误摘 - 务必设
failureThreshold: 3,避免 GC STW 或短暂网络抖动造成误判
镜像构建必须用多阶段 + CGO_ENABLED=0,否则 Alpine 下直接报 no such file or directory
很多测试环境用 FROM golang:alpine 直接跑 go run main.go,结果部署到 Kubernetes 就卡在 ContainerCreating,日志里只有 standard_init_linux.go:228: exec user process caused: no such file or directory —— 这是典型的 musl libc 和 glibc 链接冲突。
- 第一阶段用
golang:1.22-alpine编译,RUN 行必须显式写CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" -o main . - 第二阶段用
scratch或gcr.io/distroless/static:nonroot,COPY 二进制文件,ENTRYPOINT 设为["/main"](不是./main),确保 PID 1 是你的进程,信号才能正常转发 - 别在 Dockerfile 里写
go run或go build后不清理中间产物,镜像体积膨胀会拖慢测试环境拉取速度,甚至触发ImagePullBackOff
resources.limits.memory: "256Mi",Go 的 GC 仍可能尝试申请超限内存,最终被 OOMKilled。解决方案是启动前设环境变量 GOMEMLIMIT="204Mi"(cgroup limit 的约 80%),这个值必须和 YAML 中的 limits 保持比例关系,不能靠猜。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











