使用Gorm连接Docker部署的PostgreSQL时遇连接拒绝错误求助
问题概述
尝试通过Docker Compose部署的PostgreSQL数据库,使用Gorm进行Go语言连接时出现连接拒绝错误,同时本地用DBeaver连接也失败。
Docker Compose配置
services: app: build: context: . # Correct the path to your Dockerfile dockerfile: Dockerfile ports: - "127.0.0.1:8080:8080" volumes: - .:/app networks: - backend depends_on: - db db: container_name: simple_api_db_user restart: always image: postgres:latest environment: POSTGRES_USER: mateen POSTGRES_PASSWORD: password POSTGRES_DB: simple_api_db_user volumes: - db_data:/var/lib/postgresql/data networks: - backend ports: - "127.0.0.1:5430:5430" volumes: db_data: networks: backend: driver: bridge
Go语言连接代码
func NewPostgresConnection() (*gorm.DB, error) { psqlConfig, err := dbConfigs.NewPostgresqlConfig() if err != nil { return nil, err } db, err := sql.Open("postgres", psqlConfig.Dsn()) if err != nil { log.Println("DB Connection error : ", err.Error()) return nil, err } if err := db.Ping(); err != nil { log.Println("DB Ping error: ", err.Error()) return nil, err } gdb, err := gorm.Open(postgres.Open(psqlConfig.Dsn()), &gorm.Config{}) if err != nil { return nil, err } err = Migrate(gdb) if err != nil { return nil, err } return gdb, nil }
DSN配置与错误信息
打印的DSN配置:&{host=simple_api_db_user user=mateen password=password dbname=simple_api_db_user port=5430 sslmode=disable TimeZone=UTC}
应用运行错误:
simple-api-user-app-1 | 2023/05/10 14:05:16 DB Ping error: dial tcp 172.31.0.2:5430: connect: connection refused simple-api-user-app-1 | 2023/05/10 14:05:16 dial tcp 172.31.0.2:5430: connect: connection refused
DBeaver连接错误:
The connection attempt failed. EOFException java.io.EOFException
Dockerfile内容
# Builder FROM golang:latest WORKDIR /app COPY go.mod go.sum ./ RUN go mod download RUN go install github.com/cosmtrek/air@latest COPY . . CMD [ "air" ] EXPOSE 8080
解决方案
1. 修正PostgreSQL容器端口映射
PostgreSQL默认监听端口是5432,你的Docker Compose中把主机5430端口映射到容器的5430端口,但容器内Postgres并未在5430端口运行,这是核心问题。修改db服务的ports配置:
ports: - "127.0.0.1:5430:5432"
这样主机5430端口会转发到容器内的5432端口,本地工具(如DBeaver)就能通过5430连接数据库。
2. 调整容器内连接端口
因为Go应用和PostgreSQL容器在同一个Docker网络(backend)内,应用连接数据库时应该使用容器内部的默认端口5432,而不是5430。修改你的DSN配置,将port改为5432:&{host=simple_api_db_user user=mateen password=password dbname=simple_api_db_user port=5432 sslmode=disable TimeZone=UTC}
3. 优化数据库连接时机(可选)
depends_on仅保证容器启动顺序,不确保PostgreSQL服务完全就绪。可以在Go代码中添加连接重试逻辑,避免数据库未初始化完成就尝试连接:
import "time" func NewPostgresConnection() (*gorm.DB, error) { psqlConfig, err := dbConfigs.NewPostgresqlConfig() if err != nil { return nil, err } var db *sql.DB var pingErr error // 最多重试5次,每次间隔2秒 for i := 0; i < 5; i++ { db, err = sql.Open("postgres", psqlConfig.Dsn()) if err != nil { log.Println("DB Connection error : ", err.Error()) time.Sleep(2 * time.Second) continue } pingErr = db.Ping() if pingErr == nil { break } log.Println("DB Ping error, retrying...: ", pingErr.Error()) time.Sleep(2 * time.Second) } if pingErr != nil { return nil, pingErr } gdb, err := gorm.Open(postgres.Open(psqlConfig.Dsn()), &gorm.Config{}) if err != nil { return nil, err } err = Migrate(gdb) if err != nil { return nil, err } return gdb, nil }
4. 验证修改
- 重启Docker Compose服务:
docker-compose down && docker-compose up -d - 用DBeaver连接
localhost:5430,使用配置的用户名、密码和数据库名,验证连接是否正常 - 启动Go应用,检查是否还存在连接拒绝错误
内容的提问来源于stack exchange,提问作者Mateen Bagheri

