Search

Kustomize

Kustomize 란?

Kustomize 구조

1. Git Action 에서 적용

1) 매니페스트 레포지토리 구조 설계

Kustomize를 이용한 배포 자동화를 적용하기 위해서는 어플리케이션 소스코드 레포지토리와는 별도로
Kubernetes 매니페스트만을 관리하는 전용 저장소를 사용하는 것이 이상적이다.
이를 통해 이미지 빌드/테스트 파이프라인과 배포 파이프라인을 명확히 분리하고, GitOps 도구(Argo CD 등)가 이를 감시하도록 구성할 수 있다.
manifest-repo/ ├── front/ │ ├── base/ │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── ingress.yaml │ │ └── kustomization.yaml │ └── overlays/ │ ├── dev/ │ │ └── kustomization.yaml │ └── prod/ │ └── kustomization.yaml └── back/ └── ...
Plain Text
복사

2) GitHub Actions 워크플로 구성

- name: Install kustomize run: | curl -s "<https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh>" | bash sudo mv kustomize /usr/local/bin/ - name: Update DEV kustomization run: | cd frontend/overlays/dev kustomize edit set image $ECR_REGISTRY/$ECR_REPOSITORY=$ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} echo "📝 DEV kustomization 업데이트 완료" cat kustomization.yaml
YAML
복사
예시는 Kustomize를 활용해 deployment에 사용되는 image를 교체하는 내용이다.
kustomize를 설치하고 kustomize edit 등의 명령어를 통해 어떤 작업을 할지 정할 수 있다.

3) 환경별 배포 전략

dev 환경: 코드 변경 즉시 배포
prod 환경: 안정성이 검증된 이미지만 선택적으로 배포
브랜치 혹은 다른 레포지토리로 나눠서 관리
이 구조를 통해 개발과 운영 환경의 역할을 명확히 분리하고, 안정성과 유연성을 모두 확보할 수 있다.

2. EKS CI/CD용 Kustomize

1) ECR 이미지 관리 정책

CI 파이프라인에서 빌드한 이미지는 AWS ECR에 저장되고, Kustomize 매니페스트에서 이를 참조하여 자동 배포된다. 이미지 태그는 다음과 같은 정책을 따른다.
IMAGE_TAG=$(TZ='Asia/Seoul' date +'%Y%m%d-%H%M%S')
한국 시간 기준의 현재 날짜와 시간을 포맷해, 고유한 Docker 이미지 태그 문자열로 변수에 저장
예시 : 20250928-143745 (2025년 9월 28일 - 14시 37분 45초에 생성된 이미지)
다음 AWS ECR에 사용할 리포지토리를 구성한다.
프론트엔드와 백엔드, 개발용과 운영용(prod) 으로 총 4개의 리포지토리를 생성한다. 이 후 ECR URI를 확인한다.

2) 클러스터 환경 분리 (Namespace 구성)

개발(dev)과 운영(prod) 환경을 하나의 클러스터에서 안전하게 분리하기 위해 네임스페이스(namespace) 를 생성한다.
kubectl create namespace default kubectl create namespace default-prod
Bash
복사
default: 개발 환경
default-prod: 운영 환경
이렇게 나누면 동일한 클러스터 내에서도 설정 충돌 없이 dev/prod를 구분해서 배포할 수 있다.

3) 매니페스트 레포지토리 구성

매니페스트 전용 Git 레포지토리를 하나 만든다.
(예: enjoy-cd)
이 저장소는 Argo CD가 감시할 곳이며, baseoverlays 구조로 환경별 설정을 관리한다.
리포지토리 구성도
enjoy-cd/ ├── frontend/ │ ├── base/ │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── hpa.yaml │ │ └── kustomization.yaml │ └── overlays/ │ ├── dev/ │ ├── ingress.yaml │ │ └── kustomization.yaml │ └── prod/ │ ├── ingress.yaml │ └── kustomization.yaml ├── backend/ │ ├── base/ │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── hpa.yaml │ │ ├── db-secret.yaml │ │ └── kustomization.yaml │ └── overlays/ │ ├── dev/ │ ├── db-secret.yaml │ │ └── kustomization.yaml │ └── prod/ │ ├── db-secret.yaml └── └── kustomization.yaml
Smalltalk
복사
./base/kustomization.yaml 구성 예시
# backend/base/kustomization.yaml resources: - deployment.yaml - service.yaml - hpa.yaml - db-secret.yaml
YAML
복사
./overlays/dev/kustomization.yaml 구성 예시
# backend/overlays/dev/kustomization.yaml namespace: default resources: - ../../base - db-secret.yaml images: - name: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com/enjoy-back newName: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com/enjoy-back newTag: 20250926-170058 # GitHub Actions에서 자동으로 교체됨 apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization
YAML
복사
./overlays/prod/kustomization.yaml 구성 예시
# backend/overlays/prod/kustomization.yaml namespace: default-prod resources: - ../../base - db-secret.yaml images: - name: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com/enjoy-back-prod newName: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com/enjoy-back-prod newTag: 20250926-170058 # GitHub Actions에서 자동으로 교체됨 apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization
YAML
복사

4) GitHub Actions 워크플로 구현

프론트엔드 workflow
name: Build and Push Vue Frontend to ECR on: push: branches: [ "main" ] # ➜ dev에 자동 반영 (빌드) workflow_dispatch: inputs: environment: description: "배포 환경 선택" required: true default: "prod" type: choice options: [ "prod" ] image_tag: description: "DEV 이미지 태그 (비워두면 최신 태그 자동 선택)" required: false type: string jobs: build-dev: # DEV 환경: 실제 빌드 + ECR 업로드 if: github.event_name == 'push' runs-on: ubuntu-latest env: ECR_REGISTRY: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com ECR_REPOSITORY: enjoy-front steps: - name: Checkout source uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies and build run: | echo "VITE_KAKAO_MAP_API_SERVICE_KEY=${{ secrets.VITE_KAKAO_MAP_API_SERVICE_KEY }}" >> .env echo "VITE_VUE_API_URL=${{ secrets.VITE_VUE_API_URL }}" >> .env npm install npm run build - name: Get current time (KST) run: echo "IMAGE_TAG=$(TZ='Asia/Seoul' date +'%Y%m%d-%H%M%S')" >> $GITHUB_ENV - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-2 - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v1 - name: Build, tag, and push to DEV ECR run: | docker build \ -f Dockerfile.dev \ --build-arg VITE_VUE_API_URL=${{ secrets.VITE_VUE_API_URL }} \ -t $ECR_REPOSITORY:${{ env.IMAGE_TAG }} . docker tag $ECR_REPOSITORY:${{ env.IMAGE_TAG }} $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} docker push $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} echo "✅ DEV 이미지 업로드 완료: $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }}" - name: Checkout manifests repo uses: actions/checkout@v4 with: repository: cloud-pjt/enjoy-cd token: ${{ secrets.GH_PAT }} ref: develop - name: Install kustomize run: | curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash sudo mv kustomize /usr/local/bin/ - name: Update DEV kustomization run: | cd frontend/overlays/dev kustomize edit set image $ECR_REGISTRY/$ECR_REPOSITORY=$ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} echo "📝 DEV kustomization 업데이트 완료" cat kustomization.yaml - name: Commit and push DEV changes run: | git config user.name "sdpup" git config user.email "epflswu12@gmail.com" if ! git diff --quiet frontend/overlays/dev/; then git add frontend/overlays/dev/ # frontend 폴더만 추가 git commit -m "🔧 Update DEV frontend image to ${{ env.IMAGE_TAG }}" git push origin develop else echo "No frontend changes to commit." fi - name: Display next steps run: | echo "🎉 DEV 배포 완료!" echo "📋 PROD 배포를 원한다면:" echo " 1. Actions 탭에서 'Build and Push Vue Frontend to ECR' 워크플로우 선택" echo " 2. 'Run workflow' 클릭" echo " 3. Image tag에 입력: ${{ env.IMAGE_TAG }}" echo " 4. Environment: prod 선택 후 실행" promote-to-prod: # PROD 환경: DEV 이미지를 복사하는 대신 docker.prod로 재빌드 if: github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest env: ECR_REGISTRY: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com DEV_REPOSITORY: enjoy-front PROD_REPOSITORY: enjoy-front-prod steps: - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-2 - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v1 - name: Determine image tag to promote id: tag run: | if [ -n "${{ github.event.inputs.image_tag }}" ]; then IMAGE_TAG="${{ github.event.inputs.image_tag }}" echo "🎯 사용자 지정 태그 사용: $IMAGE_TAG" else IMAGE_TAG=$(aws ecr describe-images \ --repository-name $DEV_REPOSITORY \ --region ap-northeast-2 \ --query 'sort_by(imageDetails,&imagePushedAt)[-1].imageTags[0]' \ --output text) echo "🔄 최신 DEV 이미지 태그 자동 선택: $IMAGE_TAG" fi if [ "$IMAGE_TAG" = "null" ] || [ -z "$IMAGE_TAG" ]; then echo "❌ ERROR: DEV 레포지토리에서 유효한 이미지를 찾을 수 없습니다" exit 1 fi echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT echo "✅ 승격할 이미지 태그: $IMAGE_TAG" # ⬇️ 소스 코드 체크아웃 (docker.prod와 프론트 소스가 필요) - name: Checkout source uses: actions/checkout@v3 # (모노리포에서 다른 폴더라면 path 지정 가능) # with: # path: src # ⬇️ docker.prod로 Multi-Stage 빌드 & 푸시 (Node 설치/빌드 불필요) - name: Build and push PROD image (Multi-Stage) run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} echo "🏗️ docker.prod를 사용해 운영용 이미지 빌드 시작..." # docker.prod가 리포지토리 루트에 있을 때 docker build \ -f Dockerfile.prod \ --build-arg VITE_VUE_API_URL=${{ secrets.VITE_VUE_API_URL }} \ --build-arg VITE_KAKAO_MAP_API_SERVICE_KEY=${{ secrets.VITE_KAKAO_MAP_API_SERVICE_KEY }} \ -t $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG . docker push $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG echo "✅ PROD Multi-Stage 이미지 업로드 완료: $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG" # ⬇️ 매니페스트 레포 체크아웃 (작업공간 덮어쓰기 피하려면 path 지정 권장) - name: Checkout manifests repo uses: actions/checkout@v4 with: repository: cloud-pjt/enjoy-cd token: ${{ secrets.GH_PAT }} path: cd-repo - name: Install kustomize run: | curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash sudo mv kustomize /usr/local/bin/ - name: Update PROD kustomization working-directory: cd-repo/frontend/overlays/prod run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} kustomize edit set image $ECR_REGISTRY/$PROD_REPOSITORY=$ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG echo "📝 PROD kustomization 업데이트 완료" cat kustomization.yaml - name: Commit and push PROD changes working-directory: cd-repo run: | git config user.name "sdpup" git config user.email "epflswu12@gmail.com" if ! git diff --quiet frontend/overlays/prod/; then git add frontend/overlays/prod/ git commit -m "🚀 Promote DEV image ${{ steps.tag.outputs.IMAGE_TAG }} to PROD (rebuild with docker.prod)" git push echo "✅ PROD 매니페스트 업데이트 완료" else echo "No manifest changes to commit." fi - name: Deployment summary run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} echo "🎉 PROD 배포 완료!" echo "📦 배포된 이미지: $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG" echo "🔗 docker.prod(Multi-Stage)로 재빌드된 이미지가 PROD에 배포되었습니다."
YAML
복사
백엔드 workflow
name: Build and Push Java Backend to ECR on: push: branches: [ "main" ] workflow_dispatch: inputs: environment: description: "배포 환경 선택" required: true default: "prod" type: choice options: [ "prod" ] image_tag: description: "DEV 이미지 태그 (비워두면 최신 태그 자동 선택)" required: false type: string jobs: build-dev: # DEV 환경: 빠른 빌드용 Dockerfile if: github.event_name == 'push' runs-on: ubuntu-latest env: ECR_REGISTRY: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com ECR_REPOSITORY: enjoy-back steps: - name: Checkout source uses: actions/checkout@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin' cache: maven - name: Get current time (KST) run: echo "IMAGE_TAG=$(TZ='Asia/Seoul' date +'%Y%m%d-%H%M%S')" >> $GITHUB_ENV - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-2 - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v1 # DEV용 Dockerfile.dev 사용 (빠른 빌드) - name: Build and push DEV image run: | docker build -f Dockerfile.dev -t $ECR_REPOSITORY:${{ env.IMAGE_TAG }} . docker tag $ECR_REPOSITORY:${{ env.IMAGE_TAG }} $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} docker push $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} echo "✅ DEV 이미지 업로드 완료: $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }}" - name: Checkout manifests repo uses: actions/checkout@v4 with: repository: cloud-pjt/enjoy-cd token: ${{ secrets.GH_PAT }} ref: develop - name: Install kustomize run: | curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash sudo mv kustomize /usr/local/bin/ - name: Update DEV kustomization run: | cd backend/overlays/dev kustomize edit set image $ECR_REGISTRY/$ECR_REPOSITORY=$ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }} echo "📝 DEV kustomization 업데이트 완료" cat kustomization.yaml - name: Commit and push DEV changes run: | git config user.name "sdpup" git config user.email "epflswu12@gmail.com" if ! git diff --quiet backend/; then git add backend/ # backend 폴더만 추가 git commit -m "🔧 Update DEV backend image to ${{ env.IMAGE_TAG }}" git push origin develop echo "✅ DEV 매니페스트 업데이트 완료" else echo "No backend changes to commit." fi - name: Display next steps run: | echo "🎉 DEV 배포 완료!" echo "📋 PROD 배포를 원한다면:" echo " 1. Actions 탭에서 'Build and Push Java Backend to ECR' 워크플로우 선택" echo " 2. 'Run workflow' 클릭" echo " 3. Image tag에 입력: ${{ env.IMAGE_TAG }}" echo " 4. Environment: prod 선택 후 실행" promote-to-prod: # PROD 환경: 경량화된 멀티스테이지 빌드 if: github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest env: ECR_REGISTRY: 255260635764.dkr.ecr.ap-northeast-2.amazonaws.com DEV_REPOSITORY: enjoy-back PROD_REPOSITORY: enjoy-back-prod steps: - name: Checkout source uses: actions/checkout@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin' cache: maven - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-2 - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v1 - name: Determine image tag to promote id: tag run: | if [ -n "${{ github.event.inputs.image_tag }}" ]; then IMAGE_TAG="${{ github.event.inputs.image_tag }}" echo "🎯 사용자 지정 태그 사용: $IMAGE_TAG" else IMAGE_TAG=$(aws ecr describe-images \ --repository-name $DEV_REPOSITORY \ --region ap-northeast-2 \ --query 'sort_by(imageDetails,&imagePushedAt)[-1].imageTags[0]' \ --output text) echo "🔄 최신 DEV 이미지 태그 자동 선택: $IMAGE_TAG" fi if [ "$IMAGE_TAG" = "null" ] || [ -z "$IMAGE_TAG" ]; then echo "❌ ERROR: DEV 레포지토리에서 유효한 이미지를 찾을 수 없습니다" exit 1 fi echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT echo "✅ 승격할 이미지 태그: $IMAGE_TAG" # PROD는 경량화된 Dockerfile.prod로 새로 빌드 - name: Build optimized PROD image run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} echo "🏗️ PROD용 경량화 이미지 빌드 중..." docker build -f Dockerfile.prod -t $PROD_REPOSITORY:$IMAGE_TAG . docker tag $PROD_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG docker push $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG echo "✅ PROD 이미지 빌드 완료:" echo " 경량화된 이미지: $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG" # 이미지 크기 비교 (참고용) DEV_SIZE=$(docker images $ECR_REGISTRY/$DEV_REPOSITORY:$IMAGE_TAG --format "table {{.Size}}" | tail -1) PROD_SIZE=$(docker images $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG --format "table {{.Size}}" | tail -1) echo "📊 이미지 크기 비교:" echo " DEV: $DEV_SIZE (빠른 빌드용)" echo " PROD: $PROD_SIZE (경량화됨)" - name: Checkout manifests repo uses: actions/checkout@v4 with: repository: cloud-pjt/enjoy-cd token: ${{ secrets.GH_PAT }} - name: Install kustomize run: | curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash sudo mv kustomize /usr/local/bin/ - name: Update PROD kustomization run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} cd backend/overlays/prod kustomize edit set image $ECR_REGISTRY/$PROD_REPOSITORY=$ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG echo "📝 PROD kustomization 업데이트 완료" cat kustomization.yaml - name: Commit and push PROD changes run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} git config user.name "sdpup" git config user.email "epflswu12@gmail.com" if ! git diff --quiet backend/; then git add backend/ git commit -m "🚀 Deploy optimized backend $IMAGE_TAG to PROD" git push echo "✅ PROD 매니페스트 업데이트 완료" fi - name: Deployment summary run: | IMAGE_TAG=${{ steps.tag.outputs.IMAGE_TAG }} echo "🎉 PROD 배포 완료!" echo "📦 배포된 이미지: $ECR_REGISTRY/$PROD_REPOSITORY:$IMAGE_TAG" echo "🔧 DEV: 빠른 빌드, 개발 최적화" echo "🚀 PROD: 멀티스테이지, 경량화, 보안 강화"
YAML
복사

5) Argo CD 앱 생성

Argo CD는 overlays 디렉토리를 감시하여 변경사항을 자동 반영한다.
예시) front-dev :
# argo.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: # Argo CD UI에 표시될 애플리케이션 이름 name: front-dev # Argo CD가 설치된 네임스페이스 namespace: argocd spec: project: default source: # 1단계에서 만든 Manifest 리포지토리 주소 repoURL: 'https://github.com/cloud-pjt/enjoy-cd.git' # 감시할 브랜치 targetRevision: main # YAML 파일들이 있는 경로 path: frontend/overlays/dev destination: # 배포할 대상 클러스터 (클러스터 내부를 의미) server: 'https://kubernetes.default.svc' # 배포할 네임스페이스 namespace: default # 동기화 정책 설정 syncPolicy: automated: prune: true # Git에서 사라진 리소스는 클러스터에서도 자동 삭제 selfHeal: true # 클러스터 상태가 Git과 다르면 자동으로 Git 상태로 복구 syncOptions: - CreateNamespace=true # 'argo-test' 네임스페이스가 없으면 자동 생성
YAML
복사
다음과 같이 app name, repoURL, targetRevision, path, destination-namespace 값에 주의 하면서 front-dev, front-prod, back-dev, back-prod 를 4개 구성해주면 된다.