Google CloudRun PORT=8080 environment variable 트러블 슈팅

임동혁 Ldhbenecia·2024년 7월 5일

Devops & Infra

목록 보기
2/4
post-thumbnail
💡 현재 이틀동안 삽질을 계속해서 진행하고 있다.

Revision '' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable.

Secret Manager

이전에 기록했듯이 환경변수를 Secret Manager를 통해 처리하였다.
여기서 추가적으로 발생한 문제점은 이제 json 파일 자체를 처리하는 문제에 달했다.

Secret Manager에 serviceAccountKey라는 이름으로 json 파일을 담았다.
하지만 문제점은 이것을 어떻게 사용하느냐가 문제였다.
자료가 너무 없었다.

firebase:
  sdk:
    path: serviceAccountKey.json

위처럼 yml파일에 넣어두고 해당 경로를 꺼내고 있으나 gitignore로 serviceAccountKey.json 파일을 깃허브 저장소에 올리지 않았기 때문에 찾을 수가 없었다.

정말 엄청나게 많이 시도했지만 계속 실패하였다.

해결

CloudBuild.yaml

steps:
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        gcloud secrets versions access latest --secret="serviceAccountKey" > serviceAccountKey.json

  # Build the container image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'asia-northeast3-docker.pkg.dev/echo-cloud-427211/cloud-run-source-deploy/echo-be/echo-be:$COMMIT_SHA', '.']
    dir: './'

  # Push the container image to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'asia-northeast3-docker.pkg.dev/echo-cloud-427211/cloud-run-source-deploy/echo-be/echo-be:$COMMIT_SHA']

  # Deploy container image to Cloud Run
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'echo-be'
      - '--platform=managed'
      - '--image'
      - 'asia-northeast3-docker.pkg.dev/echo-cloud-427211/cloud-run-source-deploy/echo-be/echo-be:$COMMIT_SHA'
      - '--region'
      - 'asia-northeast3'
      - '--update-env-vars'
      - 'GOOGLE_APPLICATION_CREDENTIALS=/app/src/main/resources/serviceAccountKey.json'

images:
  - 'asia-northeast3-docker.pkg.dev/echo-cloud-427211/cloud-run-source-deploy/echo-be/echo-be:$COMMIT_SHA'

options:
  logging: CLOUD_LOGGING_ONLY

cloudBuild.yaml 파일을 다음과 같이 작성해주고 트리거를 새로 생성했다.
추가가 된점은 CI를 할 때 secret Manger에 접근해서 해당 파일을 불러온다.

Dockerfile

FROM openjdk:17-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN chmod +x ./gradlew
RUN ./gradlew clean build -x test

FROM openjdk:17
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
COPY serviceAccountKey.json /app/src/main/resources/serviceAccountKey.json
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "app.jar"]

그 다음은 CI에서 꺼내온 해당 파일을 도커로 빌드할 때 해당 파일을 복사해서 넣어야할 위치에 넣어주고 빌드, 배포를 진행해서 이 에러는 해결할 수 있었다..

이렇게 빌드한 이미지를 로컬에서 띄운 후 파일을 확인해본 결과
resources폴더에 잘 들어가있는 모습을 확인할 수 있다.

이제 이 다음에 나왔던 에러를 처리해야하는데..

Artifact Registry

💡 step #3: ERROR: (gcloud.run.services.update) Revision '' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.

이 에러가 정말 나를 너무 미친듯이 괴롭혔다.
위에서 환경변수 파일을 처리할 때도 저 오류가 뜨고 아래에 이 오류가 매번 겹쳤었다.

공식문서에 나와있는 방법에 의해 직접 Artifact Registry에 직접 접근해서 빌드가 실패한 이미지를 도커로 실행시켜서 에러를 확인해보려고 했다.

로컬에서 Cloud Run 서비스 테스트  |  Cloud Run Documentation  |  Google Cloud

PORT=8080 && docker run -p 9090:${PORT} -e PORT=${PORT} asia-northeast3-docker.pkg.dev/$ProjectId/저장소명/이름/이름@sha256:HashCode

imageURL에는 홈페이지에서 경로를 찾고 해당 Commit SHA까지 직접 입력해주면 된다.

Docker Image 실행 결과

처음에 실행해보았을 때 JDBC 관련 오류가 발생하였다.

jpa:
  database-platform: org.hibernate.dialect.MySQL8Dialect
  hibernate:
    ddl-auto: create-drop
    show_sql: true
    default_batch_fetch_size: 100
  properties:
    hibernate:
      format_sql: true

그래서 다음과 같이 database-platform을 설정해주었다.
해결이 되기를 간절히 바랬으나 또 하나의 오류가 남았다.

💡 "ERROR: build step 3 "gcr.io/cloud-builders/gcloud" failed: step exited with non-zero status: 1"

이번엔 이 에러가 남았다.

이 오류는 상당히 절망젹이었는데 이 오류 메시지는 Google Cloud Build에서 빌드 단계 3이 실패했음을 나타내며, 비정상적인 상태 코드 1로 종료되었다는 것을 의미한다.

step 3에서 발생한 문제라고 한다.

- name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'gcloud'
  args:
    - 'run'
    - 'deploy'
    - 'echo-be'
    - '--platform=managed'
    - '--image'
    - 'asia-northeast3-docker.pkg.dev/echo-cloud-427211/cloud-run-source-deploy/echo-be/echo-be:$COMMIT_SHA'
    - '--region'
    - 'asia-northeast3'
    - '--update-env-vars'
    - 'GOOGLE_APPLICATION_CREDENTIALS=/app/src/main/resources/serviceAccountKey.json'

문제가 생긴다면 저 update env vars이지 않을까? 해서 두 줄을 지우고 다시 빌드를 시도해보았다.

이 오류가 또 발생하였다.

도커로 다시 이 이미지를 받아서 오류 코드를 확인해보자.

계속해서 DB 관련 오류가 나오고 URL 관련 오류도 나온다.
URL은 원래 나오지 않았던 오류고 문제가 없어보인다…

삽질을 계속해서 진행했다.

삽질 여행기

구글 클라우드런에서 이미지를 말아서 배포한 도커 이미지 파일을 로컬에서 띄우는 방법을 위해서 말했듯이 계속해서 삽질해서 진행했다.

그런데 이제 어이가 없는 점은 저번에 동작했던 Secret Manager에서의 DB URL, USER_NAME, PASSWORD를 못찾는다는 점이었다.

그래서 계속해서 시도하다가 위에서 serviceAccountKey.json과 같은 방식으로 application-prod.yml 파일도 시크릿 매니저에 등록 후 CI 할때 cloudbuild.yaml, dockerfile에서 수정했다.

여기서 또 한번의 삽질이 일어났다.
위에서 보듯이 Dockerfile에서 크게 간과했던 점은 현재 우리는 빌드를 한 이후 app.jar 파일을 실행해서 스프링부트를 띄우고있다.

그런데 위의 도커파일을 보면 빌드한 이후에 패키지 파일에 resoures폴더에 넣고 있었다.

FROM openjdk:17-jdk-alpine AS build
WORKDIR /app
COPY . .
COPY serviceAccountKey.json /app/src/main/resources/serviceAccountKey.json
COPY application-prod.yml /app/src/main/resources/application-prod.yml
RUN chmod +x ./gradlew
RUN ./gradlew clean build -x test

FROM openjdk:17
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "app.jar"]

그래서 빌드를 할때 해당 파일들을 넣어주고 빌드했다.

그 결과는 성공적이었다.

허탕기록,,

이로써 8080포트 대기 에러가 떴을 때 헤쳐나가는 방법에 대해 알게되었으니 조금은 귀찮더라도 해결할 수 있다.
3분 가량의 빌드를 계속 기다려가면서 기도를 하면서 실패를 수십번 맛보아서 꺾일뻔도 했지만 결국 오기가 생겨서 성공해내서 뿌듯하다.

이 에러를 겪고 현재 글을 작성하는 지금 몇번의 수정 과정에서 에러가 더 일어났지만 이제 이 에러는 잘 파훼하고 있다.

2개의 댓글

comment-user-thumbnail
2025년 1월 20일

덕분에 도움이 됐습니다. 해결방법이 좀 달랐지만 저도 아티팩트 설정에서 오류를 만나서 고생했었네요.

1개의 답글