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

Docker化PostgreSQL连接失败:Golang服务主机名解析错误排查

问题描述

使用以下docker-compose.yaml部署PostgreSQL和Golang服务:

services:
  db:
    image: postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: test
    networks: [ "test_network" ]

  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      DB_HOST: db
      DB_USER: user
      DB_PASSWORD: password
      DB_NAME: test
    depends_on:
      - db
    networks: [ "test_network" ]

networks:
   test_network:
        driver: bridge

Golang应用中通过GORM连接数据库的代码:

db, err := gorm.Open(postgres.New(postgres.Config{
        DSN:                  "host=db user=user password=password dbname=test port=5432",
        PreferSimpleProtocol: true, // disables implicit prepared statement usage
    }), &gorm.Config{})

执行docker-compose up时出现错误:

[error] failed to initialize database, got error failed to connect to `host=postgres user=user database=test`: hostname resolving error (lookup postgres on 127.0.0.11:53: read udp 127.0.0.1:36942->127.0.0.11:53: i/o timeout)
news-api-app-1  | 2023/04/08 07:16:38 Cannot run server, encountered an error whilst initializing - failed to connect to `host=postgres user=user database=test`: hostname resolving error (lookup postgres on 127.0.0.11:53: read udp 127.0.0.1:36942->127.0.0.11:53: i/o timeout)

已知本地通过psql可正常连接数据库,存在两个疑问:

  1. 代码明确指定host=db,为何错误显示连接host=postgres?
  2. 如何解决该连接失败问题?
疑问解答

1. 为什么错误显示连接host=postgres?

最可能的原因是Golang服务使用了旧镜像:你修改了代码中的DSN为host=db,但未重新构建镜像,docker-compose up时复用了之前构建的、仍使用host=postgres的旧镜像,导致错误中的目标host与当前代码不符。

此外也需排查代码逻辑:是否存在其他数据库初始化逻辑误用了默认值(部分postgres驱动配置中默认host可能设为postgres),或者环境变量覆盖了硬编码的DSN。

2. 连接失败问题的解决方法

方法1:重新构建并启动服务

确保使用最新代码构建镜像,执行:

docker-compose up --build

方法2:确保数据库服务就绪后再连接

depends_on仅保证db容器启动,不代表PostgreSQL服务已完全就绪(比如还在初始化数据库)。可通过两种方式处理:

  • 在docker-compose中添加健康检查:修改db服务配置,等待PostgreSQL就绪后再启动app:
    db:
      image: postgres
      ports:
        - "5432:5432"
      environment:
        POSTGRES_USER: user
        POSTGRES_PASSWORD: password
        POSTGRES_DB: test
      networks: [ "test_network" ]
      healthcheck:
        test: ["CMD-SHELL", "pg_isready -U user -d test"]
        interval: 5s
        timeout: 5s
        retries: 5
    app:
      # ... 其他配置
      depends_on:
        db:
          condition: service_healthy
    
  • 在Golang代码中添加重试逻辑:初始化数据库时循环尝试连接,直到成功或达到重试次数:
    import "time"
    import "log"
    
    var db *gorm.DB
    var err error
    maxRetries := 5
    retryDelay := 2 * time.Second
    
    for i := 0; i < maxRetries; i++ {
        db, err = gorm.Open(postgres.New(postgres.Config{
            DSN:                  "host=db user=user password=password dbname=test port=5432",
            PreferSimpleProtocol: true,
        }), &gorm.Config{})
        if err == nil {
            break
        }
        log.Printf("Failed to connect to database, retrying in %v... (%d/%d)", retryDelay, i+1, maxRetries)
        time.Sleep(retryDelay)
    }
    
    if err != nil {
        log.Fatalf("Cannot run server, encountered an error whilst initializing - %v", err)
    }
    

方法3:验证容器网络连通性

如果以上方法无效,进入app容器验证能否解析并连通db服务:

# 进入app容器
docker exec -it news-api-app-1 sh
# 尝试ping db服务
ping db
# 尝试用psql连接数据库
psql -h db -U user -d test

如果ping不通db,需检查docker-compose中的网络配置,确保两个服务都加入了test_network网络。


内容的提问来源于stack exchange,提问作者cert_perf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:15:30