Kubernetes 개발·운영 실전 6편 — 멀티 환경 배포 전략 (Kustomize + ArgoCD)
Kustomize overlay로 dev/staging/prod 환경 설정을 분리하고 ArgoCD App of Apps 패턴으로 전체 클러스터를 GitOps로 관리하는 실전 가이드.
TestForge Team ·
멀티 환경 관리의 핵심 문제
dev, staging, prod 세 환경에서 같은 애플리케이션을 운영합니다. 환경마다 다른 것들이 있습니다.
- 이미지 태그 (dev:
latest, prod:1.2.3) - replicas (dev: 1, prod: 3)
- 도메인 (
dev.example.comvsexample.com) - 리소스 요청/제한
- 외부 서비스 연결 정보 (DB URL, Redis URL)
이걸 파일 복사로 관리하면 한 환경에서 고친 것을 다른 환경에 반영하는 것을 잊어 드리프트가 생깁니다. Kustomize는 공통 기반(base) + 환경별 오버라이드(overlay) 구조로 이 문제를 해결합니다.
1. Kustomize 디렉터리 구조
k8s/
├── base/ # 공통 기반 매니페스트
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── patch-deployment.yaml
├── staging/
│ ├── kustomization.yaml
│ └── patch-deployment.yaml
└── prod/
├── kustomization.yaml
├── patch-deployment.yaml
└── patch-hpa.yaml
2. base 구성
base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: my-app
managed-by: kustomize
base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-registry/my-app:latest
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
envFrom:
- configMapRef:
name: my-app-config
3. overlay 구성
overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: development
bases:
- ../../base
patches:
- path: patch-deployment.yaml
images:
- name: my-registry/my-app
newTag: dev-latest
configMapGenerator:
- name: my-app-config
behavior: merge
literals:
- LOG_LEVEL=debug
- DATABASE_URL=postgres://dev-db:5432/myapp
overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
bases:
- ../../base
patches:
- path: patch-deployment.yaml
- path: patch-hpa.yaml
images:
- name: my-registry/my-app
newTag: "1.2.3"
configMapGenerator:
- name: my-app-config
behavior: merge
literals:
- LOG_LEVEL=info
- DATABASE_URL=postgres://prod-db:5432/myapp
overlays/prod/patch-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
template:
spec:
containers:
- name: my-app
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
overlays/prod/patch-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
배포 및 미리보기
# 렌더링 결과 확인 (배포 없음)
kubectl kustomize overlays/prod
# 배포
kubectl apply -k overlays/prod
# dev 배포
kubectl apply -k overlays/dev
4. ArgoCD App of Apps 패턴
단일 ArgoCD Application으로 전체 클러스터의 모든 앱을 관리합니다.
Git 저장소 구조
gitops-repo/
├── apps/ # App of Apps 루트
│ ├── kustomization.yaml
│ ├── my-app.yaml
│ ├── api-gateway.yaml
│ └── monitoring.yaml
└── manifests/
├── my-app/
│ └── overlays/prod/
├── api-gateway/
│ └── overlays/prod/
└── monitoring/
└── overlays/prod/
루트 Application (App of Apps)
# bootstrap/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/gitops-repo
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
개별 Application 정의
# apps/my-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: production
source:
repoURL: https://github.com/myorg/gitops-repo
targetRevision: main
path: manifests/my-app/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Git에서 삭제된 리소스 클러스터에서도 삭제
selfHeal: true # 수동 변경 감지 시 자동 복구
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA가 관리하는 replicas 무시
5. CI/CD 파이프라인 연결
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
IMAGE_TAG=${GITHUB_SHA::8}
docker build -t $REGISTRY/my-app:$IMAGE_TAG .
docker push $REGISTRY/my-app:$IMAGE_TAG
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
- name: Update image tag in gitops repo
run: |
git clone https://github.com/myorg/gitops-repo
cd gitops-repo
# Kustomize로 이미지 태그 업데이트
cd manifests/my-app/overlays/prod
kustomize edit set image my-registry/my-app:$IMAGE_TAG
git config user.email "ci@github.com"
git config user.name "GitHub Actions"
git add .
git commit -m "chore: update my-app image to $IMAGE_TAG"
git push
ArgoCD가 Git 변경을 감지해 자동으로 클러스터에 반영합니다.
6. 환경 프로모션 전략
[개발자 PR]
↓ merge to main
[CI: 이미지 빌드 + dev 태그 업데이트]
↓ ArgoCD auto sync
[dev 환경 배포]
↓ 테스트 통과 후 수동 프로모션
[staging 태그 업데이트 PR]
↓ merge
[staging 환경 배포]
↓ QA 승인
[prod 태그 업데이트 PR + 리뷰]
↓ merge
[prod 환경 배포]
# 프로모션 스크립트 — staging → prod
#!/bin/bash
CURRENT_TAG=$(kustomize cfg grep --path manifests/my-app/overlays/staging | grep newTag | awk '{print $2}')
cd manifests/my-app/overlays/prod
kustomize edit set image my-registry/my-app:$CURRENT_TAG
git add . && git commit -m "chore: promote my-app $CURRENT_TAG to prod"
git push origin -u promote/my-app-$CURRENT_TAG
7. 드리프트 감지
# ArgoCD CLI로 동기화 상태 확인
argocd app list
argocd app diff my-app
# 클러스터와 Git 상태 비교
argocd app sync my-app --dry-run
# 수동 변경 감지 및 복구
argocd app sync my-app --force
시리즈 마무리 — 전체 아키텍처
이 시리즈에서 구성한 Kubernetes 개발·운영 체계를 정리합니다.
[개발자 로컬]
Kind 클러스터 + Skaffold/Tilt → 빠른 개발 루프
[코드 구조]
Namespace + RBAC → 팀·환경 격리
WorkloadType 선택 → 서비스 특성에 맞는 배포 단위
[네트워크]
ClusterIP + Ingress + NetworkPolicy → 명시적 트래픽 제어
[배포 관리]
Helm Chart → 템플릿화 + 버전 관리
Kustomize overlay → 환경별 설정 분리
[GitOps]
ArgoCD App of Apps → Git이 Single Source of Truth
CI/CD 이미지 태그 업데이트 → 자동 배포 파이프라인
각 편에서 다룬 내용이 하나의 흐름으로 연결됩니다. 로컬에서 개발한 코드가 Git을 거쳐 프로덕션까지 일관된 방식으로 배포되는 구조입니다.