ArgoCD를 사용한 GitOps: 선언적 배포 및 점진적 롤아웃
GitOps는 Git을 코드 저장소에서 단일 진실 소스 Kubernetes 클러스터의 상태를 확인하세요. 아이디어는 간단하지만 강력합니다. 모든 것이 배포됩니다. 클러스터의 내용은 Git 버전의 YAML 매니페스트에 설명되어 있어야 합니다. 클러스터의 에이전트 (ArgoCD)는 저장소를 관찰하고 클러스터의 실제 상태가 항상 수렴되는지 확인합니다. Git에서 원하는 상태로. 누군가 수동으로 핫픽스를 직접 적용하는 경우 kubectl, ArgoCD는 이를 감지하고 자동으로 취소합니다.
이 기사에서는 구성 방법을 살펴 보겠습니다. 아르고CD 처음부터, 구현하다 패턴 앱 중의 앱 수십 개의 애플리케이션을 선언적으로 관리하고, 사용하다 애플리케이션 세트 멀티 클러스터, 멀티 환경을 위한 통합 아르고 롤아웃 카나리아 배포 및 다운타임 없는 블루-그린을 위해.
무엇을 배울 것인가
- Helm을 사용한 ArgoCD 설치 및 구성
- Git과 동기화된 배포를 위한 애플리케이션 ArgoCD 생성
- 많은 애플리케이션을 관리하는 Apps 패턴의 앱
- ApplicationSet: 자동화된 다중 클러스터 및 다중 환경 배포
- 동기화 정책: 자동 동기화, 자가 복구, 정리
- Argo Rollouts: 통계 분석 기능이 있는 카나리아, 청록색, 트래픽 분할
- 다중 팀 환경을 위한 ArgoCD RBAC
- 배포 이벤트에 대한 Slack/Teams 알림
아르고CD 설치
# Installa ArgoCD con Helm (raccomandato per produzione)
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--version 7.6.0 \
--set global.domain=argocd.company.com \
--set server.ingress.enabled=true \
--set server.ingress.ingressClassName=nginx \
--set configs.params."server.insecure"=true \
--set dex.enabled=false # disabilita se non usi SSO
# Ottieni la password admin iniziale
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
# Accedi con ArgoCD CLI
argocd login argocd.company.com
argocd account update-password
# Verifica stato
argocd version
kubectl get pods -n argocd
첫 번째 애플리케이션 ArgoCD
에이 애플리케이션 ArgoCD는 주요 리소스입니다. 출처를 정의합니다. 매니페스트(소스) 및 배포 위치(대상)를 가져옵니다.
# application-api-service.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-service-production
namespace: argocd
labels:
team: team-alpha
environment: production
finalizers:
- resources-finalizer.argocd.argoproj.io # elimina risorse K8s quando Application viene eliminata
spec:
project: team-alpha # ArgoCD Project per RBAC
source:
repoURL: https://github.com/company/k8s-manifests
targetRevision: main # branch/tag/commit SHA
path: apps/api-service/production # path nel repo
destination:
server: https://kubernetes.default.svc # cluster locale
namespace: team-alpha-production
syncPolicy:
automated:
prune: true # elimina risorse non piu presenti in Git
selfHeal: true # ripristina modifiche manuali non autorizzate
syncOptions:
- CreateNamespace=true # crea namespace se non esiste
- PrunePropagationPolicy=foreground
- ApplyOutOfSyncOnly=true # applica solo le risorse cambiate
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# Ignorare alcune differenze (es. annotation aggiunte dal cluster)
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # ignora modifiche manuali al numero di repliche
GitOps용 Git 저장소의 구조
GitOps 저장소의 구조는 유지 관리 가능성에 직접적인 영향을 미칩니다. 가장 많은 패턴 K8s 매니페스트 저장소에서 애플리케이션 코드 저장소를 공통화하고 분리합니다.
# Struttura raccomandata del repo k8s-manifests:
k8s-manifests/
├── apps/ # manifest applicazioni
│ ├── api-service/
│ │ ├── base/ # Kustomize base
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── kustomization.yaml
│ │ ├── dev/
│ │ │ ├── kustomization.yaml # overlays per dev
│ │ │ └── resources-patch.yaml
│ │ ├── staging/
│ │ │ └── kustomization.yaml
│ │ └── production/
│ │ ├── kustomization.yaml
│ │ └── hpa.yaml
│ └── worker-service/
│ └── ...
├── platform/ # risorse platform (ingress, cert-manager, etc.)
│ ├── ingress-nginx/
│ ├── cert-manager/
│ └── monitoring/
└── argocd/ # App of Apps: Application resources
├── root-app.yaml # App of Apps root
├── team-alpha.yaml
└── platform.yaml
# Kustomize base per api-service
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: api-service
managed-by: argocd
# production/kustomization.yaml - overlay con 3 repliche
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../base
replicas:
- name: api-service
count: 3
images:
- name: company.registry.io/api-service
newTag: "v2.5.1" # aggiornato dalla CI/CD pipeline
patchesStrategicMerge:
- resources-patch.yaml
앱 패턴의 앱
App of Apps를 사용하면 단일 ArgoCD 애플리케이션("루트 앱")이 모든 것을 관리합니다. 다른 ArgoCD 응용 프로그램. 이는 애플리케이션이 많은 클러스터에 가장 확장성이 뛰어난 패턴입니다.
# argocd/root-app.yaml - la App of Apps root
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/k8s-manifests
targetRevision: main
path: argocd/ # questa cartella contiene le Application resources
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
---
# argocd/team-alpha.yaml - Application che punta agli overlay di team-alpha
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: team-alpha-production
namespace: argocd
spec:
project: team-alpha
source:
repoURL: https://github.com/company/k8s-manifests
targetRevision: main
path: apps/api-service/production
kustomize:
images:
- company.registry.io/api-service:v2.5.1 # aggiornato dalla CI
destination:
server: https://kubernetes.default.svc
namespace: team-alpha-production
syncPolicy:
automated:
prune: true
selfHeal: true
ApplicationSet: 다중 클러스터 및 다중 환경
애플리케이션 세트 하나에서 여러 ArgoCD 응용 프로그램을 자동으로 생성합니다. 템플릿. 여러 클러스터 또는 환경에 동일한 애플리케이션을 배포하는 데 적합합니다.
# applicationset-multi-env.yaml
# Deploy api-service su dev, staging e production dallo stesso template
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: api-service-all-envs
namespace: argocd
spec:
generators:
- list:
elements:
- environment: dev
namespace: team-alpha-dev
replicaCount: "1"
imageTag: "latest"
cluster: in-cluster
- environment: staging
namespace: team-alpha-staging
replicaCount: "2"
imageTag: "v2.5.0"
cluster: in-cluster
- environment: production
namespace: team-alpha-production
replicaCount: "5"
imageTag: "v2.4.9" # production usa tag stabile
cluster: production-cluster
template:
metadata:
name: 'api-service-{{environment}}'
labels:
environment: '{{environment}}'
spec:
project: team-alpha
source:
repoURL: https://github.com/company/k8s-manifests
targetRevision: main
path: 'apps/api-service/{{environment}}'
kustomize:
images:
- 'company.registry.io/api-service:{{imageTag}}'
destination:
server: '{{cluster}}'
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: '{{eq environment "production" | not}}' # no selfHeal in prod
Argo 롤아웃: Canary 배포 및 Blue-Green
Argo Rollouts는 고급 배포 전략으로 Kubernetes를 확장합니다. 분석 기능을 갖춘 카나리아 통계, 청록색(수동 또는 자동 전환 포함), Istio를 통한 트래픽 분할 또는 NGINX 입력:
# Installa Argo Rollouts
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts \
-f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
# Installa plugin kubectl
curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64
chmod +x kubectl-argo-rollouts-linux-amd64
sudo mv kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts
자동 분석을 통한 카나리아 배포
# rollout-canary.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
namespace: team-alpha-production
spec:
replicas: 10
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
spec:
containers:
- name: api
image: company.registry.io/api-service:v2.5.1
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 500m
memory: 1Gi
strategy:
canary:
# Step 1: 10% traffico alla nuova versione
# Step 2: analisi automatica per 5 minuti
# Step 3: se ok, vai al 30% poi 100%
steps:
- setWeight: 10 # 10% traffico al canary
- analysis: # analisi automatica
templates:
- templateName: success-rate
args:
- name: service-name
value: api-service
- pause: {duration: 5m}
- setWeight: 30
- pause: {duration: 5m}
- setWeight: 100
# Canary Service: il nuovo Service per il traffico canary
canaryService: api-service-canary
stableService: api-service-stable
# Traffic routing con NGINX Ingress
trafficRouting:
nginx:
stableIngress: api-service-ingress
---
# AnalysisTemplate: definisce i criteri di successo
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
namespace: team-alpha-production
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 1m
successCondition: result[0] >= 0.95 # 95% di successo richiesto
failureLimit: 3 # fallisce dopo 3 misurazioni consecutive < 95%
provider:
prometheus:
address: http://prometheus.monitoring.svc:9090
query: |
sum(rate(http_requests_total{service="{{args.service-name}}",status=~"2.."}[5m]))
/
sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))
- name: latency-p99
interval: 1m
successCondition: result[0] < 0.5 # P99 < 500ms
provider:
prometheus:
address: http://prometheus.monitoring.svc:9090
query: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{service="{{args.service-name}}"}[5m])) by (le)
)
CLI를 통한 출시 관리
# Visualizza stato del rollout in tempo reale
kubectl argo rollouts get rollout api-service -n team-alpha-production --watch
# Promuovi manualmente al prossimo step (se pause)
kubectl argo rollouts promote api-service -n team-alpha-production
# Rollback immediato se qualcosa va storto
kubectl argo rollouts abort api-service -n team-alpha-production
kubectl argo rollouts undo api-service -n team-alpha-production
# Dashboard UI di Argo Rollouts
kubectl argo rollouts dashboard &
# Apri http://localhost:3100
Slack 및 Teams용 ArgoCD 알림
# argocd-notifications-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
template.app-deployed: |
message: |
:rocket: Application *{{.app.metadata.name}}* deployed to *{{.app.spec.destination.namespace}}*
Image: `{{index .app.status.summary.images 0}}`
Sync: {{.app.status.sync.status}}
template.app-health-degraded: |
message: |
:red_circle: Application *{{.app.metadata.name}}* health degraded!
{{range .app.status.conditions}}{{.message}}{{end}}
trigger.on-deployed: |
- description: Application is synced and healthy
send:
- app-deployed
when: app.status.operationState.phase in ['Succeeded'] and
app.health.status == 'Healthy'
trigger.on-health-degraded: |
- description: Application has degraded
send:
- app-health-degraded
when: app.health.status == 'Degraded'
---
# Applica annotazione sull'Application per ricevere notifiche
kubectl annotate app api-service-production \
notifications.argoproj.io/subscribe.on-deployed.slack="deployments-channel" \
-n argocd
ArgoCD를 사용한 GitOps 모범 사례
프로덕션 GitOps 체크리스트
- K8s 앱 코드 및 매니페스트에 대한 별도의 저장소: GitOps 저장소에는 애플리케이션 코드가 포함되어서는 안 됩니다. 코드에서 구성을 분리
- GitOps 저장소의 이미지 태그("최신" 아님): 이미지 태그는 재현성을 위해 "최신"이 아닌 SHA 또는 특정 버전이어야 합니다.
- 생산을 위한 필수 검토: 지점 생산에 대한 PR에는 최소한 한 번의 승인이 필요합니다. ArgoCD는 프로덕션에서 검토 없이 자동으로 적용되어서는 안 됩니다.
- 외부 비밀 연산자를 사용한 비밀: GitOps 저장소에서 Secret을 명확하게 설정하지 마세요. AWS Secrets Manager 또는 Vault에서 ESO 사용
- 개발에서는 자가 복구, 프로덕션에서는 수동: 자동 자가 복구는 개발/스테이징에는 유용하지만 프로덕션에서는 위험합니다(긴급 핫픽스가 취소될 수 있음).
- 원시 YAML이 아닌 Kustomize 또는 Helm을 사용하십시오. 템플릿을 사용하면 중복을 방지하면서 환경별로 오버레이를 재사용할 수 있습니다.
결론 및 다음 단계
ArgoCD는 Kubernetes 배포를 수동적이고 위험한 작업에서 프로세스로 전환합니다. 자동화되고 감사 가능하며 되돌릴 수 있습니다. 관리용 앱과 앱의 결합 점진적인 카나리아 배포를 위한 클러스터 전체 선언 및 Argo 롤아웃을 통해 속도와 보안의 균형을 유지하는 전달 파이프라인입니다.
GitOps 이후의 자연스러운 다음 단계는 관찰 가능성입니다. 카나리아가 성공하는지 아니면 회귀를 도입하는지 알 수 있습니다. 기사 이 시리즈 중 11개(Prometheus, Grafana 및 OpenTelemetry)가 그림을 완성합니다.
Kubernetes at Scale 시리즈의 향후 기사
관련 시리즈
- DevSecOps — GitOps + 파이프라인의 보안 스캐닝
- 플랫폼 엔지니어링 — IDP의 구성 요소인 ArgoCD
- Terraform 및 코드형 인프라 — GitOps 이전의 클러스터 프로비저닝







