Docker部署Spring Boot连接PostgreSQL报localhost:5433被拒问题
Docker部署Spring Boot连接PostgreSQL容器问题排查与解决
问题背景
学习Docker过程中尝试容器化部署简易Spring Boot应用,数据库采用Docker Hub官方PostgreSQL镜像。应用在IntelliJ IDEA本地直接运行时功能正常,但通过Dockerfile构建的应用镜像启动后抛出数据库连接错误,相关配置、启动命令、报错信息如下:
- 应用Dockerfile内容:
FROM openjdk:8-jdk-alpine ADD target/spring-boot-jpa-postgresql-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java","-jar", "app.jar"]
- application.properties配置:
spring.datasource.url= jdbc:postgresql://localhost:5433/postgres spring.datasource.username= postgres spring.datasource.password= admin spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation= true spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.PostgreSQLDialect # Hibernate ddl auto (create, create-drop, validate, update) spring.jpa.hibernate.ddl-auto= create
- PostgreSQL容器启动命令:
docker run --name posttest -d -p 5433:5432 -e POSTGRES_PASSWORD=admin postgres
- 应用容器启动核心报错:
org.postgresql.util.PSQLException: Connection to localhost:5433 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. Caused by: java.net.ConnectException: Connection refused (Connection refused) 2022-06-18 21:57:40.977 ERROR 1 --- [ task-1] o.h.engine.jdbc.spi.SqlExceptionHelper : Connection to localhost:5433 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
问题1:5432:5432端口映射时外部工具/本地应用无法连接的原因
核心原因是宿主机5432端口已被其他进程占用。
- 本地大概率已经运行了原生安装的PostgreSQL服务,或者其他进程占用了5432端口,Docker做端口映射时如果宿主机指定端口被占用,要么映射规则失效,要么流量被宿主机上占用端口的进程拦截,根本无法转发到Docker容器内的PostgreSQL服务,因此会出现连接超时、访问失败的问题。
- 换成5433这类未被占用的宿主机端口做映射后,没有端口冲突,流量可以正常转发到容器内的5432端口,因此DBeaver、IDEA本地启动的应用都能正常连接。
验证方法:执行对应命令即可查看5432端口占用情况:
- Windows:
netstat -ano | findstr :5432 - Linux/macOS:
lsof -i:5432
确认占用进程后,要么停掉占用进程释放5432端口,要么继续使用未被占用的端口做映射即可。
问题2:应用镜像正常连接PostgreSQL容器的配置方案
你之前将配置里的localhost改为PostgreSQL容器名仍然报错的核心原因:独立启动的容器默认归属Docker默认桥接网络,该网络不提供容器名DNS解析能力,容器之间无法直接通过容器名定位到对方,因此即使写了容器名也解析不到对应IP。
以下是可直接落地的推荐方案:
自定义桥接网络实现容器互联(生产可用,兼容性好)
自定义桥接网络默认提供容器名DNS解析,是Docker官方推荐的容器间互联方式,步骤如下:
- 创建自定义桥接网络
docker network create app-net
- 启动PostgreSQL容器时加入该网络(如果之前已经启动过同名posttest容器,先执行
docker rm -f posttest删除旧容器)
docker run --name posttest -d --network app-net -e POSTGRES_PASSWORD=admin -p 5433:5432 postgres
这里保留
-p 5433:5432是为了本地DBeaver、IDEA等宿主机工具可以连接数据库,容器之间互联不需要依赖这个端口映射。
- 启动应用容器时同样加入该网络,两种配置方式二选一即可:
- 方式一:启动时通过环境变量覆盖数据库地址,不需要修改代码、重新打包镜像,最便捷
docker run -p 8080:8080 --network app-net -e spring.datasource.url=jdbc:postgresql://posttest:5432/postgres mvp:v4- 方式二:修改application.properties中的数据库连接地址为
jdbc:postgresql://posttest:5432/postgres,注意容器间访问要使用容器内服务的监听端口5432,不是宿主机映射的5433,重新打包构建镜像后,执行以下命令启动:
docker run -p 8080:8080 --network app-net mvp:v4
启动后应用即可正常连接PostgreSQL容器提供服务。
常见踩坑提醒
- 容器内的
localhost永远指向当前容器自身的回环地址,既不是宿主机,也不是其他容器,不要用localhost访问其他容器的服务 - 同网络下容器间访问服务,要使用服务在容器内监听的原始端口,不要用宿主机映射的端口
- 默认桥接网络不支持容器名解析,容器互联必须使用自定义桥接网络
内容的提问来源于stack exchange,提问作者varo111
相关产品推荐
相关产品推荐

