이 글의 목적
GitHub Actions로 GKE(Google Kubernetes Engine)에 자동 배포하는 과정을, 처음 설정하며 실제로 막혔던 지점과 함께 정리한다. 인프라 학습 시리즈의 6편으로, 4편(GKE 연결)·7편(ArgoCD) 사이에서 "코드가 push되면 어떻게 클러스터까지 가는가"를 담당한다.
요약: Repository 준비 → 워크플로 인식 확인(manual-test) → GKE 자동 배포 연결. 마지막에서 서비스 계정 토큰 권한 때문에 한 번 크게 막혔고, 그 과정에서 OIDC의 필요성을 체감했다.
1단계 — Repository와 워크플로 디렉터리 준비
GitHub에서 새 Repository를 만들고, 로컬 작업 폴더를 연결한다. GitHub Actions는 .github/workflows/ 아래의 YAML 파일을 자동으로 인식하므로, 이 경로를 먼저 만든다.
git init
git remote add origin https://github.com/<user>/<repo>.git
mkdir -p .github/workflows
git add . && git commit -m "init" && git push -u origin main
2단계 — 워크플로가 인식되는지 먼저 확인 (manual-test)
GKE 연결을 바로 붙이기 전에, "워크플로 자체가 트리거되는가"만 먼저 검증했다. workflow_dispatch(수동 실행) 트리거를 가진 최소 워크플로를 올리면, Actions 탭에서 버튼으로 직접 돌려볼 수 있다.
# .github/workflows/manual-test.yaml
name: Manual test
on:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Echo
run: echo "workflow가 인식되고 실행됩니다"
Actions 탭 → 좌측 Manual test → Run workflow 를 누르면 job이 돌고, 각 step의 로그를 펼쳐 확인할 수 있다. 여기까지 초록불이 들어오면 "파이프라인 배선"은 정상이라는 뜻이라, 다음 단계의 실패는 권한·설정 문제로 범위를 좁힐 수 있다.
3단계 — GKE 자동 배포 연결
다음을 준비한다.
- 필수 API 활성화:
container.googleapis.com,artifactregistry.googleapis.com - Artifact Registry 저장소 생성(이미지 push 대상)
- 배포용 서비스 계정 + IAM 역할:
roles/artifactregistry.writer,roles/container.developer - GitHub Secrets:
GCP_PROJECT,GKE_CLUSTER,GKE_ZONE, 인증 자격증명
배포 워크플로의 뼈대는 이미지 빌드 → Artifact Registry push → GKE에 rollout 세 단계다.
# .github/workflows/deploy.yaml
name: Deploy to GKE
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.DEPLOY_SA }}
- uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: ${{ secrets.GKE_CLUSTER }}
location: ${{ secrets.GKE_ZONE }}
- name: Build & Push
run: |
gcloud auth configure-docker $REGION-docker.pkg.dev -q
docker build -t $IMAGE:$GITHUB_SHA .
docker push $IMAGE:$GITHUB_SHA
- name: Rollout
run: |
kubectl set image deployment/app app=$IMAGE:$GITHUB_SHA
kubectl rollout status deployment/app
관측된 문제와 해결 — "토큰 발급 권한이 없다"
IAM 역할을 다 부여한 뒤에도 Actions에서 배포가 동일하게 실패했다. 에러의 실질 원인은 연결된 계정이 서비스 계정 토큰을 발급할 권한이 없다는 것이었다.
| 증상 | 원인 | 해결 |
|---|---|---|
| IAM 역할 부여 후에도 인증 실패 | 토큰 발급(Token Creator) 권한 부재 | roles/iam.serviceAccountTokenCreator 부여 |
| Actions에선 실패, CMD 직접 실행은 성공 | 브랜치 지정 등 실행 컨텍스트 차이로 추정 | 브랜치를 명시해 실행하니 통과 |
| Autopilot에서 IP 이슈 | Artifact Registry 리전(US)과 클러스터 불일치, Autopilot은 Global IP 요구 | 리전 정렬은 다음 과제로 분리(불필요한 Global Static IP 생성은 지양) |
로컬 CMD로 같은 명령을 돌렸을 때는 성공했는데, 이전 실행과의 차이를 되짚어 보니 브랜치를 지정해 작동시킨 점이 달랐다. 결국 마지막 명령이 통과하면서 GitHub Actions가 정상 동작하는 것을 확인했다.
깨달음 — Secrets에 키를 올리는 방식의 한계와 OIDC
이 과정에서 가장 크게 남은 건 보안 모델에 대한 의문이었다. GitHub Secrets에 서비스 계정 키(JSON)를 올린다는 것 자체가, 장기 자격증명이 저장공간에 상주한다는 뜻이다. 여기서 OIDC(워크로드 아이덴티티 연합)라는 개념을 알게 됐다.
- OIDC를 쓰면 GitHub Actions가 실행 시점에 단기 토큰을 발급받아 GCP에 인증한다 — 장기 키를 저장하지 않는다.
- 위
deploy.yaml의google-github-actions/auth@v2+workload_identity_provider가 바로 이 방식이다(키 JSON 대신 WIF Provider를 가리킨다). - 개념적으로는 "저장공간에 키를 두지 않고, 신뢰 관계로 짧게 살아 있는 토큰을 그때그때 발급"하는 모델로 이해됐다.
다음에는 Kubernetes 앱 배포·코드 배포·DB 설정 배포 각각에 OIDC를 적용해, 저장된 키를 없애는 방향으로 정리할 계획이다.
흔한 함정
- IAM 역할만 부여하고
serviceAccountTokenCreator를 빠뜨리면, 권한이 충분해 보여도 토큰 발급에서 막힌다. - Artifact Registry 리전과 클러스터 리전이 어긋나면 네트워킹·IP에서 불필요한 우회가 생긴다. 처음부터 리전을 맞추는 게 낫다.
- 장기 서비스 계정 키를 Secrets에 두는 방식은 동작은 하지만 보안상 권장되지 않는다 — 가능하면 OIDC로 전환한다.
다음 단계
Autopilot에서 Standard Cluster로 전환하며 리전 정렬·네트워킹을 다시 점검하고, 배포 경로 전반에 OIDC를 적용한다. 시리즈의 다음 편(ArgoCD)에서 GitOps 방식의 배포와 비교한다.
GKE 인프라 학습 시리즈 (요약본)
- GKE 인프라 학습 시리즈 시작 (개요·계획)
- (4-1) K8S를 GKE와 연결
- GKE에 직접 띄우고 비용 줄이기 (API 서버·K8s 실행·비용 최적화)
- (6) GitHub Actions (현재 글)
- (7) ArgoCD
- 도메인 발급 및 GKE와의 연결
📚 이 시리즈는 네이버 블로그 원본 10편을 요약·정리한 것입니다. 세부 절차를 순서대로 따라 하려면 → 네이버 블로그 원본 시리즈
답글 남기기