You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose网络中Go容器无法连接MongoDB问题排查

问题根因

连接失败是两个核心问题叠加导致的,depends_on 没有起到你预期的等待作用,同时配置里还存在容易忽略的挂载隐患。

  • depends_on 只会保证依赖容器的启动顺序,不会等待容器内的服务真正完成初始化、开始监听端口。MongoDB容器刚启动时,还在做内存映射、加载存储引擎,27017端口还没对外提供服务,这时候你的Go服务就已经开始发起连接,自然会报no reachable servers错误。
  • Dockerfile中设置的工作目录是/usr/src/app,编译好的二进制也存放在这个路径下,但docker-compose里给api服务配置的卷挂载是./:/go/src/app,路径完全不匹配,虽然不会直接触发网络错误,但后续本地改代码后容器内不会同步更新,调试时很容易踩坑。
  • 容器内的localhost指向容器自身,不是宿主机也不是其他同网络容器,你代码里用mongodb:27017、redis:6379作为连接地址的写法是对的,不用改,本地跑go run能用localhost是因为本地服务直接跑在宿主机环回网卡上,和Docker内部网络是两套完全隔离的环境。
修复方案

第一步:给依赖服务加健康检查,让API等服务真正就绪再启动

修改docker-compose.yml,给MongoDB、Redis加健康检查规则,同时调整api服务的依赖条件,不要只等容器启动,要等服务健康检查通过再启动:

version: "3.7"

services:
  api:
    container_name: 'api'
    build: './'
    ports:
      - '1323:1323' # 和Go服务实际监听的端口对齐
    volumes:
      - './:/usr/src/app' # 修正挂载路径,和Dockerfile的WORKDIR保持一致
    depends_on:
      mongodb:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - api-network
  mongodb:
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - ./data/mongo:/data/db
    networks:
      - api-network
    # MongoDB健康检查配置
    healthcheck:
      test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
      interval: 5s
      timeout: 5s
      retries: 5
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    volumes:
      - ./data/redis:/data
    networks:
      - api-network
    # Redis健康检查配置
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
networks:
  api-network:

第二步:给连接逻辑加重试(可选但强烈建议)

健康检查只能保证启动阶段的可用性,服务运行中如果出现MongoDB/Redis重启,重连逻辑能避免API直接崩溃。修改Go代码里的连接部分,加简单的循环重试即可,不需要引入额外依赖:

// MongoDB连接重试
var db *mgo.Session
var err error
maxRetries := 10
for i := 0; i < maxRetries; i++ {
    db, err = mgo.Dial("mongodb://mongodb:27017")
    if err == nil {
        break
    }
    log.Printf("连接MongoDB失败,2秒后重试,错误信息: %v", err)
    time.Sleep(2 * time.Second)
}
if err != nil {
    e.Logger.Fatal("多次重试后仍无法连接MongoDB: ", err)
}

// Redis连接重试
var rdb *redis.Client
for i := 0; i < maxRetries; i++ {
    rdb = redis.NewClient(&redis.Options{
        Addr: "redis:6379",
    })
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    err = rdb.Ping(ctx).Err()
    cancel()
    if err == nil {
        break
    }
    log.Printf("连接Redis失败,2秒后重试,错误信息: %v", err)
    time.Sleep(2 * time.Second)
}
if err != nil {
    e.Logger.Fatal("多次重试后仍无法连接Redis: ", err)
}
limiter = redis_rate.NewLimiter(rdb)

第三步:清理旧容器重新启动

执行以下命令清除旧的容器和无效缓存,重新构建启动:

docker compose down -v
docker compose up --build -d
验证

启动后执行命令查看服务日志:

docker compose logs -f

可以看到MongoDB、Redis先启动,等健康检查通过后API服务才会启动,不会再出现no reachable servers的报错。

内容的提问来源于stack exchange,提问作者Halil Yıldırım

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 00:45:38