java - Spring Boot 应用在部署到 Google App Engine 时无法连接到 Google Cloud SQL (PostgreSQL)
问题描述
我有一个基于 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 -样本。
当我在本地运行应用程序时,一切正常。但是当我将应用程序部署到 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-
在本地测试应用程序时,它能够连接并获得身份验证,因为“application.properties”文件已正确配置,私钥的路径在“..credentials.location”属性中指定。部署 App Engine 时,尝试连接的不是应用程序,而是为应用程序提供服务的App Engine 实例本身。我怀疑在这种情况下会发生什么,App Engine 没有被告知去哪里获取驻留在“application.properties”Spring Boot 文件中的正确凭据。
在本教程中,在 App Engine 上运行的 Spring Boot 应用程序连接到 Cloud SQL 实例时完成了类似的集成。用于将 App Engine 指向凭据的方法是通过保存凭据的Spring Profiles以及“<a href="https://cloud.google.com/appengine/docs/standard/java11/ config/appref" rel="nofollow noreferrer">app.yaml” 文件,其中配置文件通过“spring_profiles_active”环境变量激活。
或者,可以在 Cloud SDK 中完成身份验证,如您引用的示例的第 5 步中所述。这是用于通过此方法获取凭据的命令,这是来自完整教程的实现示例。
2-
Spring Boot 启动器使用Tomcat 作为默认的 servlet 容器。App Engine 使用Jetty 作为 servlet 容器。在部署 App Engine 的时候,如果不忽略 Tomcat 的依赖,就会和 Jetty 的发生冲突。这可能是在执行 App Engine 部署时引发“osbweb.embedded.tomcat.TomcatStarter : Error started Tomcat context”错误时发生的情况。
这是有关如何排除这些依赖项的官方 Spring 文档,这里是集成相同组件的完整教程中的实现示例。
推荐阅读
- json - Fabric 1.15.2 我的战利品表不工作
- excel - 使用 VBA 获取已安装程序 (WhatsApp) 的路径
- python - Python 交互式图形库
- javascript - 如何在两个独立的后端之间同步数据?
- c++ - 导航 while 循环
- shell - $2 空白字符串不匹配
- python - MacOS Finder 按字母顺序排序与 Python .sort() 不同
- javascript - Meteor 中 Stripe 集成的挑战
- swift - 如何从 viewDidAppear 之外设置标签的文本?
- jinja2 - Airflow Jinja 模板 - 如何将 query_params 传递到我的 SQL 文件中?