集成测试期间的数据库连接适用于本地,但不适用于 Google Cloud Build

DB connection during integration tests works on local, but not working on Google Cloud Build

我正在使用 GitHub、Gradle 和 Docker.

将 Java 11 REST API 部署到 GKE

以下错误只发生在Google Cloud Build上,本地环境没有。根据错误,应用程序似乎无法从 Google Cloud Build 中找到数据库服务器(Google Cloud SQL)。 public和私有IP都试了,结果都是一样的:

...
Step #0 - "Build":     2021-03-11 04:12:04.644  INFO 115 --- [    Test worker] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
Step #0 - "Build":     2021-03-11 04:12:35.855 ERROR 115 --- [    Test worker] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Exception during pool initialization.
Step #0 - "Build": 
Step #0 - "Build":     com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
Step #0 - "Build": 
Step #0 - "Build":     The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
...
Step #0 - "Build":     Caused by: java.net.SocketTimeoutException: connect timed out
...

这是在我添加集成测试后发生的。删除测试后,应用程序部署成功。所以,我可以删除集成测试来避免这个问题。问题是,如果可能的话,我想保留测试,因为有些东西我们无法用单元测试来测试。

这是我用于部署到 GKE 的 Docker 文件。 RUN gradle build --no-daemon -i --stacktrace是在test任务中出现错误的地方:

ARG APP_NAME=test-api
ARG GRADLE_USER_HOME_PATH=/home/gradle/cache_home/

#cache dependencies to reduce downloads
FROM gradle:6.8-jdk11 AS cache
ARG APP_NAME
ARG GRADLE_USER_HOME_PATH
WORKDIR /${APP_NAME}/
RUN mkdir -p ${GRADLE_USER_HOME_PATH}
ENV GRADLE_USER_HOME ${GRADLE_USER_HOME_PATH}
COPY --chown=gradle:gradle build.gradle /${APP_NAME}/
RUN gradle clean build --no-daemon -i --stacktrace -x bootJar

#build
FROM gradle:6.8-jdk11 AS build
ARG APP_NAME
ARG GRADLE_USER_HOME_PATH
WORKDIR /${APP_NAME}/
#Copies cached dependencies
COPY --from=cache ${GRADLE_USER_HOME_PATH} /home/gradle/.gradle/
#Copies the Java source code inside the container
COPY --chown=gradle:gradle . /${APP_NAME}/
#Compiles the code and runs unit tests (with Gradle build)
RUN gradle build --no-daemon -i --stacktrace

#Discards the Gradle image with all the compiled classes/unit test results etc.
#Starts again from the JRE image and copies only the JAR file created before
FROM openjdk:11-jre-slim
ARG APP_NAME
COPY --from=build /${APP_NAME}/build/libs/${APP_NAME}.jar /${APP_NAME}/${APP_NAME}.jar
ENTRYPOINT ["java","-jar","/test-api/test-api.jar"]

如何实现使用DB到GKE的集成测试?或者也许我需要改变我的方法?

我参考这个问答解决了问题:

我必须在 cloudbuild.yaml 上添加 2 个步骤(Cloud SQL ProxyTest)才能使用 Cloud SQL Proxy。其他步骤由 GKE 自动生成:

steps:
  - name: gradle:6.8.3-jdk11
    entrypoint: sh
    args:
      - '-c'
      - |-
        apt-get update && apt-get install -y wget \
        && wget "https://storage.googleapis.com/cloudsql-proxy/v1.21.0/cloud_sql_proxy.linux.amd64" -O cloud_sql_proxy \
        && chmod +x cloud_sql_proxy \
        || exit 1
    id: Cloud SQL Proxy
  - name: gradle:6.8.3-jdk11
    entrypoint: sh
    args:
      - '-c'
      - |-
        (./cloud_sql_proxy -instances=<CONNECTION_NAME>=tcp:<PORT> & sleep 2) \
        && gradle test --no-daemon -i --stacktrace \
        || exit 1
    id: Test
  - name: gcr.io/cloud-builders/docker
    args:
      - build
      - '-t'
      - '$_IMAGE_NAME:$COMMIT_SHA'
      - .
      - '-f'
      - $_DOCKERFILE_NAME
    dir: $_DOCKERFILE_DIR
    id: Build
  - name: gcr.io/cloud-builders/docker
    args:
      - push
      - '$_IMAGE_NAME:$COMMIT_SHA'
    id: Push
  - name: gcr.io/cloud-builders/gke-deploy
    args:
      - prepare
      - '--filename=$_K8S_YAML_PATH'
      - '--image=$_IMAGE_NAME:$COMMIT_SHA'
      - '--app=$_K8S_APP_NAME'
      - '--version=$COMMIT_SHA'
      - '--namespace=$_K8S_NAMESPACE'
      - '--label=$_K8S_LABELS'
      - '--annotation=$_K8S_ANNOTATIONS,gcb-build-id=$BUILD_ID'
      - '--create-application-cr'
      - >-
        --links="Build
        details=https://console.cloud.google.com/cloud-build/builds/$BUILD_ID?project=$PROJECT_ID"
      - '--output=output'
    id: Prepare deploy
  - name: gcr.io/cloud-builders/gsutil
    args:
      - '-c'
      - |-
        if [ "$_OUTPUT_BUCKET_PATH" != "" ]
        then
          gsutil cp -r output/suggested gs://$_OUTPUT_BUCKET_PATH/config/$_K8S_APP_NAME/$BUILD_ID/suggested
          gsutil cp -r output/expanded gs://$_OUTPUT_BUCKET_PATH/config/$_K8S_APP_NAME/$BUILD_ID/expanded
        fi
    id: Save configs
    entrypoint: sh
  - name: gcr.io/cloud-builders/gke-deploy
    args:
      - apply
      - '--filename=output/expanded'
      - '--cluster=$_GKE_CLUSTER'
      - '--location=$_GKE_LOCATION'
      - '--namespace=$_K8S_NAMESPACE'
    id: Apply deploy

...

Dockerfile

ARG APP_NAME=test-api
ARG APP_HOME=/test-api

FROM openjdk:11-jdk-slim AS build
USER root
ARG APP_HOME
WORKDIR ${APP_HOME}/
COPY . .
# test is performed from Test step from cloudbuild.yaml
RUN ./gradlew build --no-daemon -i --stacktrace -x test

FROM openjdk:11-jdk-slim
ARG APP_NAME
ARG APP_HOME
WORKDIR ${APP_HOME}/
COPY --from=build ${APP_HOME}/build/libs/${APP_NAME}.jar ./${APP_NAME}.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/test-api/test-api.jar"]

虽然我解决了质疑的问题,但这个脚本有一个小问题:将有 2 个单独的 Gradle 依赖项下载(TestBuild)。我无法在 gcr.io/cloud-builders/docker 上使用云 SQL 代理,因此我使用 Test 步骤而不是 Build 步骤来解决问题。也许这可以使用 docker run --network="host"host.docker.internal 来解决,但我没有尝试。