go服务必须监听0.0.0.0而非localhost,容器间通信依赖自定义bridge网络和服务名dns解析,depends_on不保证服务就绪,需健康检查重试;多阶段构建推荐golang:alpine编译+alpine:latest运行并安装ca-certificates。

用 docker-compose 搭多容器 Go 环境,核心不是“能不能跑”,而是“服务间能不能稳定通信”——绝大多数失败都卡在容器网络互通和启动时序上。
Go 服务监听地址必须是 0.0.0.0,不能写 localhost 或 127.0.0.1
这是最常踩的坑。Go 代码里写 http.ListenAndServe("localhost:8080", nil),容器内其他服务(比如 user 调 auth)会连不上,因为 localhost 在容器里指向自己,不是宿主机或同网段其他容器。
- 正确写法:
http.ListenAndServe(":8080", nil)(冒号开头即默认绑定所有接口)或显式写"0.0.0.0:8080" - Docker 默认给每个服务分配独立网络命名空间,
localhost是隔离的,没意义 - 验证方式:进容器执行
netstat -tuln | grep :8080,看到0.0.0.0:8080才算生效
depends_on 只控制启动顺序,不保证依赖服务已就绪
depends_on 在 docker-compose.yml 里只是让容器按顺序 docker start,但 Go 服务可能还在初始化 DB 连接、加载配置、预热缓存——此时发起 HTTP 调用大概率报 connection refused。
- 不要依赖
depends_on做服务可用性判断 - 在 Go 代码里加重试逻辑:比如用
backoff.Retry或简单轮询http.Get("http://user:8080/health")直到返回 200 - 或者用
wait-for-it.sh脚本包装CMD,例如:CMD ["./wait-for-it.sh", "user:8080", "--", "./main"] - 健康检查端点建议用轻量 handler,不查 DB,只返回
200 OK
容器间调用必须用服务名 + 内部端口,不是宿主机映射端口
Docker Compose 自动创建一个用户定义桥接网络,并内置 DNS,把每个 service 名解析成对应容器 IP。你写的 http://user:8080/api/users 是对的;但写成 http://localhost:8081/api/users 或 http://host.docker.internal:8081 就错了。
- 服务名来自
docker-compose.yml的services:下一级 key,比如user:→ 就用user - 端口填容器内部暴露的端口(
EXPOSE 8080),不是ports: ["8081:8080"]里的左边那个 - 环境变量传地址时也照此格式:
USER_SERVICE_URL=http://user:8080,别带http://localhost - 如果跨 compose 文件或混合部署,才考虑
network_mode: host或自定义网络,但会牺牲隔离性
多阶段构建推荐用 golang:1.x-alpine + alpine:latest 组合
镜像体积和运行时兼容性得兼顾。用 golang:1.23(Debian 基础)编译没问题,但最终运行镜像若直接基于它,会多出一堆用不到的 dev 工具和 libc;而纯 alpine 又可能缺 ca-certificates 导致 HTTPS 请求失败。
- 构建阶段用
golang:1.23-alpine:轻量、快、CGO_ENABLED=0 友好 - 运行阶段用
alpine:latest+apk add ca-certificates:最小体积,支持 TLS - 务必加
CGO_ENABLED=0 GOOS=linux GOARCH=amd64编译,避免运行时找不到动态库 - 如果项目用了 cgo(如 SQLite、某些加密库),就得保留
glibc或切回debian:slim基础镜像
真正麻烦的从来不是写几行 docker-compose.yml,而是当 user 服务反复重启、auth 报 connection refused、日志里只有一行 Get \"http://user:8080/health\": dial tcp: lookup user on 127.0.0.11:53: no such host 的时候——那八成是服务名拼错了,或者 docker-compose.yml 里少了个 networks: 配置让它们不在同一个网络里。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











