部署到Google App Engine时,Spring Boot应用程序无法连接到Google Cloud SQL(PostgreSQL)

时间:2019-10-22 20:55:05

标签: java postgresql spring-boot jdbc google-cloud-platform

我有一个基于Gradle的Spring Boot(版本2.1.6)应用程序,该应用程序将部署到Google App Engine。我已经创建了一个我要连接的Google Cloud SQL(PostgreSQL 11)数据库实例。

我已按照此示例中的所有步骤操作:https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-sql-postgres-sample

当我在本地运行该应用程序时,一切正常运行。但是,当我将应用程序部署到App Engine时,它无法连接到数据库。这些是我得到的错误:

ERROR: (gcloud.app.deploy) Error Response: [9] 
Application startup error:
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40) ~[google-api-client-1.28.0.jar!/:1.28.0]
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:417) ~[google-api-client-1.28.0.jar!/:1.28.0]
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1089) ~[google-http-client-1.30.1.jar!/:na]
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:515) ~[google-api-client-1.28.0.jar!/:1.28.0]
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:448) ~[google-api-client-1.28.0.jar!/:1.28.0]
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:565) ~[google-api-client-1.28.0.jar!/:1.28.0]
    at com.google.cloud.sql.core.CloudSqlInstance.fetchEphemeralCertificate(CloudSqlInstance.java:327) ~[jdbc-socket-factory-core-1.0.14.jar!/:na]
    ... 10 common frames omitted

2019-10-22 20:49:13.206  INFO 1 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
2019-10-22 20:49:13.474  INFO 1 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.10.Final}
2019-10-22 20:49:13.485  INFO 1 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2019-10-22 20:49:14.420  INFO 1 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-10-22 20:49:15.392 ERROR 1 --- [           main] o.s.b.web.embedded.tomcat.TomcatStarter  : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'authenticationTokenFilter': Unsatisfied dependency expressed through field 'apiKeysService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'apiKeysServiceImpl' defined in URL [jar:file:/app.jar!/BOOT-INF/classes!/nl/storegear/sgapi/services/servicesimpl/ApiKeysServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'apiKeyRepository': Cannot create inner bean '(inner bean)#72e34f77' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#72e34f77': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
2019-10-22 20:49:15.466  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2019-10-22 20:49:15.473  WARN 1 --- [           main] o.a.c.loader.WebappClassLoaderBase       : The web application [ROOT] appears to have started a thread named [pool-1-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1088)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 java.lang.Thread.run(Thread.java:748)
2019-10-22 20:49:15.478  WARN 1 --- [           main] o.a.c.loader.WebappClassLoaderBase       : The web application [ROOT] appears to have started a thread named [pool-1-thread-2] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
...

这是我的application.properties文件的样子:

...

spring.datasource.hikari.connectionTimeout=20000
spring.datasource.hikari.maximumPoolSize=5

spring.datasource.username={REDACTED}
spring.datasource.password={REDACTED}
spring.cloud.gcp.sql.database-name={REDACTED}
spring.cloud.gcp.sql.instance-connection-name={REDACTED}
spring.datasource.continue-on-error=true
spring.datasource.initialization-mode=always
spring.cloud.gcp.credentials.location=file:src/main/resources/{REDACTED}.json
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.show-sql=false

...

我认为这可能与gcp凭证json文件有关,但我不知道下一步该怎么做。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

这里可能有2个问题。

1-

在本地测试应用程序时,由于已正确配置“ application.properties”文件,并在“ ..credentials.location”属性中指定了私钥的路径,因此它可以连接并通过身份验证。部署App Engine后,尝试连接的不是应用程序,而是服务于该应用程序的App Engine instance itself。我怀疑在这种情况下会发生什么,App Engine没有被告知要去哪里获取正确的凭据,该凭据驻留在“ application.properties” Spring Boot文件中。

In this tutorial,在App Engine上运行的Spring Boot应用程序连接到Cloud SQL实例的情况下,完成了类似的集成。将App Engine指向凭据的方法是通过Spring Profiles保持the credentials以及“ app.yaml”文件的配置来完成的,其中通过“ spring_profiles_active”使配置文件处于活动状态”环境变量。

或者,也可以按照step 5 of the example you referenced中的说明在Cloud SDK中进行身份验证。这里是the command用来通过这种方法获取凭据的信息,here is an implementation example是从完整的教程中获取的。

2-

Spring Boot入门者使用Tomcat as the default servlet containers。 App Engine使用Jetty as servlet containers。部署App Engine时,如果不忽略Tomcat依赖项,则它们将与Jetty冲突。执行App Engine部署时,抛出“ o.s.b.web.embedded.tomcat.TomcatStarter:启动Tomcat上下文错误”错误时,可能就是这种情况。

这里是official Spring documentation,介绍如何排除这些依赖关系,这里是集成了相同组件的完整教程中的implementation example