宣言と動作のあいだ
한국어 원문으로 표시합니다.
한 줄 요약
Argo 의 오브젝트는 의도를 적은 것일 뿐이고, 그 의도를 현실로 만드는 것은 컨트롤러입니다. 컨트롤러가 없으면 YAML 이 맞는지조차 알 수 없습니다.
왜 컨트롤러가 있어야 하나
앞 모듈들에서 Workflow 와 Rollout 을 여러 개 썼습니다. 그런데 그 실습들이 도는 곳에는 컨트롤러가 없어서, 그 YAML 이 실제로 무엇을 하는지 확인할 방법이 없었습니다.
Argo 의 네 프로젝트는 전부 컨트롤러가 있어야 의미가 생기는 물건입니다. 오브젝트는 의도를 적은 것일 뿐이고, 그 의도를 현실로 만드는 것은 컨트롤러입니다.
Workflows 컨테이너를 실제로 돌린다 없으면 단계가 진행되지도 실패하지도 않는다
Rollouts 파드를 실제로 띄우고 나눈다 없으면 카나리가 몇 퍼센트인지 볼 수 없다
Analysis Job 을 띄워 판정한다 없으면 자동 롤백이 통째로 빠진다
되돌아간 것은 트래픽이지 선언이 아니다
가장 값진 함정입니다. 분석이 실패해 자동 롤백이 일어나도 spec.template 의 이미지는 새 판 그대로입니다.
- 그대로 두면 다음에 다른 것을 고쳐 배포할 때 그 이미지가 같이 나갑니다
- GitOps 를 쓰면 저장소가 여전히 새 이미지를 가리키므로 다시 같은 배포를 시도합니다. 무한히 되돌아가는 고리가 됩니다
고치려면 선언을 되돌려야 합니다 — 저장소의 이미지 태그를 되돌리는 커밋입니다.
limit 은 재시도 횟수다
Workflows 의 retryStrategy.limit 은 재시도 횟수입니다. 첫 시도는 여기 들어가지 않습니다. limit: 2 면 실제 시도는 3번입니다.
도는 중에 템플릿을 고쳐도 바뀌지 않는다
컨트롤러가 시작 시점의 정의를 status.storedTemplates 에 박아 둡니다. 재현성을 위해서입니다. "템플릿을 고쳤는데 왜 그대로냐" 의 답이 이것이고, 다음 워크플로부터 바뀝니다.
카나리 가중치가 실제로 무엇을 하나
setWeight: 20 이 "요청의 20%" 를 뜻하는지 "파드의 20%" 를 뜻하는지가 구성에 따라
다릅니다. 이 차이가 실측과 기대를 어긋나게 만듭니다.
| trafficRouting | 가중치의 의미 | 정확도 |
|---|---|---|
| 없음 | 파드 수 비율 | 거칠다. replicas 5면 20%가 파드 1개 |
| Istio·Gateway API | 실제 요청 비율 | 정확하다 |
| NGINX Ingress | 실제 요청 비율(어노테이션) | 정확하다 |
trafficRouting 이 없으면 컨트롤러가 파드 수로 근사합니다. replicas: 3 에서
setWeight: 10 을 주면 파드 0개는 만들 수 없으니 1개(약 33%)가 됩니다. 작은
가중치로 시작하려면 replicas 가 충분히 크거나 trafficRouting 이 있어야 합니다.
분석이 무엇을 보고 판단하나
AnalysisTemplate 은 지표 제공자에게 질의하고 그 결과로 계속할지 정합니다.
metrics:
- name: error-rate
interval: 1m
count: 5 # 5번 재고
failureLimit: 2 # 2번 실패하면 롤백
successCondition: result[0] < 0.05
provider:
prometheus:
address: http://prometheus.monitoring.svc:9090
query: |
sum(rate(http_requests_total{status=~"5..",version="{{args.version}}"}[2m]))
/ sum(rate(http_requests_total{version="{{args.version}}"}[2m]))
여기서 자주 틀리는 것이 카나리만 걸러 내지 않는 쿼리 입니다. 위 쿼리에
version 라벨이 없으면 안정 판과 카나리를 합쳐 재게 되어, 카나리가 100% 실패해도
전체 오류율은 20% 밖에 안 오릅니다. 임계값을 넘지 않아 나쁜 배포가 통과합니다.
그리고 트래픽이 적을 때의 함정 이 있습니다. 카나리에 요청이 3개 들어왔는데 1개가 실패하면 오류율 33% 입니다. 최소 표본 수 조건을 함께 걸어야 합니다.
successCondition: result[0] < 0.05 || result[1] < 20 # 요청이 20건 미만이면 통과
배포 전략을 고르는 기준
| 카나리 | 블루그린 | |
|---|---|---|
| 자원 | 조금 더(단계별) | 두 배 |
| 되돌리기 속도 | 가중치를 0으로 — 빠르다 | 서비스 셀렉터 전환 — 가장 빠르다 |
| DB 스키마 | 두 판이 오래 공존 | 두 판이 잠깐 공존 |
| 적합한 곳 | 트래픽이 많고 지표로 판단 가능 | 검증을 사람이 하거나 트래픽이 적을 때 |
트래픽이 적은 내부 서비스에 카나리를 쓰면 표본이 모자라 분석이 무의미합니다. 그때는 블루그린으로 preview 를 사람이 확인하고 넘기는 편이 낫습니다.
실무에서 진짜 중요한 것
자동 롤백 뒤에는 반드시 선언을 되돌리는 커밋을 넣습니다. 롤백은 트래픽만 되돌리고 spec.template 은 새 판 그대로 남습니다. GitOps 를 쓰면 저장소가 여전히 새 이미지를 가리키므로 같은 배포를 무한히 다시 시도합니다.
배포 판정은 Healthy 가 아니라 status.stableRS 로 합니다. 승격이 끝나고 Healthy 가 된 뒤에도 옛 파드가 Terminating 으로 잠시 남아, 이미지를 세면 두 종류가 나옵니다. 안정 판을 가리키는 해시가 유일하게 흔들리지 않는 기준입니다.
retryStrategy.limit 은 총 시도 횟수가 아닙니다. 첫 시도는 여기 들어가지 않으므로 limit: 2 는 실제로 3번 돕니다. 타임아웃 예산을 계산할 때 한 번씩 빠뜨리는 자리입니다.
다음 두 실습에서 이것들을 진짜 컨트롤러 위에서 직접 확인합니다.