必须设 CGO_ENABLED=0、GOOS=linux,Dockerfile 用多阶段构建并先复制 go.mod,运行时需信号处理与 graceful shutdown,HTTPS 证书须手动配置。

直接用 golang:alpine 构建镜像,不加多阶段、不关 CGO_ENABLED、不分离 go.mod,90% 的容器启动失败或运行时 panic 都源于这三点。
为什么 CGO_ENABLED=0 不是可选项而是必填项
Alpine 镜像用的是 musl libc,而默认 Go 编译(CGO_ENABLED=1)链接的是 glibc —— 二者不兼容。典型报错是:standard_init_linux.go:228: exec user process caused: no such file or directory,看着像路径错了,其实是动态库找不到。
- 即使你换 Ubuntu 基础镜像,也建议强制设为
0:静态二进制体积更小、无 libc 版本漂移风险、能塞进scratch镜像 -
GOOS=linux必须显式指定,否则本地 macOS/Windows 构建会产出非 Linux 可执行文件 - 别信“我本地跑得通”,容器里没
gcc、没pkg-config、没/usr/lib/x86_64-linux-gnu/,cgo 依赖的玩意儿全不存在
Dockerfile 多阶段构建必须拆开 go.mod 和源码复制
Docker 层缓存只对「指令顺序一致 + 文件内容未变」生效。如果把 COPY . . 放在 go mod download 前面,每次改一行代码都会让整个依赖下载步骤失效,构建时间从 3 秒拉长到 45 秒以上。
- 先
COPY go.mod go.sum ./,再RUN go mod download:只要依赖没变,这层就复用 - 源码
COPY . .放在下载之后:改业务代码不影响依赖层 - 构建阶段用
golang:1.23-alpine,运行阶段用alpine:latest或scratch:避免把go工具链打进生产镜像
Go 服务在容器里挂掉前不执行清理,等于没部署
Kubernetes 或 docker stop 默认发 SIGTERM,不是 SIGKILL。如果你的 main() 没监听这个信号,进程会被强制终止,活跃 HTTP 连接中断、DB 连接池没关闭、gRPC 客户端未 graceful shutdown —— 下游看到的就是 502/503。
立即学习“go语言免费学习笔记(深入)”;
- 必须用
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)捕获 -
http.Server.Shutdown()要传 context.WithTimeout,否则可能永远等不到连接结束 - DB 关闭、gRPC server.Stop()、消息队列 consumer.Close() 等操作,必须在
Shutdown()返回之后再执行,顺序不能反
运行时依赖如 HTTPS 或数据库证书容易被忽略
用 scratch 镜像最干净,但连 /etc/ssl/certs 都没有 —— 所有走 HTTPS 的请求(比如调第三方 API、连云数据库)会因证书验证失败而卡住或报 x509: certificate signed by unknown authority。
- 选
alpine:latest而非scratch时,记得加RUN apk --no-cache add ca-certificates - 用
scratch的话,得手动COPY证书文件,并通过GODEBUG=x509ignoreCN=0或自定义http.Transport注入根证书池 - 别在
builder阶段装ca-certificates:它不会自动复制到运行阶段
真正卡住人的从来不是“怎么写 Dockerfile”,而是编译参数、信号处理、证书路径这些散落在文档角落的硬性约束 —— 它们不报错,但会让服务在某个特定环境(比如 k8s rollout 或高并发压测时)突然失联。


















