Cloud Run部署的Spring Boot应用无法连接同项目PostgreSQL实例
Spring Boot部署到Cloud Run后无法连接GCP PostgreSQL实例问题排查
问题背景
开发的Spring Boot应用本地运行时可正常连接GCP项目中的PostgreSQL14实例,但部署到同项目的Cloud Run后抛出NullPointerException,核心错误栈如下:
2024-07-17 11:07:25.658 CEST java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(java.sql.SQLException, String)" because the return value of "org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.sqlExceptionHelper()" is null at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:116) ~[hibernate-core-6.5.2.Final.jar:6.5.2.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:290) ~[hibernate-core-6.5.2.Final.jar:6.5.2.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:123) ~[hibernate-core-6.5.2.Final.jar:6.5.2.Final] ... at com.idea.poc1.Poc1Application.main(Poc1Application.java:10) ~[classes/:na]
本地可正常连接的配置步骤
- 创建启用公网IP的PostgreSQL14实例
- 将本地机器IP加入实例网络白名单以允许连接
项目依赖配置(pom.xml)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--<dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version> </dependency>--> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> </dependencies>
本地配置文件(application.properties)
spring.application.name=poc1 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=none spring.jpa.hibernate.show-sql=true spring.datasource.url=jdbc:postgresql://211.321.30.46:5432/postgres spring.datasource.username=postgresuser spring.datasource.password=password spring.sql.init.mode=always #spring.sql.init.schema-locations=classpath:/schema.sql spring.sql.init.continue-on-error=true #logging.level.org.hibernate=DEBUG #logging.level.org.hibernate.SQL=DEBUG #logging.level.org.hibernate.type=TRACE
当前GCP项目配置
- Cloud Run服务账号已授予
roles/cloudsql.client角色 - 执行部署的用户已授予
roles/cloudsql.client角色
问题原因
本地通过固定公网IP+白名单的方式连接数据库,但Cloud Run的出口IP是动态变化的,无法提前加入PostgreSQL实例的白名单;同时直接使用公网IP的连接方式不符合Cloud Run连接Cloud SQL的最佳实践,导致数据库连接失败,进而引发Hibernate初始化过程中的NullPointerException。
解决方案
1. 修改数据源连接URL
替换原有公网IP格式的URL为Cloud SQL专用连接格式:
spring.datasource.url=jdbc:postgresql:///postgres?cloudSqlInstance=你的GCP项目ID:实例区域:实例名称&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=postgresuser&password=password
注意:cloudSqlInstance的值需要替换为你的PostgreSQL实例的连接名,格式为项目ID:区域:实例名,可在GCP控制台的Cloud SQL实例详情页获取。
2. 添加Cloud SQL Socket Factory依赖
在pom.xml中添加PostgreSQL的Cloud SQL Socket Factory依赖,用于建立安全连接:
<dependency> <groupId>com.google.cloud.sql</groupId> <artifactId>postgres-socket-factory</artifactId> <version>1.15.0</version> </dependency>
3. 部署Cloud Run时配置Cloud SQL连接
部署应用到Cloud Run时,在部署配置中指定要连接的Cloud SQL实例:
- GCP控制台部署:在"连接"部分添加对应的PostgreSQL实例
- gcloud命令行部署:添加
--add-cloudsql-instances=你的实例连接名参数
4. 验证配置
- 确保Cloud Run服务账号的
roles/cloudsql.client权限生效 - 确认数据源配置中的用户名、密码、实例连接名均正确
完成以上步骤后,重新部署应用到Cloud Run即可正常连接PostgreSQL实例。
内容的提问来源于stack exchange,提问作者user3839347
相关产品推荐
相关产品推荐

