最可靠方式是用 docker-compose.yml 编排多个 Go 服务,Go 服务须监听 0.0.0.0:PORT 而非 localhost:PORT,容器间通过服务名(如 http://auth:8080)调用,配合环境变量传参、多阶段 Alpine 构建及健康等待机制。

直接用 docker-compose.yml 编排多个 Go 服务最可靠,比本地跑一堆进程+端口映射更接近真实部署场景,也规避了“在我机器上能跑”的环境差异问题。
Go 服务必须监听 0.0.0.0:PORT,不能写 localhost:PORT
这是容器间调用失败的头号原因。Docker 内部网络中,localhost 指向容器自身,其他服务根本连不上你。
-
http.ListenAndServe("localhost:8080", nil)→ 其他容器访问会超时 -
http.ListenAndServe("0.0.0.0:8080", nil)→ 正确,允许所有网络接口接入 - 如果用了
gin、echo等框架,也要检查其启动方式是否隐式绑定了127.0.0.1(比如某些版本的gin.Run()默认如此) - 建议显式传参:
router.Run("0.0.0.0:8080")或通过环境变量控制绑定地址
服务名即 DNS 名,容器内调用直接用 http://service-name:PORT
Docker Compose 自动为每个 service 创建 DNS 记录,无需硬编码 IP 或改 /etc/hosts。
- 在
docker-compose.yml中定义服务名为auth,其他 Go 服务里发 HTTP 请求就写http://auth:8080/login - 该域名只在 Docker 内部网络生效,宿主机浏览器无法直连(要走
ports映射) - 不要依赖
depends_on来判断服务是否“已就绪”——它只控制启动顺序,不等待服务端口真正监听成功 - Go 代码里需自行实现重试逻辑,或引入
wait-for-it.sh脚本做健康等待
多阶段构建 + Alpine 镜像,减小体积且避免运行时污染
用官方 golang:alpine 构建,再 COPY 到 alpine:latest 运行,是 Go 容器化的标准姿势。
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
立即学习“go语言免费学习笔记(深入)”;
- 构建阶段用
golang:1.23-alpine编译二进制;运行阶段用纯alpine:latest,无 Go 环境、无源码、无构建工具 - 避免使用
golang:latest直接运行 —— 镜像体积大(>1GB),含大量开发依赖,有安全风险 - 若项目依赖 cgo(如 SQLite、某些加密库),则需保留
glibc或改用golang:alpine+apk add --no-cache gcc musl-dev - 最终镜像大小应控制在 15–30MB 左右,远小于未优化的 500MB+ 镜像
环境变量传配置,别把地址写死在代码里
数据库地址、下游服务地址、超时时间这些,全靠环境变量注入,而不是在 main.go 里写死字符串。
- Go 中读取:
os.Getenv("USER_SERVICE_URL"),默认值用三元逻辑封装(如url := os.Getenv("USER_SERVICE_URL"); if url == "" { url = "http://user:8080" }) -
docker-compose.yml中通过environment或env_file注入:USER_SERVICE_URL: http://user:8080 - 不同环境(dev/staging/prod)只需换
.env文件或覆盖docker-compose.override.yml,不用改代码 - 注意:环境变量名在 Linux 容器中默认全大写,Go 里用
os.Getenv区分大小写,务必保持一致
最容易被忽略的是服务启动后的“就绪等待”——Docker 不知道你的 Go 服务是不是真 ready 了,depends_on 和健康检查(healthcheck)得配合使用,否则上游服务发起请求时大概率遇到 connection refused。

















