Go服务在Docker Compose中无法连接MySQL/Redis,因localhost指向自身而非其他容器;应使用服务名(如mysql)作为主机地址,并确保未设置network_mode: "host",同时通过环境变量统一配置DB连接参数。

Go 服务无法连接到 Docker Compose 中的 MySQL/Redis?检查 network_mode 和 host 配置
Go 应用在容器内运行时,默认无法用 localhost 访问同 compose 文件中定义的其他服务——因为每个容器有独立网络命名空间。localhost 指向自己,不是宿主机,更不是其他容器。
正确做法是:在 Go 代码里把数据库地址写成服务名(如 mysql、redis),前提是它们在同一个自定义网络中。Docker Compose 默认会创建一个网络,并将所有 service 接入其中。
- 确保
docker-compose.yml中没有设置network_mode: "host",否则容器共享宿主机网络,service 名解析会失效 - Go 连接字符串示例:
"user:pass@tcp(mysql:3306)/dbname?parseTime=true",其中mysql是 yml 中 service 的名字 - 如果 Go 服务运行在宿主机(非容器),而 DB 在 compose 容器中,则应使用
host.docker.internal(macOS/Windows)或宿主机 IP(Linux,需额外配置)
go run 本地开发时如何复用 docker-compose.yml 中的环境变量?
docker-compose.yml 里的 environment 或 .env 文件只对容器生效,go run main.go 不会自动加载它们——这是常见混淆点。
两种实用方案:
立即学习“go语言免费学习笔记(深入)”;
- 用
direnv或 shell 脚本提前source同一份.env文件,再运行 Go 程序 - 在 Go 代码中用
os.Getenv读取环境变量,然后通过docker-compose run --rm app go run main.go启动,这样 compose 会注入定义好的变量 - 避免硬编码:把 DB 地址、端口等提取为
DB_HOST、DB_PORT变量,在 yml 和本地 .env 中保持一致
为什么 Go 的 go.mod 和 vendor 目录在容器里总报错?挂载路径要避开 GOPATH 冲突
常见错误:cannot find module providing package ...,尤其在使用 volume 挂载当前目录进容器后。
根本原因:Docker 默认工作目录是 /app,但 Go 工具链会按 GO111MODULE 和当前路径判断模块根目录;若挂载覆盖了容器内已有的 go.mod 或 vendor/,或权限不一致,就会失败。
- 在
Dockerfile中明确执行WORKDIR /app,并在构建阶段COPY go.mod go.sum .→go mod download→ 再COPY . . - 开发时若用 bind mount(如
./:/app),确保宿主机目录下已有有效的go.mod,且不要挂载vendor/目录(容易权限混乱) - 推荐开发镜像使用
golang:1.21-alpine等官方基础镜像,避免自建镜像遗漏GOPATH或CGO_ENABLED设置
如何让 Go 服务在 compose 启动后自动重试连接 DB,而不是直接 panic?
容器启动顺序不保证,MySQL 容器可能比 Go 服务慢几秒就绪。直接调用 sql.Open + db.Ping() 失败就退出,会导致反复重启。
简单可靠的重试逻辑应嵌入初始化流程,而非依赖外部工具(如 wait-for-it.sh):
- 用
backoff.Retry(来自github.com/cenkalti/backoff/v4)封装db.Ping,指数退避最多 30 秒 - 避免在
init()中做连接,改在main()开始处初始化 DB,并处理 error - 注意:重试期间日志要清晰,比如打印
"waiting for mysql at mysql:3306 (attempt 3/10)",否则排查超时问题时无从下手










