DevOpsDevOps 학습 로드맵 · 4/17편

Argo Rollouts로 카나리 배포와 Prometheus 메트릭 기반 자동 롤백 붙이기

기본 Deployment 롤링 업데이트가 못 보는 것부터, Argo Rollouts CRD로 트래픽을 단계적으로 흘리는 카나리 배포, Nginx Ingress 트래픽 분할, AnalysisTemplate으로 Prometheus 메트릭을 봐서 자동 롤백하는 절차, 블루그린 옵션까지.

2026-07-2412 min read
#Argo Rollouts#카나리 배포#ArgoCD#Prometheus#Nginx Ingress#GitOps#트래픽 미러링
DevOps 학습 로드맵시리즈 목차
1채용공고 요구사항 6개 중 자신 있게 답할 수 있는 게 절반도 안 됐다2kubeadm으로 온프레미스 Kubernetes 클러스터를 처음부터 세우는 절차3FastAPI 서비스 골격, RabbitMQ DLQ, Harbor+Trivy, Jenkins→ArgoCD 파이프라인 구축 절차4Argo Rollouts로 카나리 배포와 Prometheus 메트릭 기반 자동 롤백 붙이기5yaml 복붙 관리의 드리프트 문제를 Kustomize overlay로 구조화하기6Terraform과 Ansible로 클러스터를 코드에서 다시 세울 수 있게 만드는 절차7Prometheus·Loki 관측 스택 구축과 장애 주입 실험 설계 절차8SLI/SLO/에러 버짓을 실제로 계산해서 배포 판단 기준으로 써보기9임계값 없이 - 통계 기반 이상탐지로 Datadog Watchdog 흉내내기10Grafana OnCall로 PagerDuty 없이 온콜·에스컬레이션 구현하기11자체 JWT 구현부터 취약점 실험, Keycloak 마이그레이션까지의 실제 절차12ISMS-P 인프라 영역 심사를 가정하고 내 클러스터의 증적을 만드는 절차13SealedSecret이 못 남기는 것 - OpenBao + External Secrets Operator로 감사 로그 확보하기14번외: 더미 워커를 실제 ONNX 추론으로, GPU 스케줄링까지 교체하는 절차15번외: 인터넷을 완전히 끊고도 클러스터가 돌아가는지 - 폐쇄망(에어갭) 시뮬레이션 절차16번외: 부하테스트로 관측 스택을 실전 검증하기 - k6 + HPA + MSA 파이프라인17번외: DORA 4대 지표를 Four Keys로 자동 집계해보기

목표

지금까지 이 시리즈는 ArgoCD로 GitOps 배포까지는 갖췄지만(시리즈 2), 배포 전략 자체는 기본 Kubernetes Deployment의 롤링 업데이트에 머물러 있었다. 이 시리즈는 그 위 단계를 다룬다 - 새 버전에 트래픽을 조금씩만 흘려보고, 문제가 있으면 사람이 알아채기 전에 메트릭 기준으로 자동으로 되돌리는 배포를 만든다.

개념: Deployment 롤링 업데이트가 못 보는 것

기본 Deployment의 롤링 업데이트는 단순하다 - 새 파드를 하나씩 늘리고 옛 파드를 하나씩 줄인다. 이때 유일한 판단 기준은 헬스체크(liveness/readiness)를 통과하는가다. 문제는 헬스체크 통과와 "서비스가 제대로 동작하는가"가 다른 질문이라는 점이다 - 프로세스는 떠 있고 /healthz도 200을 반환하는데, 특정 API의 에러율만 조용히 올라가는 배포는 롤링 업데이트가 절대 잡아내지 못한다. 롤링 업데이트는 "파드가 살아있는지"만 보고, "트래픽을 받은 결과가 정상인지"는 보지 않는다.

Argo Rollouts는 Deployment를 대체하는 CRD(Rollout)로, 배포 과정에 단계·대기·검증을 끼워 넣을 수 있게 해준다. 핵심 개념 세 가지:

개념설명
카나리(Canary)새 버전에 트래픽을 5%→20%→50%→100%처럼 단계적으로 흘리고, 각 단계 사이에 대기 시간이나 수동 승인을 둘 수 있음
AnalysisTemplate각 단계에서 Prometheus 등 메트릭을 쿼리해 기준(에러율, p99 레이턴시 등)을 정의 - 기준을 넘으면 사람 개입 없이 자동으로 이전 버전으로 롤백
블루그린(Blue-Green)새 버전을 통째로 띄워두고 스위치 한 번으로 트래픽을 전환, 문제 시 즉시 원복
트래픽 미러링(Mirroring)실사용자에게는 여전히 기존 버전이 응답하고, 같은 요청을 복제해서 신버전에 "그림자"로만 보냄 - 응답은 버려지므로 신버전이 잘못 응답해도 사용자는 영향받지 않음

이 시리즈는 이미 ArgoCD·Prometheus·Nginx Ingress를 갖추고 있으므로(시리즈 2, 6), 트래픽 분할은 서비스 메시 없이 Nginx Ingress 애노테이션 기반 분할로 가장 간단하게 시작한다.

실제 구축 절차

1. Argo Rollouts 설치

kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

# kubectl 플러그인 - Rollout 상태를 실시간으로 보기 위함
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

2. Deployment → Rollout 전환

기존 api-server Deployment를 Rollout 오브젝트로 바꾼다. apiVersion과 kind만 바뀌고 spec.template 이하는 거의 동일하다 - 대신 strategy 아래에 카나리 단계를 정의한다.

# api-server-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: api-server
spec:
  replicas: 5
  selector:
    matchLabels: { app: api-server }
  template:
    metadata:
      labels: { app: api-server }
    spec:
      containers:
        - name: api-server
          image: harbor.local/proxy-cache/api-server:latest
  strategy:
    canary:
      canaryService: api-server-canary
      stableService: api-server-stable
      trafficRouting:
        nginx:
          stableIngress: api-server-ingress
      steps:
        - setWeight: 5
        - pause: { duration: 2m }
        - analysis:
            templates:
              - templateName: error-rate-check
        - setWeight: 20
        - pause: { duration: 2m }
        - setWeight: 50
        - pause: { duration: 5m }
        - setWeight: 100

canaryService/stableService는 같은 파드 셀렉터를 가리키지만 각각 신규/기존 버전으로 라우팅되는 별도 Service다. trafficRouting.nginx.stableIngress에 지정한 Ingress의 애노테이션을 Argo Rollouts가 컨트롤러 대신 자동으로 조작해 트래픽 비율을 나눈다 - 즉 사람이 직접 nginx.ingress.kubernetes.io/canary-weight를 고칠 필요가 없다.

kubectl apply -f api-server-rollout.yaml
kubectl argo-rollouts get rollout api-server --watch   # 단계별 진행 상황을 실시간으로 확인

왜 5% → 20% → 50% → 100%인가. 이 숫자는 임의로 정한 게 아니라 두 가지를 동시에 만족시키려는 절충이다.

  • 초반 스텝(5%)은 최대한 작게, blast radius를 줄이는 목적이다. 배포 초기가 결함이 발견될 확률이 제일 높은 구간이므로, 문제가 있는 버전이라도 전체 트래픽의 5%만 잠깐 나쁜 응답을 받고 끝나야 한다. 5%보다 더 낮출 수도 있지만, 그러면 아래에서 다룰 통계적 유의성 문제가 커진다.
  • 중반 이후 스텝(20% → 50%)은 간격을 넓혀 검증 속도를 높이는 목적이다. 5%에서 이미 한 번 안전하다는 신호를 받았다면, 남은 위험은 "저트래픽 구간에서는 안 보이던 문제가 고트래픽에서 드러나는가"(리소스 한계, 커넥션 풀 고갈, 캐시 스탬피드 등)로 좁혀진다. 이 구간에서는 스텝을 촘촘하게 나눠도 얻는 정보가 크지 않으므로 20%→50%처럼 크게 뛰어도 된다.
  • 각 단계 사이 pause 시간은 "이 단계에서 이상 신호가 나타나기까지 걸리는 시간"을 기준으로 정한다. 에러율처럼 즉시 나타나는 지표는 2분이면 충분하지만, 메모리 누수나 커넥션 누수처럼 누적돼야 드러나는 문제는 짧은 pause로는 절대 못 잡는다. 그래서 트래픽 비중이 커지는 뒷단계(50%)의 pause를 앞단계보다 길게(5분) 잡는 것이 합리적이다 - 트래픽이 커질수록 누적성 문제가 더 빨리, 더 뚜렷하게 드러나기 때문이다.
  • 트래픽이 적은 서비스에서는 5%가 통계적으로 무의미할 수 있다. 하루 요청이 10만 건인 서비스라면 5% 단계에서도 30초당 수십~수백 건이 들어오므로 에러율 계산이 신뢰할 만하지만, 하루 1,000건짜리 내부 서비스라면 5% 단계의 30초 구간에는 요청이 아예 0건일 수도 있다. 이 경우 setWeight 숫자를 낮추는 게 아니라 분석 구간(pause.duration, analysis 스텝의 interval)을 늘려서 표본을 충분히 모으는 방향으로 조정해야 한다 - 트래픽이 적은 서비스는 시간을 사서 표본 크기를 확보하는 것이지, 비율을 조정해서 해결되는 문제가 아니다.

3. AnalysisTemplate - Prometheus 메트릭 기준 자동 롤백

카나리 단계 사이에 끼워 넣은 analysis 스텝이 바로 이 부분이다. 5% 트래픽을 받는 동안 에러율을 Prometheus에 쿼리해서, 기준을 넘으면 그 자리에서 자동으로 롤백한다.

# analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: error-rate-check
spec:
  metrics:
    - name: error-rate
      interval: 30s
      count: 4                     # 30초씩 4번 반복 측정
      successCondition: result[0] < 0.05   # 5% 미만이어야 통과
      failureLimit: 1               # 1번이라도 실패하면 즉시 중단
      provider:
        prometheus:
          address: http://prometheus-operated.monitoring:9090
          query: |
            sum(rate(http_requests_total{app="api-server-canary", status=~"5.."}[1m]))
            /
            sum(rate(http_requests_total{app="api-server-canary"}[1m]))

successCondition을 만족하지 못하는 순간 Argo Rollouts는 남은 카나리 단계를 진행하지 않고 트래픽 비중을 즉시 0으로 되돌린다 - "배포 후 대시보드를 지켜보다 이상하면 수동으로 롤백"하던 걸 기계가 대신하는 지점이 정확히 여기다.

4. ArgoCD와의 연동

시리즈 2에서 이미 ArgoCD로 GitOps 배포를 하고 있다면, Rollout/AnalysisTemplate 매니페스트도 같은 Git 저장소·같은 Application에 그대로 커밋하면 된다 - ArgoCD 입장에서는 Deployment든 Rollout이든 그냥 관리하는 리소스 중 하나다. 다만 ArgoCD UI에서 카나리 진행 상태를 보려면 Argo Rollouts용 UI 확장(kubectl argo-rollouts dashboard)을 따로 띄워야 한다.

5. (선택) 블루그린으로 전략 교체

일부 서비스는 트래픽을 점진적으로 나누는 것보다 "완전히 새 버전으로 스위치 - 문제 시 즉시 원복"이 더 맞을 수 있다. strategy.canary 대신 strategy.blueGreen으로 바꾸면 된다.

  strategy:
    blueGreen:
      activeService: api-server-active
      previewService: api-server-preview
      autoPromotionEnabled: false   # 수동 승인 후에만 전환
      prePromotionAnalysis:
        templates:
          - templateName: error-rate-check

prePromotionAnalysis로 전환 직전에도 같은 AnalysisTemplate을 재사용할 수 있다 - 카나리와 블루그린이 검증 로직 자체는 공유하고, 트래픽을 어떻게 나누느냐만 다르다는 걸 보여주는 지점이다.

검증 방법

  • 의도적으로 에러율이 높은 이미지를 배포해, 5% 단계에서 AnalysisTemplate이 실패를 감지하고 자동 롤백하는지 확인
  • 정상 이미지 배포 시 5%→20%→50%→100%까지 각 단계가 정의한 대기 시간대로 진행되는지 kubectl argo-rollouts get rollout --watch로 확인
  • 롤백이 발생했을 때 실제 서비스 트래픽이 끊기지 않고 안정 버전으로 계속 처리되는지 확인
  • (선택) 블루그린 전략에서 previewService로 먼저 접근해 검증한 뒤 수동 승인으로 전환이 잘 되는지 확인

체크리스트

  • Argo Rollouts 컨트롤러·kubectl 플러그인 설치
  • 기존 Deployment를 Rollout으로 전환, canary/stable Service 분리
  • Nginx Ingress 트래픽 분할 연동 확인
  • Prometheus 쿼리 기반 AnalysisTemplate 작성, 카나리 단계에 편입
  • 의도적 실패 배포로 자동 롤백 동작 검증
  • ArgoCD Application에 Rollout 매니페스트 편입
  • (선택) 블루그린 전략으로 교체, prePromotionAnalysis 재사용 확인