지난 포스팅에서는 Prometheus와 Grafana를 도입하여 GKE 클러스터의 상태를 모니터링하는 환경을 구축했다. 이로써 서비스의 운영 안정성을 확보할 수 있었다.
하지만 배포 파이프라인에는 여전히 수동 개입이 필요한 한계가 존재했다. Docker 이미지 태그를 고정된 latest로 사용하고 있었기 때문에, Auto Sync 설정을 해둔 상태에서 새로운 이미지가 레지스트리에 푸시되어도 Argo CD는 Manifest YAML 파일의 변경 사항을 감지하지 못했다. 결국 배포를 위해서는 Argo CD에서 수동으로 Sync를 맞추거나 파드를 수동으로 터미널에서 재시작해야만 했다.
이번 포스팅에서는 Kustomize를 도입하여 이미지 태그에 불변성을 부여하고, CI 파이프라인이 변경된 태그를 Git 저장소에 자동으로 반영하게 함으로써 수동 개입 없이 완전한 GitOps 자동화를 완성한 과정을 기록한다.
1. 문제 정의: Mutable Tag의 한계와 GitOps
기존 파이프라인의 문제는 Docker 이미지 태그를 latest로 고정해서 사용했다는 점이다.
- CI (GitHub Actions): 새로운 코드로 이미지를 빌드하고
backend:latest로 덮어쓴다. - CD (Argo CD): Git 저장소의
backend.yaml을 확인한다. 여전히image: backend:latest라고 적혀 있다. - 결과: Argo CD는 Git과 클러스터 상태가 "동일하다"고 판단하여 아무런 동작도 수행하지 않는다.
완전한 자동 GitOps를 구현하기 위해서는 "어떤 버전의 이미지가 배포되어야 하는지" 가 Git에 명시적으로 선언되어야 했다. 즉, 배포마다 Git Commit SHA 등을 활용하여 고유한 식별자를 태그로 사용하고, 이 변경 사항이 Git Manifest에 반영되어야 Argo CD가 이를 감지하고 배포를 트리거할 수 있다.
2. 해결 방안: Kustomize 도입
YAML 파일을 직접 문자열 치환(sed 등)하는 방식은 관리가 어렵고 오류 발생 가능성이 높다. 따라서 쿠버네티스 네이티브 구성 관리 도구인 Kustomize를 도입했다.
Kustomize를 사용하면 원본 YAML 파일을 건드리지 않고도 이미지 태그와 같은 특정 필드만 깔끔하게 수정할 수 있다.
2.1. Kustomization 파일 작성
k8s 디렉토리에 kustomization.yaml 파일을 생성하고, 관리할 리소스와 이미지 정책을 정의했다.
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - backend.yaml - frontend.yaml - ingress.yaml - certificate.yaml images: - name: backend-image # 추상화된 이미지 이름 newName: asia-northeast3-docker.pkg.dev/[GCP_PROJECT_ID]/realtime-chat-repo/backend newTag: latest # 초기값 (CI 과정에서 변경됨) - name: frontend-image newName: asia-northeast3-docker.pkg.dev/[GCP_PROJECT_ID]/realtime-chat-repo/frontend newTag: latest
기존 backend.yaml과 frontend.yaml의 image 필드는 Kustomize가 인식할 수 있도록 backend-image, frontend-image와 같은 식별자로 수정했다.
3. CI 파이프라인 고도화 (GitHub Actions)
GitHub Actions 워크플로우(ci.yml)를 수정하여 다음의 Write-back 패턴을 구현했다.
- Build & Push: Git Commit SHA(
github.sha)를 태그로 사용하여 Docker 이미지를 빌드하고 푸시한다. - Update Manifest:
kustomize edit set image명령어를 사용하여kustomization.yaml의 태그 정보를 업데이트한다. - Commit & Push: 변경된 Manifest 파일을 Git 저장소에 다시 커밋하고 푸시한다.
# ... (인증 및 빌드 과정 생략) ... # [핵심] Kustomize를 사용하여 이미지 태그 업데이트 - name: Update Kubernetes Manifests run: | cd k8s # 백엔드 이미지 태그를 현재 Commit SHA로 변경 kustomize edit set image backend-image=${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO_NAME }}/backend:${{ github.sha }} # 프론트엔드 이미지 태그 변경 kustomize edit set image frontend-image=${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO_NAME }}/frontend:${{ github.sha }} cd .. # 변경된 kustomization.yaml을 Git에 커밋 및 푸시 - name: Commit and Push Manifest changes run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" git add k8s/kustomization.yaml if git diff-index --quiet HEAD; then echo "No changes to commit" else git commit -m "ci: update image tags to ${{ github.sha }}" git push origin main fi
4. 검증: 자동 배포 파이프라인 동작 확인
구축된 파이프라인이 의도대로 동작하는지 검증하기 위해 코드를 수정하고 Push를 진행했다. 데이터의 흐름에 따라 각 단계를 확인했다.
4.1. CI 로그 확인 (GitHub Actions)
GitHub Actions가 이미지 빌드 후, kustomization.yaml 파일을 수정하여 자동으로 커밋을 생성하는 것을 확인했다.

4.2. Git 저장소 변경 확인 (Source of Truth)
GitHub 저장소의 커밋 내역을 확인한 결과, 봇에 의해 newTag가 latest에서 특정 해시값(a1b2c...)으로 변경된 것을 확인할 수 있었다. 이제 Git 저장소는 배포된 버전에 대한 명확한 진실 공급원 역할을 하게 된다.

4.3. Argo CD 감지 및 동기화
Git 저장소의 변경이 발생하자, Argo CD가 이를 감지하고 Sync 프로세스를 시작했다. 애플리케이션 상세 정보에서 이미지 태그가 Git SHA 버전으로 업데이트된 것을 확인했다.

4.4. 실제 파드(Pod) 확인
마지막으로 GKE 클러스터 내부에서 실행 중인 파드의 정보를 조회하여, 실제 컨테이너가 해당 버전의 이미지를 사용하고 있는지 검증했다.
kubectl describe pod backend-xxxxxx

5. 결론 및 향후 계획
이번 작업을 통해 불변 태그(Immutable Tag) 를 기반으로 한 완전 자동화된 GitOps 파이프라인을 구축했다.
- 추적 가능성: 언제 어떤 버전이 배포되었는지 Git 커밋 히스토리만으로 완벽하게 추적 가능하다.
- 안정성:
latest태그 사용 시 발생할 수 있는 캐싱 문제나 버전 불일치 문제를 원천 차단했다. - 자동화: 개발자는 코드 작성에만 집중하면, 배포는 시스템이 알아서 수행한다.
이로써 GKE 환경에서의 인프라 구축과 배포 자동화 학습 목표를 모두 달성했다. 다음 단계에서는 현재의 단일 채팅방 구조를 게시글별 채팅, 관리자 1:1 문의 등으로 확장하는 애플리케이션 고도화 작업을 진행할 예정이다. 또한, 학습이 완료된 후에는 비용 효율성을 고려하여 프리티어 범위 내의 아키텍처(단일 VM 등)로 마이그레이션하는 과정도 다룰 계획이다.
