작년 말부터 팀 내부에서 카나리 배포 도구 얘기가 계속 돌았다. 우리 서비스는 그동안 그냥 Deployment의 RollingUpdate maxSurge/maxUnavailable 조합으로만 배포해왔는데, 최근에 P99 레이턴시가 순간적으로 튀는 케이스가 반복되면서 "이거 그냥 롤링 업데이트로는 안 잡히겠다"는 얘기가 나왔다. 새 버전이 트래픽을 5%만 받아본 뒤 지표 보고 승격시키는 구조로 가야 한다는 데는 합의가 됐는데, 문제는 Argo Rollouts를 쓸지 Flagger를 쓸지였다.
한 달 정도 두 도구를 실제로 스테이징에 붙여보고 최근에 결론을 냈다. 이 글은 그 과정에서 정리한 노트다. 둘 중 하나가 절대 옳다는 얘기가 아니라, 어떤 상황에서 어느 쪽이 덜 아픈지 정도의 이야기다.
근본적인 접근 방식이 다르다
두 도구가 비슷해 보이지만 사실 설계 철학이 꽤 다르다.
Argo Rollouts는 기존 Deployment 리소스를 통째로 Rollout이라는 CRD로 교체하는 방식이다. spec.strategy.canary.steps에 20% → 40% → 60% → 80% → 100% 같은 단계를 명시적으로 적어두고, 각 단계 사이에 pause를 넣어 수동 승격을 강제하거나 analysis로 자동 판단을 걸 수 있다. 개념적으로는 "내가 배포 파이프라인을 직접 그린다"에 가깝다.
반면 Flagger는 기존 Deployment를 건드리지 않는다. Canary라는 CRD가 Deployment 위에 얹혀서, Deployment가 업데이트되면 Flagger가 알아서 primary/canary 리소스를 만들고 트래픽을 5%씩 올려가며 지표를 본다. 실패하면 자동 롤백. 개념적으로 "너희는 그냥 평소처럼 배포해, 나머지는 내가 알아서 할게" 쪽이다.
이 차이가 실제 팀에서 크게 갈리는 지점이 됐다.
마이그레이션 비용
우리 서비스는 마이크로서비스가 40개쯤 된다. 40개 Deployment를 다 Rollout CRD로 바꾸는 게 만만치 않다. Helm chart 템플릿을 수정해야 하고, ArgoCD가 리소스 diff를 새로 잡고, HPA가 Rollout을 대상으로 붙는지 검증도 필요했다. 실제로 옮겨보니 서비스 하나당 20~30분씩은 들었다. 40개면 대충 하루 반나절.
Flagger는 이 부분이 압도적으로 편했다. Deployment는 그대로 두고 Canary 리소스만 하나 추가하면 끝. 물론 서비스 메시(우리는 Istio)가 이미 깔려 있어야 한다는 전제가 있긴 하다.
정리하면 대충 이렇다.
- 새 프로젝트를 그린필드로 시작하는 거면 Argo Rollouts든 Flagger든 큰 차이 없음
- 이미 굴러가는 서비스 수십 개에 카나리를 붙이는 거면 Flagger 쪽이 마찰이 훨씬 적음
- 반대로 GitOps 파이프라인이 이미 ArgoCD 중심이고 카나리 진행 상황을 ArgoCD UI에서 보고 싶으면 Argo Rollouts
제어의 세밀함
Flagger를 처음 봤을 때 좋았던 건 "설정이 짧다"는 점이었다. 대충 이렇게 쓴다.
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: payment-api
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
service:
port: 8080
analysis:
interval: 1m
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 30s
10%씩 트래픽을 올리다 50%까지 가면 승격. 성공률 99% 미만이거나 P99 500ms 초과면 롤백. 끝이다. 사람이 개입할 여지가 거의 없다는 게 장점이자 단점.
Argo Rollouts는 반대로 이렇게 쓴다.
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payment-api
spec:
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 5m }
- setWeight: 20
- pause: {} # 수동 승격 대기
- analysis:
templates:
- templateName: success-rate
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
pause: {}는 사람이 승격 버튼을 누를 때까지 무한 대기다. 우리 조직 특성상 야간에 큰 릴리스를 돌릴 때 온콜이 실제로 지표를 보면서 승격 여부를 판단하고 싶어하는 케이스가 있었는데, 이 명시적 승격 게이트가 Argo Rollouts 쪽이 훨씬 자연스러웠다. Flagger로도 metric alert 걸어놓고 사람 판단을 끼울 수는 있지만, 흐름이 자연스럽지 않다.
거꾸로 말하면, Flagger의 "사람이 개입할 필요 없이 지표만 보고 알아서 진행"이라는 특성이 오히려 매력인 팀도 많다. 배포 담당자가 매번 대기 화면 앞에 붙어 있을 필요가 없다는 뜻이니까.
서비스 메시 종속성
이건 실제로 결정에 큰 영향을 줬다. Flagger는 트래픽 스플리팅을 직접 하지 않는다. Istio, Linkerd, App Mesh, NGINX Ingress, Traefik, Gloo, Contour 같은 걸 통해서 트래픽을 나눈다. 즉, 이 중 하나가 반드시 있어야 한다.
Argo Rollouts는 서비스 메시가 없어도 그냥 Kubernetes Service의 selector 조작만으로도 카나리를 할 수 있다. 물론 이렇게 하면 트래픽 스플리팅이 정밀하지 않다(파드 수 비율로만 됨). 그래도"Istio 없이 5%/95% 나누기"가 가능하긴 하다는 게 큰 차이다.
우리는 Istio가 이미 있었기 때문에 이 부분은 사실상 무의미했다. 근데 만약 서비스 메시를 새로 도입하기 부담스러운 팀이면 Argo Rollouts가 진입 장벽이 훨씬 낮다.
GitOps 통합
우리는 ArgoCD를 쓴다. Argo Rollouts는 당연히 ArgoCD와 통합이 매끄럽다. ArgoCD UI에 Rollout 리소스가 그대로 렌더링되고, 카나리 진행 단계와 승격/롤백 버튼이 UI에서 바로 보인다. 사람 개입이 필요한 순간에 Slack alert만 잘 걸어두면 온콜이 곧바로 ArgoCD 열어서 승격 눌러버릴 수 있다.
Flagger는 Flux CD와 궁합이 좋다. Flux 진영에서 만든 도구이기도 하고, Flux의 Kustomization/HelmRelease로 배포하면 Canary 리소스가 자연스럽게 얹힌다. 물론 ArgoCD로 Flagger를 관리하는 것도 되긴 되는데(그냥 CRD니까), UI에서 카나리 진행 상황이 예쁘게 나오지는 않는다.
우리 팀은 뭘 선택했나
결론부터 말하면 Argo Rollouts로 갔다. 근데 이게 "Argo Rollouts가 더 좋아서"는 아니다. 정확히는 세 가지 이유였다.
첫째, 이미 ArgoCD를 쓰고 있고 UI 통합이 결정적이었다. 야간 배포에서 온콜이 승격 버튼을 UI에서 누를 수 있다는 게 팀 요구사항이었다.
둘째, "지표 보고 자동 승격"보다 "지표 보여주고 사람이 승격"을 선호하는 조직 문화가 있었다. 자동 롤백은 걸어두더라도 승격만큼은 사람 판단을 원했다.
셋째, 마이그레이션 비용을 감수할 수 있는 규모였다. 40개 서비스 이틀 정도면 다 옮길 수 있었다.
만약 우리 팀이 서비스가 200개였다면? 아마 Flagger로 갔을 거다. Deployment를 안 건드려도 된다는 게 결정타였을 것 같다. 만약 자동화 지향적인 팀이고 사람이 개입할 필요 없이 지표만으로 승격/롤백을 완전히 맡기고 싶다면 그것도 Flagger.
몇 가지 함정
두 도구를 붙여본 뒤에 알게 된, 문서에 잘 안 나오는 얘기들.
analysis에 쓸 지표는 카나리 배포 도입 전에 먼저 확보돼 있어야 한다. Argo Rollouts든 Flagger든 Prometheus 쿼리를 참조하는데, "요청 성공률 99% 이상" 같은 걸 자신 있게 쓸 수 있으려면 애초에 그 지표가 안정적으로 나오고 있어야 한다. 우리는 도구 도입 자체보다 지표 신뢰도 올리는 데 더 오래 걸렸다.
pause 시간을 짧게 잡지 마라. 문서 예제만 보고 5분 pause를 걸어놓으면, 실제 사용자 트래픽이 카나리에 도달하는 데 걸리는 시간(로드밸런서 워밍업, DNS TTL, 커넥션 풀 재사용 등) 때문에 지표가 유효해지기 전에 승격돼버린다. 최소 15분은 되어야 지표가 의미 있어진다.
롤백 시나리오를 반드시 스테이징에서 돌려봐라. "지표가 나쁘면 자동 롤백"이라는 게 문서상으론 한 줄인데, 실제로 롤백이 걸렸을 때 트래픽이 어떻게 되돌아가는지, 세션이 어떻게 되는지 등은 실제로 재현해봐야 안다. 우리는 스테이징에서 일부러 canary에 500 리턴하는 이미지 배포해서 자동 롤백을 몇 번 돌려봤다.
마무리
두 도구를 놓고 고민한다면 "어느 쪽이 더 우수한가"보다 다음 세 가지를 먼저 물어보는 게 낫다.
기존 GitOps 파이프라인이 ArgoCD인가 Flux인가. 서비스 메시가 이미 있는가. 승격을 자동화하고 싶은가 아니면 사람 판단을 남기고 싶은가.
이 세 개만 답이 나오면 도구는 거의 저절로 정해진다. 진짜 어려운 건 도구 선택이 아니라, 카나리 판단 기준이 되는 지표를 어떻게 신뢰할 만한 수준으로 유지하느냐다. 그 부분은 다음에 한번 따로 정리해보려고 한다.
혹시 다른 팀에서 두 도구 중 뭘 쓰고 있는지, 왜 그렇게 선택했는지 궁금하다. 댓글로 알려주시면 큰 도움이 될 것 같다.
'IT > CI CD' 카테고리의 다른 글
| ArgoCD ApplicationSet으로 멀티 환경 배포 자동화하기 (0) | 2026.07.01 |
|---|---|
| GitHub Actions secrets: inherit, 한 줄이 일으키는 의외의 일들 (0) | 2026.06.27 |
| ArgoCD ApplicationSet으로 PR 프리뷰 환경 자동화하기 (0) | 2026.06.26 |
| GitHub Actions OIDC로 AWS 권한, Access Key 없이 끝내기 (0) | 2026.06.24 |
| ArgoCD ApplicationSet, 사실 내부적으로는 이렇게 돈다 (0) | 2026.06.22 |