Docker部署SpringBoot应用无法连接PostgreSQL容器问题
问题现象
把基于SpringBoot开发的API应用部署到Docker容器时,出现数据库连接失败错误,具体日志如下:
2023-03-06 17:23:55,369 ERROR com.zaxxer.hikari.pool.HikariPool : BackendHikariPool - Exception during pool initialization.
org.postgresql.util.PSQLException: The connection attempt failed.
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:331)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
at org.postgresql.jdbc.PgConnection.(PgConnection.java:223)
at org.postgresql.Driver.makeConnection(Driver.java:402)
at org.postgresql.Driver.connect(Driver.java:261)
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:364)
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206)
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:476)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561)
at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:115)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:266)
本地机器能通过localhost或Docker分配的IP连接PostgreSQL,但SpringBoot容器始终无法建立连接。
补充信息
Dockerfile内容
FROM openjdk:17-jdk-slim ADD target/fitness-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java", "-jar", "app.jar"]
docker-compose.yml内容
version: '3.1' services: postgres: image: 'postgres:12-alpine' ports: - "5432:5432" environment: POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword POSTGRES_DB: fitness volumes: - 'postgres_data:/var/lib/postgresql/data' localstack: image: 'localstack/localstack:0.12.14' ports: - "4566:4566" environment: - DEFAULT_REGION=eu-central-1 - SERVICES=sqs - DATA_DIR=/tmp/localstack/data - DOCKER_HOST=unix:///var/run/docker.sock volumes: - /tmp/localstack:/tmp/localstack - ./config/localstack/sqs/setup-local-env.sh:/docker-entrypoint-initaws.d/setup-local-env.sh volumes: postgres_data: localstack_data:
解决方法
1. 修改数据库连接配置
SpringBoot应用的数据库URL不能用localhost——容器内的localhost指向容器自身,不是宿主机或PostgreSQL容器。要把连接URL里的主机名改成docker-compose中PostgreSQL服务的名称postgres,示例配置:
spring.datasource.url=jdbc:postgresql://postgres:5432/fitness spring.datasource.username=myuser spring.datasource.password=mypassword
2. 确保SpringBoot容器加入同一Docker网络
如果SpringBoot容器是单独启动的(没通过docker-compose一起启动),需要手动把它加入docker-compose创建的网络:
- 先查docker-compose创建的网络名称:
docker network ls,一般是<项目目录>_default - 启动SpringBoot容器时加入该网络:
docker run --network=<网络名称> -d <你的SpringBoot镜像名>
3. 验证网络连通性
进入SpringBoot容器内部,尝试ping PostgreSQL服务名:
docker exec -it <SpringBoot容器ID> ping postgres
如果能ping通,说明网络没问题,再检查数据库用户名、密码、端口是否匹配。
4. (推荐)把SpringBoot加入docker-compose
更稳妥的方式是将SpringBoot服务加到现有的docker-compose.yml里,Docker会自动处理网络连通性:
version: '3.1' services: postgres: # 保留原配置 localstack: # 保留原配置 springboot-app: build: . ports: - "8080:8080" depends_on: - postgres environment: SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/fitness SPRING_DATASOURCE_USERNAME: myuser SPRING_DATASOURCE_PASSWORD: mypassword
之后执行docker-compose up -d --build启动所有服务即可。
内容的提问来源于stack exchange,提问作者Daviel Sánche

