Github Action + GKE + Kustomize CI/CD와 트러블 슈팅

박진형·2025년 4월 29일
0

Github Action과 Kustomize를 사용하여 GKE CI/CD를 구축하는데 상당한 어려움을 겪었습니다.
생각보다 제공된 템플릿에는 추가로 설정해줘야하는 것들이 많았습니다.

세세한 과정을 모두 작성하진 못해도 트러블 슈팅했던 점 위주로 작성하여 공유합니다.

워크로드 아이덴티티 제휴 설정

워크로드 아이덴티티 제휴 설정을 해줘야한다.
기존에는 서비스 계정, 키 파일 등을 사용했던것 같은데 deprecate 시키고 워크로드 아이덴티티를 공식적으로 권장하는 모양이다..

이름은 적절히 원하는 값을 입력하고 발급자는

https://token.actions.githubusercontent.com 로 지정한다.


결론을 우선 말하자면 속성 조건을
assertion.repository=='userId/repositoryName' 로 지정해줘야한다.
*userId와 repositoryName은 사용자의 것으로 수정 필요 ex) pjh612/waiting-system

이것을 지정해주지 않았더니 attribute condition must reference one of the provider's claims. 에러가 발생했다.

풀이 생성 됐다면 서비스 계정을 연결한다.
서비스 계정을 생성하고 권한을 미리 부여해놓는다. 우선은 아래 역할을 부여해놨는데 최소화할 수 있을 것 같다.

서비스 계정을 생성하고 권한을 부여했다면
다시 워크로드 아이덴티티 풀로 돌아가서 "액세스 권한 부여" -> "서비스 계정 가장 기능을 사용하여 액세스 권한 부여"


계정을 선택하고 주 구성원 섹션에서 repository, 그리고 마찬가지로 userId와 repositoryName을 사용자의 github Id, Repository 이름으로 변경해준다.

Github Actions Secret 설정

Repository -> Settings -> Secret and variables -> actions -> New Repository secret

GKE_PROJECT
gcp project id
GKE_WORKLOAD_IDENTITY_PROVIDER
projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider 를 사용자에 맞게 수정하여 저장

공급업체 수정에 들어가면 확인할 수 있는데 project 뒷부분을 복사 붙여넣기 하면된다.
project 뒷부분에는 project id가 들어가는게아니고 별도의 프로젝트 번호가 들어간다.

SA_EMAIL
권한 부여했던 서비스 계정

Workflow setting


New workflow -> gke 검색 -> Configure

Google Cloud가 제공하는 yml파일을 몇가지 수정해야한다.

env

env:
  MODULE: 'waiting-service'
  PROJECT_ID: ${{ secrets.GKE_PROJECT }}
  EMAIL: ${{ secrets.SA_EMAIL }}
  GAR_LOCATION: 'asia-northeast1'
  GKE_CLUSTER: 'test-cluster'
  GKE_ZONE: 'asia-northeast1-a'
  DEPLOYMENT_NAME: 'dev-waiting-service'
  REPOSITORY: 'waiting-service-repo'
  IMAGE: 'pjh612/waiting-system'
  WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GKE_WORKLOAD_IDENTITY_PROVIDER }}
  PROFILE: 'dev'

MODULE, PROFILE, EMAIL은 따로 추가한 변수고
EMAIL, PROJECT_ID, WORKLOAD_IDENTITY_PROVIDER는 secret으로 설정해준다.

그리고 각 값들은 사용자에 맞게 지정해준다.
REPOSITORY 값은 GCP의 Artifact Registry Repository 이름과 맞춰주면 된다.

Authenticate to Google Cloud

      - id: 'auth'
        name: 'Authenticate to Google Cloud'
        uses: 'google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2' # google-github-actions/auth@v2
        with:
          workload_identity_provider: '${{ env.WORKLOAD_IDENTITY_PROVIDER }}'
          project_id: '${{ env.PROJECT_ID }}'
          service_account: '${{ env.EMAIL }}'

제공된 템플릿에는 workload_identity_provider 옵션만 존재했는데 오류가 발생한다.

Error: google-github-actions/get-gke-credentials failed with: required "container.clusters.get" permission(s) for "projects/***/zones/asia-northeast1-a/clusters/test-cluster".

project_id와 service_account를 추가해주니 해결됐다.

Build and push Docker container

      - name: 'Build and push Docker container'
        run: |-
          gcloud auth configure-docker ${GAR_LOCATION}-docker.pkg.dev
          
          DOCKER_TAG="${GAR_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${IMAGE}:${GITHUB_SHA}"
          
          ./gradlew ${{ env.MODULE }}:jibDockerBuild \
          -Dimage="${GAR_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${IMAGE}" \
          -Dtags=${GITHUB_SHA}
          
          docker push "${DOCKER_TAG}"

나는 이렇게 변형했는데 jib를 사용하고 있었기 때문에 dockerfile을 따로 사용하지 않았고,
push시 권한 문제가 발생해서 gcloud auth configure-docker ${GAR_LOCATION}-docker.pkg.dev 구문을 상단에 삽입해주었더니 해결 되었다.

Set up Kustomize

기존 템플릿을 사용하면 오류가 발생한다.

Run curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.4.3/kustomize_v5.4.3_linux_amd64.tar.gz 
Error: Process completed with exit code 23.

아래와 같이 수정해주어서 오류를 해결했다.

      - name: Setup Kustomize
        uses: imranismail/setup-kustomize@v1

명령어를 바로 사용할 수 있게 해주므로 다음 단계에서는 ./kustomize를 사용하는게 아닌 kustomize를 사용하도록한다.

Deploy to GKE

기존 Deploy to GKE 스텝에서 아래 명령어를 템플릿으로 제공해주고 있는데 LOCATION은 사실 변수 처리 되어야한다.

Before

./kustomize edit set image LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:TAG=$GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$IMAGE:$GITHUB_SHA

After

./kustomize edit set image ${GAR_LOCATION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:TAG=$GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$IMAGE:$GITHUB_SHA

위 코드는 overlay kustomization 파일에 적용이 되긴하나. base의 기존 이미지를 바꿔주지는 않는다.

그래서 overlay kustomization 파일에 아래와 같이 patch, replace, IMAGE_NAME 변수를 활용해서 이미지 이름을 동적으로 변경시켜주도록 했다.

kustomizaztion.yaml

patches:
- patch: |
    - op: replace
      path: /spec/template/spec/containers/0/image
      value: ${IMAGE_NAME}

kustomize가 IMAGE_NAME을 외부에서 주입 시켜주는 기능을 별도로 제공해주지 않는것 같으므로 envsubst를 활용한다.
해당 명령어는 변수를 export하고, 기존 kustomization.yaml 파일을 변수의 값으로 치환한 새 파일로 만들어준다.

export IMAGE_NAME=${GAR_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${IMAGE}:${GITHUB_SHA}
envsubst < kustomization.yaml > kustomization.tmp && mv kustomization.tmp kustomization.yaml

apply -k를 사용하여 kustomize를 적용하고 네임스페이스를 추가로 지정해준다.

kubectl apply -k .
kubectl rollout status deployment/$DEPLOYMENT_NAME -n ${{ env.PROFILE }}

최종

      - name: 'Deploy to GKE'
        run: |-
          cd overlays/${{ env.PROFILE }}
          export IMAGE_NAME=${GAR_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${IMAGE}:${GITHUB_SHA}
          envsubst < kustomization.yaml > kustomization.tmp && mv kustomization.tmp kustomization.yaml
          cat ./kustomization.yaml
          kustomize build .
          kubectl apply -k .
          kubectl rollout status deployment/$DEPLOYMENT_NAME -n ${{ env.PROFILE }}
          kubectl get services -o wide -n ${{ env.PROFILE }}

ImagePullBackOff, ErrImagePull

rollout 배포가 잘 되는 듯 하였으나 403에러가 발생하며 deployment describe에서 대략 이런 에러 이벤트를 확인할 수 있었다.

Error: ImagePullBackOff   

Failed to pull image "image": failed to pull and unpack ... "...": 
failed to resolve reference "image": failed to authorize: 
failed to fetch oauth token: unexpected status from GET request to ...: 403 Forbidden            
Error: ErrImagePull                              

403 에러가 발생했는데 이런 저런 시도와 검색 끝에 GKE 클러스터 노드에 할당된 서비스 계정이 별도로 있다는 것을 알았고 그 계정에 권한을 부여하면 해결할 수 있을 것 같았다.

VM 인스턴스에 들어가서 클러스터 노드의 세부정보에 서비스 계정이 있다.
별도로 지정해주지 않아 디폴트 서비스 계정으로 설정된 것 같다.

IAM에 들어가서 이 계정에 Artifact Registry 리더 역할을 부여해주면 Artifact Registry에 업로드된 이미지를 pull 받아올 수 있다.

0개의 댓글