我正在尝试在本地运行连接到云SQL数据库的Ktor应用程序的Docker容器。
这个容器稍后将被推送到Cloud Run,所以我在我的环境变量中使用了一个IAM服务帐户来进行身份验证。我已经研究这个问题一个星期了,但还没有找到答案。
我使用的步骤如下:
1.创建IAM服务帐户“foo-cloudrun@foo-foo-121212.iam.gserviceaccount.com
1.为Cloud Run和Cloud SQL设置所需的角色:
Cloud Build Service Agent
Cloud Run Admin
Cloud Run Service Agent
Cloud SQL Client
Cloud SQL Instance User
Viewer
1.从IAM帐户创建新密钥并将其保存到桌面。
1.通过在CMD上运行以下命令激活并登录到服务帐户:
gcloud auth activate-service-account --key-file="C:\Users\user\Desktop\cloudrun-key.json"
1.将GOOGLE_APPLICATION_CREDENTIALS环境变量设置为密钥文件位置:
set GOOGLE_APPLICATION_CREDENTIALS="C:\Users\user\Desktop\cloudrun-key.json"
1.导航到我的应用程序文件夹并构建Docker映像:
docker build -t my-application .
1.启动映像:
docker run -p 8080:8080 my-application
这就是我得到一个模糊异常的地方:线程“main”中出现异常.
为了了解发生了什么,我尝试使用docker compose来查看是否有更好的想法。因此,我运行gradleshadowJar在build/libs目录中创建一个.jar文件,然后运行**“docker-compose up”**。
这就是我遇到这个异常的地方,这个异常让我很困惑,因为我已经将环境变量设置到了正确的位置:
引起原因:java.io. IO异常:应用程序默认身份证明不可用。如果在Google Compute Engine中运行,则这些身份证明可用。否则,必须定义环境变量GOOGLE_APPLICATION_ CREDENTIALS,使其指向定义身份证明的文件。有关详细信息,请参阅https://developers.google.com/accounts/docs/application-default-credentials。
Dockerfile如下所示:
FROM gradle:7-jdk11 AS build
# Copy local code to the container image.
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
# Build a release artifact.
RUN gradle shadowJar --no-daemon
FROM openjdk:11
EXPOSE 8080:8080
RUN mkdir /app
# Copy the jar to the production image from the builder stage.
COPY --from=build /home/gradle/src/build/libs/*.jar /app/my-application-docker.jar
# Run the web service on container startup.
ENTRYPOINT [ "java", "-jar", "/app/my-application-docker.jar" ]
docker-compose.yml文件:
services:
web:
build: .
ports:
- "8080:8080"
environment:
INSTANCE_CONNECTION_NAME: ${INSTANCE_CONNECTION_NAME}
DB_IAM_USER: ${DB_IAM_USER}
DB_USER: ${DB_USER}
DB_NAME: ${DB_NAME}
PORT: ${PORT}
JDBC_DRIVER: ${JDBC_DRIVER}
GOOGLE_APPLICATION_CREDENTIALS: ${GOOGLE_APPLICATION_CREDENTIALS}
环境文件:
JDBC_DRIVER=org.postgresql.Driver
DB_IAM_USER=foo-cloudrun@foo-foo-121212.iam
DB_NAME=my-database
INSTANCE_CONNECTION_NAME=foo-foo-121212:us-central1:database-sql-instance
PORT=8080
GOOGLE_APPLICATION_CREDENTIALS=C:\Users\user\Desktop\cloudrun-key.json
数据库工厂.kt文件,如this reference:
object DatabaseFactory {
private val INSTANCE_CONNECTION_NAME = System.getenv("INSTANCE_CONNECTION_NAME");
private val DB_IAM_USER = System.getenv("DB_IAM_USER")
private val DB_NAME = System.getenv("DB_NAME")
fun init() {
Database.connect(hikari())
transaction {
SchemaUtils.create(FirstTable)
SchemaUtils.create(SecondTable)
}
}
private fun hikari(): HikariDataSource {
val config = HikariConfig()
// IAM AUTHENTICATION
config.driverClassName = System.getenv("JDBC_DRIVER")
config.jdbcUrl = String.format("jdbc:postgresql:///%s", DB_NAME)
config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.postgres.SocketFactory")
config.addDataSourceProperty("cloudSqlInstance", INSTANCE_CONNECTION_NAME)
config.addDataSourceProperty("enableIamAuth", "true")
config.addDataSourceProperty("user", DB_IAM_USER)
config.addDataSourceProperty("password", "password")
config.addDataSourceProperty("sslmode", "disable")
config.connectionTimeout = 10000 // 10s
config.maximumPoolSize = 5
config.minimumIdle = 3
config.maxLifetime = 1800000; // 30 minutes
config.isAutoCommit = false
config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
config.validate()
// Initialize the connection pool using the configuration object.
return HikariDataSource(config);
}
suspend fun <T> dbQuery(block: () -> T): T =
withContext(Dispatchers.IO) {
transaction {
addLogger(StdOutSqlLogger)
block()
}
}
}
我尝试过但失败的事情:
1.正在本地测试云运行服务。正在获取NullPointerException
第8080章:我的应用程序是什么?
如果您有任何问题,请与我们联系。如果您有问题,请与我们联系。
1.使用我的gmail用户帐户运行docker-composite up命令:
- 取消设置环境变量(设置GOOGLE_APPLICATION_CREDENTIALS=)
- gcloud验证登录(到gmail帐户)
- gcloud auth应用程序-默认登录(将默认凭据设置为已知位置)
- 再次运行docker run命令或docker-compose up
我得到的是:
- ”从环境变量GOOGLE_APPLICATION_CREDENTIALS读取凭证文件时出错,值为“C:\Users\user\Desktop\cloudrun-key. json”:文件不存在。"*
1.通过系统属性手动设置Windows系统环境变量中的GOOGLE_APPLICATION_CREDENTIALS。再次出现相同错误。
任何帮助都很好,谢谢。
1条答案
按热度按时间z9smfwbn1#
哇,这是一个很大的问题:-)
第一个以下命令是互斥的-ish:
这将使用服务帐户验证
gcloud
及其命令。当您运行gcloud something
时,它将使用服务帐户作为其标识。这使得使用Google客户端库构建的代码能够使用应用程序默认凭据(ADC)来获取代码的运行时标识。它不会影响
gcloud
。它确实为您的代码提供了一个标识。我假设
set
是Windows环境变量命令第二个我承认我仔细考虑了这个问题,您需要在容器运行时将服务帐户装入容器。
使用
docker
或podman
等:使用Docker时,路径
c:\Users\user\Desktop\cloudrun-key.json
可能不正确。您可能需要将\
替换为/
。您可能需要对c:
执行一些操作。我不知道它在Windows上是如何Map的。--volume
标志将您的主机上的密钥位置Map到(:
)容器中的位置。在这种情况下,在容器中,密钥将是
/secrets/key.json
,因此这是用于GOOGLE_APPLICATION_CREDENTIALS
的值。使用
docker-compose
,它将类似于:第三当您在Cloud Run上运行容器时,它将利用ADC并自动使用您部署的Cloud Run服务的标识。Cloud Run服务具有默认标识,但您可以在部署时使用
gcloud run deploy ... --service-account=${SERVICE_ACCOUNT}
指定标识。多亏了ADC,您不需要担心将密钥装入容器或指定环境变量,它就可以正常工作。