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

Golang Testcontainers网络问题:微服务无法连接PostgreSQL容器

微服务测试容器无法连接PostgreSQL测试容器问题

我正在为Golang微服务(基于Fiber和Gorm框架)编写测试,需要创建Docker网络,将PostgreSQL测试容器和微服务测试容器接入同一网络,但微服务始终无法连接到数据库。

DB连接配置(db.go)

func SetupDB(port string, host string) *gorm.DB {

    dsn := "host=" + host + " user=postgres password=password dbname=prescription port=" + port + " sslmode=disable"

    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

    if err != nil {
        panic("error connecting to database")
    }

    db.AutoMigrate(&model.Prescription{})

    return db
}

Testcontainers配置

PostgreSQL容器配置

prescriptionDBContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
    ContainerRequest: testcontainers.ContainerRequest{
        Image:        "postgres",
        ExposedPorts: []string{postgresPort.Port()},
        Env: map[string]string{
            "POSTGRES_USER":     "postgres",
            "POSTGRES_PASSWORD": "password",
            "POSTGRES_DB":       "prescription",
        },
        Networks: []string{network.Name},
        NetworkAliases: map[string][]string{
            network.Name: {"db-network"},
        },
        WaitingFor: wait.ForAll(
            wait.ForLog("database system is ready to accept connections"),
            wait.ForListeningPort(postgresPort),
        ),
    },
    Started: true,
})

微服务容器配置

prescriptionContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
    ContainerRequest: testcontainers.ContainerRequest{
        FromDockerfile: testcontainers.FromDockerfile{Context: "../../../../prescription"},
        Networks:       []string{network.Name},
        NetworkAliases: map[string][]string{
            network.Name: {"db-network"},
        },
        Env: map[string]string{
            "POSTGRES_USER":     "postgres",
            "POSTGRES_PASSWORD": "password",
            "POSTGRES_DB":       "prescription",
            "HOST":              prescriptionDBHost,
            "DB_PORT":           prescriptionDBPort.Port(),
        },
        ExposedPorts: []string{pMicroPort.Port()},
        WaitingFor:   wait.ForListeningPort("8080"),
    },
    Started: true,
})

尝试过的方法及错误

我尝试了多种HOST和DB_PORT组合,均失败:

  • 通过容器名称获取HOST:

    prescriptionDBHost, err := prescriptionDBContainer.Name(context.Background())
    // 配置:"HOST": prescriptionDBHost, "DB_PORT": prescriptionDBPort.Port()
    

    错误:

    failed to initialize database, got error failed to connect to `host=/stoic_heyrovsky user=postgres database=prescription`: dial error (dial unix /stoic_heyrovsky/.s.PGSQL.53802: connect: no such file or directory)
    panic: error connecting to database
    
  • 去除容器名称中的"/":

    "HOST": strings.Trim(prescriptionDBHost,"/"), "DB_PORT": prescriptionDBPort.Port()
    

    出现类似dial tcp错误。

  • 使用localhost/127.0.0.1作为HOST:

    "HOST": "localhost", "DB_PORT": prescriptionDBPort.Port()
    // 或 "HOST": "127.0.0.1", "DB_PORT": prescriptionDBPort.Port()
    

    错误:

    failed to initialize database, got error failed to connect to `host=localhost user=postgres database=prescription`: dial error (dial tcp [::1]:53921: connect: cannot assign requested address)
    
  • 通过容器IP获取HOST:

    prescriptionDBHost, err := prescriptionDBContainer.ContainerIP(context.Background())
    // 配置:"HOST": prescriptionDBHost, "DB_PORT": prescriptionDBPort.Port()
    

    同样出现dial tcp错误。

额外调试:暂停测试后,手动用localhost+对应端口连接数据库容器可以成功,但docker network inspect显示数据库容器已接入网络,微服务容器未接入。


解决方法

1. 修正网络别名冲突

给两个容器设置了同一个网络别名db-network会导致DNS解析混乱,给PostgreSQL容器单独设置唯一别名,比如postgres-db:

// PostgreSQL容器的NetworkAliases配置
NetworkAliases: map[string][]string{
    network.Name: {"postgres-db"},
},

微服务容器的网络别名可换成其他名称,比如prescription-service,避免冲突。

2. 使用容器网络别名+内部端口通信

在同一Docker网络内,容器之间直接用网络别名+容器内部端口通信,不需要主机映射的随机端口。修改微服务容器的环境变量:

Env: map[string]string{
    // ...其他配置
    "HOST":      "postgres-db",
    "DB_PORT":   "5432",
},

3. 确保网络与容器初始化顺序

确认Docker网络已提前创建完成:

network, err := testcontainers.GenericNetwork(context.Background(), testcontainers.GenericNetworkRequest{
    NetworkRequest: testcontainers.NetworkRequest{
        Name: "test-network", // 自定义网络名称
    },
})
if err != nil {
    panic(err)
}

同时,微服务容器的WaitingFor仅监听8080端口可能不够,可添加等待数据库连接成功的逻辑,或延长等待时间确保网络完全就绪。

4. 验证容器网络状态

创建容器后打印网络信息,确认两个容器都在同一网络:

// 打印PostgreSQL容器网络信息
dbNetworks, err := prescriptionDBContainer.Networks(context.Background())
if err != nil {
    panic(err)
}
fmt.Println("DB容器网络:", dbNetworks)

// 打印微服务容器网络信息
serviceNetworks, err := prescriptionContainer.Networks(context.Background())
if err != nil {
    panic(err)
}
fmt.Println("微服务容器网络:", serviceNetworks)

完成以上步骤后,微服务容器应该能通过postgres-db别名和5432端口正常连接到PostgreSQL容器。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 11:21:10