GitOps란?
GitOps는 Git 저장소를 단일 진실 공급원(Single Source of Truth)으로 삼아 인프라와 애플리케이션을 선언적으로 관리하는 운영 방법론입니다. ArgoCD는 Kubernetes 환경에서 가장 널리 사용되는 GitOps 도구로, Git에 커밋된 매니페스트와 클러스터 상태를 자동으로 동기화합니다. 이 글에서는 ArgoCD의 아키텍처, Application 리소스 설정, Sync 전략, 멀티 클러스터 관리, Webhook 자동화까지 실전 패턴을 다룹니다.
ArgoCD 아키텍처
ArgoCD는 3개의 핵심 컴포넌트로 구성됩니다.
| 컴포넌트 | 역할 | 특징 |
|---|---|---|
| API Server | Web UI, CLI, gRPC API 제공 | RBAC, SSO 인증 처리 |
| Repo Server | Git 저장소에서 매니페스트 생성 | Helm, Kustomize, Jsonnet 지원 |
| Application Controller | 클러스터 상태와 Git 상태 비교·동기화 | 3분 주기 폴링 (기본값) |
동작 흐름: Git 커밋 → Repo Server가 매니페스트 렌더링 → Controller가 차이 감지 → 클러스터에 적용(Sync)
ArgoCD 설치
Helm Chart로 설치하는 것이 운영 환경에서 권장됩니다.
# Helm으로 설치
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd
--namespace argocd
--create-namespace
--set server.service.type=LoadBalancer
--set configs.params.server.insecure=true
--set server.extraArgs={--insecure}
# 초기 admin 비밀번호 확인
kubectl -n argocd get secret argocd-initial-admin-secret
-o jsonpath="{.data.password}" | base64 -d
# CLI 로그인
argocd login argocd.example.com --username admin --password <password>
# 비밀번호 변경
argocd account update-password
Application 리소스 정의
ArgoCD의 핵심은 Application CRD입니다. Git 저장소와 클러스터 목적지를 연결합니다.
# 기본 Application 정의
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-api
namespace: argocd
# Finalizer: 앱 삭제 시 클러스터 리소스도 함께 삭제
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main # 브랜치, 태그, 커밋 해시
path: apps/my-api/overlays/production
destination:
server: https://kubernetes.default.svc # in-cluster
namespace: production
# 동기화 정책
syncPolicy:
automated:
prune: true # Git에서 삭제된 리소스 → 클러스터에서도 삭제
selfHeal: true # 수동 변경(kubectl edit) → Git 상태로 복원
allowEmpty: false # 빈 매니페스트 방지
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true # 다른 리소스 먼저 동기화 후 삭제
retry:
limit: 3
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Helm 차트 소스 설정
Git에 저장된 Helm 차트나 외부 Helm 레포지토리를 소스로 사용하는 패턴입니다.
# Git 내 Helm 차트 참조
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-api-helm
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/helm-charts.git
targetRevision: main
path: charts/my-api
helm:
releaseName: my-api
# values 파일 참조 (같은 저장소 내)
valueFiles:
- values.yaml
- values-prod.yaml
# 인라인 값 오버라이드
parameters:
- name: image.tag
value: "v1.5.2"
- name: replicaCount
value: "4"
# values를 직접 정의
values: |
ingress:
enabled: true
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
destination:
server: https://kubernetes.default.svc
namespace: production
# 외부 Helm 레포지토리 사용
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: redis
namespace: argocd
spec:
source:
repoURL: https://charts.bitnami.com/bitnami
chart: redis # chart 필드 사용 (path 대신)
targetRevision: 18.6.1
helm:
releaseName: redis
values: |
architecture: standalone
auth:
enabled: true
password: my-redis-pass
destination:
server: https://kubernetes.default.svc
namespace: production
Kustomize 소스 설정
Kustomize의 overlay 패턴과 ArgoCD를 결합하면 환경별 배포를 깔끔하게 관리할 수 있습니다.
# 디렉터리 구조
apps/my-api/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
└── overlays/
├── staging/
│ ├── kustomization.yaml
│ └── replica-patch.yaml
└── production/
├── kustomization.yaml
├── replica-patch.yaml
└── resource-patch.yaml
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
patches:
- path: replica-patch.yaml
- path: resource-patch.yaml
images:
- name: myorg/my-api
newTag: v1.5.2
commonLabels:
env: production
# ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-api-prod
namespace: argocd
spec:
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: apps/my-api/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
AppProject로 권한 분리
팀별로 배포 가능한 클러스터, 네임스페이스, 저장소를 제한합니다. K8s ResourceQuota와 함께 멀티테넌시를 구성할 수 있습니다.
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: backend-team
namespace: argocd
spec:
description: "백엔드 팀 프로젝트"
# 허용된 Git 저장소
sourceRepos:
- https://github.com/myorg/backend-*
- https://charts.bitnami.com/bitnami
# 배포 허용 대상
destinations:
- server: https://kubernetes.default.svc
namespace: backend-* # 와일드카드 지원
- server: https://kubernetes.default.svc
namespace: staging
# 배포 허용/거부 리소스
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota # ResourceQuota 수정 불가
# 역할 정의 (RBAC)
roles:
- name: developer
description: "배포 및 동기화 권한"
policies:
- p, proj:backend-team:developer, applications, get, backend-team/*, allow
- p, proj:backend-team:developer, applications, sync, backend-team/*, allow
groups:
- backend-developers # SSO 그룹 매핑
- name: viewer
policies:
- p, proj:backend-team:viewer, applications, get, backend-team/*, allow
groups:
- backend-viewers
Sync Wave와 Hook
리소스 간 배포 순서가 중요할 때 Sync Wave로 순서를 제어하고, Hook으로 배포 전후 작업을 실행합니다.
# Sync Wave: 숫자가 낮은 것부터 순서대로 적용
# Wave -1: 네임스페이스, ConfigMap
# Wave 0: 기본 (Deployment, Service)
# Wave 1: Ingress, HPA
# Wave 2: 모니터링 설정
# namespace.yaml — 가장 먼저 생성
apiVersion: v1
kind: Namespace
metadata:
name: production
annotations:
argocd.argoproj.io/sync-wave: "-1"
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
annotations:
argocd.argoproj.io/sync-wave: "-1"
data:
DATABASE_URL: "jdbc:postgresql://db:5432/mydb"
# deployment.yaml — 기본 wave (0)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api
annotations:
argocd.argoproj.io/sync-wave: "0"
# ...
# DB 마이그레이션 Job — PreSync Hook
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: myorg/my-api:v1.5.2
command: ["npm", "run", "migration:run"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
# Slack 알림 — PostSync Hook
apiVersion: batch/v1
kind: Job
metadata:
name: notify-deploy
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: notify
image: curlimages/curl:8.5.0
command:
- curl
- -X
- POST
- -H
- "Content-Type: application/json"
- -d
- '{"text":"✅ my-api v1.5.2 배포 완료"}'
- $(SLACK_WEBHOOK_URL)
env:
- name: SLACK_WEBHOOK_URL
valueFrom:
secretKeyRef:
name: slack-webhook
key: url
ApplicationSet으로 대량 앱 관리
여러 환경이나 마이크로서비스를 하나의 템플릿으로 생성합니다.
# List Generator: 환경별 앱 자동 생성
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: my-api-envs
namespace: argocd
spec:
generators:
- list:
elements:
- env: staging
namespace: staging
revision: develop
replicas: "1"
- env: production
namespace: production
revision: main
replicas: "4"
template:
metadata:
name: 'my-api-{{env}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: '{{revision}}'
path: 'apps/my-api/overlays/{{env}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
# Git Generator: 디렉터리 구조에서 자동 검색
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: all-apps
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/myorg/k8s-manifests.git
revision: main
directories:
- path: apps/*/overlays/production
template:
metadata:
name: '{{path.basename}}-prod'
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: production
Webhook으로 즉시 동기화
ArgoCD는 기본 3분 주기로 Git을 폴링합니다. GitHub Webhook을 설정하면 커밋 즉시 동기화를 트리거할 수 있습니다.
# GitHub Webhook 설정
# URL: https://argocd.example.com/api/webhook
# Content type: application/json
# Secret: argocd-webhook-secret
# Events: Push events
# ArgoCD에 Webhook secret 등록
kubectl -n argocd edit configmap argocd-secret
# data 섹션에 추가
data:
webhook.github.secret: "argocd-webhook-secret"
# 또는 Notification으로 Slack 연동
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
trigger.on-sync-succeeded: |
- when: app.status.sync.status == 'Synced'
send: [app-sync-succeeded]
template.app-sync-succeeded: |
slack:
attachments: |
[{
"color": "#18be52",
"title": "{{.app.metadata.name}} 동기화 완료",
"text": "리비전: {{.app.status.sync.revision}}",
"fields": [{
"title": "네임스페이스",
"value": "{{.app.spec.destination.namespace}}",
"short": true
}]
}]
정리
ArgoCD GitOps는 “Git에 커밋 = 배포”라는 단순한 원칙으로 Kubernetes 운영을 혁신합니다. Application CRD로 소스와 목적지를 선언하고, automated.selfHeal로 드리프트를 자동 복구하며, Sync Wave/Hook으로 배포 순서를 제어합니다. ApplicationSet으로 환경별·서비스별 앱을 대량 생성하고, AppProject로 팀별 권한을 분리하세요. Git 히스토리가 곧 배포 히스토리가 되는 것이 GitOps의 핵심 가치입니다.