정상 Canary는 왜 안전한가: step과 AnalysisRun
새 버전의 파드가 Ready라고 해서 서비스도 정상이라고 볼 수 있을까요?
Deployment의 롤링 업데이트는 파드 준비 상태를 확인하며 버전을 교체하지만, 오류율을 보고 배포를 멈추거나 새 버전에 트래픽을 5%만 보내는 기능은 제공하지 않습니다.
우리 환경에서는 Argo Rollouts와 Istio로 트래픽을 나누고, AnalysisRun으로 오류율과 지연 시간을 확인합니다.
파드 수와 트래픽 비율을 따로 다룬다
Rollout도 Deployment처럼 ReplicaSet으로 파드를 관리합니다.
배포 순서는 step으로 지정하고, stable과 canary에 보낼 트래픽은 Istio로 조절합니다.
setWeight: 5를 지정하면 전체 트래픽의 5%를 새 버전으로 보냅니다.
파드 수와는 별개라 canary가 2대여도 트래픽은 5%만 받을 수 있습니다.
5%를 보내고, 10분을 본다
공통 차트의 기본 steps는 다음과 같습니다.
steps:
- setWeight: 5
- pause:
duration: 10m
- setWeight: 100새 버전에 5%를 보낸 뒤 10분 동안 관찰하고, 문제가 없으면 100%로 늘립니다.
이때 background AnalysisRun이 배포 중 메트릭을 계속 확인합니다.
서비스가 자체 steps를 선언하면 공통 차트의 리스트를 통째로 대체합니다.
setWeight: 100 하나만 선언한 서비스는 5%로 관찰하는 단계와 10분 대기를 생략합니다.
아래 예시는 이 기본 steps에 전체 replica 20대, minPodsPerReplicaSet: 2를 적용했습니다.
파드 20대가 준비돼야 트래픽을 100%로 늘린다
처음 5%에 필요한 파드는 계산상 20 × 5% = 1대입니다.
하지만 최소 파드 수가 2이므로 canary는 2대로 시작합니다.
10분 뒤 마지막 setWeight: 100 단계로 넘어가면 컨트롤러는 새 ReplicaSet의 목표를 20대로 늘립니다.
그림의 ③~⑤처럼 step index가 2로 바뀌어도, 20대가 모두 준비되기 전까지는 트래픽을 5%만 보냅니다.
Ready 이후 minReadySeconds 동안 안정 상태를 유지해야 가용한 파드로 인정합니다.
컨트롤러가 적용하는 조건은 다음과 같습니다.
새 ReplicaSet이 현재 step에서 요구하는 만큼 준비되지 않았다면 이전 weight를 사용한다.
변경한 상태는 다음 reconcile에서 확인한다
컨트롤러는 현재 상태를 읽고 필요한 변경을 적용하는 reconcile을 반복합니다.
한 번의 reconcile에서 traffic weight와 ReplicaSet 목표를 계산한 뒤 step 진행 여부를 기록합니다.
바뀐 step index는 다음 reconcile에서 읽고, 파드의 가용성을 확인해 새 weight를 적용할지 결정합니다.
마지막 step과 승격
모든 step을 통과하고 새 ReplicaSet 전체가 준비되면 새 버전을 stable로 승격(promotion)합니다.
step이 더 없을 때 컨트롤러는 최종 weight를 100으로 계산합니다.
따라서 마지막 setWeight: 100을 명시하지 않아도 정상 배포는 100%까지 진행됩니다.
AnalysisRun은 무엇을 보고 멈추는가
측정할 메트릭과 판정 기준을 AnalysisTemplate에 지정하면, 배포 중 생성되는 AnalysisRun이 이 설정에 따라 측정합니다.
우리 환경에서는 background analysis를 사용해 특정 step에 한정하지 않고 배포 중 계속 측정합니다.
오류율이 0.001 이상이거나 지연 시간이 0.3s 이상이면 해당 측정을 실패로 판정합니다.
interval: 20s마다 측정하고, 실패가 failureLimit: 2를 초과해 누적 세 번이 되면 AnalysisRun이 Failed가 됩니다.
중간에 성공한 측정이 있어도 실패 횟수는 줄지 않습니다.
컨트롤러는 Rollout을 abort하고, canary weight를 0으로 내려 stable로 트래픽을 되돌립니다.
새 버전만 측정하는 것은 아니다
현재 Prometheus 쿼리는 stable과 canary를 구분하지 않고 서비스 전체 메트릭을 봅니다.
canary에서 오류가 늘어도 트래픽 비중이 5%라면 서비스 전체 오류율에는 작게 반영될 수 있습니다.
새 버전의 오류율을 따로 확인하려면 쿼리에서도 두 버전의 요청을 구분해야 합니다.
그런데 롤백이 step을 건너뛰면, 컨트롤러가 찾는 “이전 weight”는 무엇이 될까요?