Skip to Content
Blog마지막 setWeight: 100을 왜 지워야 하는가

마지막 setWeight: 100을 왜 지워야 하는가

#Argo Rollouts#GitOps#Istio#트러블슈팅

2부에서는 rollbackWindow가 정상적인 Canary의 안전장치를 어떻게 깨뜨리는지 확인했습니다.

정상 배포에서는 새 ReplicaSet이 준비되지 않았을 때 Controller가 이전 traffic weight를 유지합니다.

문제는 rollbackWindow가 step index를 끝으로 보내면서 그 “이전 weight”가 마지막 setWeight: 100이 된다는 점이었습니다.

결과적으로 새 ReplicaSet의 최종 목표는 20대인데 실제 Available은 2대뿐인 순간에 traffic 100%가 먼저 전달될 수 있었습니다.

이번 글에서는 이 경로를 어떻게 막을 것인지 다룹니다.

결론은 단순합니다.

Canary steps 마지막의 setWeight: 100을 제거합니다.

중요한 것은 한 줄을 지우는 행위보다 왜 그것만으로 정상 배포는 그대로 유지하면서 롤백 경로만 안전하게 바뀌는가입니다.

그리고 사고 당시 canary가 왜 하필 2대였는지, minPodsPerReplicaSet이 어떤 배경에서 들어왔는지도 함께 살펴봅니다.

1. 먼저 결론

이번 문제에 대한 처방은 다음과 같습니다.

  1. Canary steps 마지막의 setWeight: 100을 제거합니다.
  2. 정상 배포는 그대로 100%까지 진행됩니다.
  3. ReplicaSet의 최종 파드 수도 달라지지 않습니다.
  4. rollbackWindow에서는 역탐색이 마지막 100 대신 그 앞의 낮은 weight를 사용하게 됩니다.
  5. 다만 남겨 둔 마지막 weight가 초기 canary 파드 수로 감당 가능한 값인지는 별도로 확인해야 합니다.
  6. 서비스가 자체 steps를 선언하면 base 설정을 상속하지 않으므로 base와 서비스 override를 각각 수정해야 합니다.
  7. dynamicStableScale, setCanaryScale, minPodsPerReplicaSet 조정만으로 이 문제를 해결하려고 해서는 안 됩니다.
  8. Controller 수정이 upstream에 들어가기 전까지는 Rollback Drill과 CI 검증을 같이 유지해야 합니다.

핵심은 마지막 setWeight: 100정상 배포에서 100%에 도달하기 위해 필요한 step이 아니라는 점입니다.

1부에서 확인했듯 모든 step을 통과하면 Controller는 최종 weight를 100%로 계산합니다.

따라서 아래 두 설정은 정상 배포의 최종 목적지가 같습니다.

steps: - setWeight: 5 - pause: duration: 10m - setWeight: 100
steps: - setWeight: 5 - pause: duration: 10m

차이는 rollbackWindow에서 나타납니다.

첫 번째 설정은 역탐색이 100을 찾지만 두 번째 설정은 5를 찾습니다.

2. 처방 — 마지막 setWeight: 100을 지운다

정상 배포에서는 마지막 setWeight: 100이 없어도 모든 step을 통과한 뒤 최종적으로 100% traffic에 도달합니다.

따라서 다음 설정에서

steps: - setWeight: 5 - pause: duration: 10m

pause가 끝나면 Rollout은 그대로 전체 traffic 전환과 promotion을 진행할 수 있습니다.

ReplicaSet의 최종 목표도 그대로입니다.

최종 Desired Pods = 20 최종 Traffic = 100%

즉 마지막 setWeight: 100을 지운다고 해서 파드가 덜 뜨거나 정상 배포가 5%에서 멈추는 것은 아닙니다.

달라지는 것은 새 ReplicaSet이 아직 준비되지 않은 rollbackWindow 경로에서 Controller가 어떤 값을 “이전 weight”로 선택하느냐입니다.

기존 설정에서는 step 끝에서 역탐색하면 바로 setWeight: 100을 만났습니다.

5% → pause → 100% rollback 역탐색

100을 제거하면 다음과 같이 바뀝니다.

5% → pause rollback 역탐색

따라서 롤백 대상 ReplicaSet이 아직 초기 파드 수만 준비된 상태라면 traffic도 기존의 낮은 weight에 머뭅니다.

파드가 모두 준비되고 promotion 조건까지 충족한 뒤 최종 100% 전환이 이루어집니다.

대가는 무엇인가

대가가 없는 변경은 아닙니다.

사고 당시처럼 롤백 대상 ReplicaSet이 2대만 준비되어 있다면 마지막 weight가 5%일 경우 롤백이 완료될 때까지 traffic의 5%만 복구 버전으로 향합니다.

복구 버전 5% 장애 버전 95%

즉 100%를 2대에 몰아 주는 사고는 막지만, 전체 ReplicaSet이 준비되는 동안에는 장애 버전에 traffic이 일부 남습니다.

하지만 promotion 자체가 새 ReplicaSet의 전체 가용성을 기다리기 때문에 롤백 완료 시각이 늦어지는 것은 아닙니다.

달라지는 것은 준비 구간의 traffic 분배입니다.

따라서 이 처방의 목표는

복구가 끝날 때까지 기다리는 시간을 줄이는 것

이 아니라,

복구가 끝나기 전에 준비되지 않은 ReplicaSet으로 traffic이 먼저 몰리는 것을 막는 것

입니다.

안전 한계는 마지막으로 남은 weight가 정한다

마지막 100을 지웠다고 해서 어떤 weight를 남겨도 안전한 것은 아닙니다.

초기 canary 파드 수가 감당할 수 있는 traffic이어야 합니다.

단순화하면 다음 관계로 볼 수 있습니다.

안전한 전체 Pod 규모 ≈ minPodsPerReplicaSet / 남는 traffic 비율

minPodsPerReplicaSet: 2라면:

마지막으로 남는 weight초기 2대로 대응 가능한 전체 규모
1%약 200 Pods
5%약 40 Pods
10%약 20 Pods
50%약 4 Pods

예를 들어 전체 Replica가 100대까지 올라갈 수 있는 서비스라면 마지막 weight를 5%로 남기는 것만으로는 충분하지 않을 수 있습니다.

이 경우에는

  • 마지막 rung을 더 낮추거나
  • 초기 Canary Pod 수를 늘리거나
  • 별도의 Rollback 정책을 적용해야 합니다.

따라서 처방의 핵심은 단순히 100을 삭제한다가 아니라,

rollbackWindow가 역탐색해 가져갈 마지막 weight를 초기 ReplicaSet 용량에 맞는 값으로 제한한다

입니다.

적용이 두 갈래로 갈리는 이유

1부에서 살펴봤듯 Helm values의 리스트는 merge되지 않고 통째로 교체됩니다.

따라서 base에서

steps: - setWeight: 5 - pause: duration: 10m

으로 변경해도 서비스에서

steps: - setWeight: 1 - pause: duration: 5m - setWeight: 5 - pause: duration: 5m - setWeight: 100

처럼 자체 steps를 선언하면 base 변경은 적용되지 않습니다.

따라서 적용 작업은 두 갈래입니다.

base steps 수정 + 서비스별 steps override 수정

서비스별 형태도 구분해야 합니다.

[1, 5, 100]이나 [5, 100]처럼 앞에 낮은 rung이 있는 경우에는 마지막 100을 제거하면 됩니다.

반면

10 → 50 → 100

처럼 마지막 앞 단계가 이미 높은 경우에는 100만 제거해도 rollbackWindow가 50을 선택합니다.

이 경우에는 앞 단계까지 같이 조정해야 합니다.

[100] 하나만 존재하는 경우도 사고 경로에는 노출됩니다.

정상 배포에서는 전체 ReplicaSet이 준비된 뒤 100%로 전환되지만 rollbackWindow에서 step을 끝으로 넘기면 역탐색이 그 하나뿐인 100을 집을 수 있기 때문입니다.

따라서 이 형태 역시 제거 대상입니다.

반대로 steps: []처럼 setWeight 자체가 없다면 이번 역탐색 문제에는 직접 노출되지 않습니다.

이 규칙은 사람이 매번 확인하기보다 CI에서 검증하는 것이 좋습니다.

예를 들어 다음을 검사할 수 있습니다.

마지막 setWeight == 100 → 실패 또는 마지막 setWeight가 초기 canary capacity보다 큰 경우 → 실패

3. 왜 다른 대안은 답이 아닌가

마지막 setWeight: 100 제거 외에도 몇 가지 옵션을 생각할 수 있습니다.

하지만 각각 해결하는 문제가 다릅니다.

대안이번 문제 해결 여부이유
dynamicStableScaleXrollbackWindow의 weight 선택 자체를 막지 못함
setCanaryScale부분적미리 Pod를 늘릴 수 있지만 step skip 이후에는 보호하지 못함
minPodsPerReplicaSet 인상조건부충분히 크게 잡으면 막을 수 있지만 Canary 비용이 커짐
step analysisXrollbackWindow가 Analysis 자체를 skip
마지막 setWeight: 100 제거O역탐색이 선택할 값을 직접 낮춤

dynamicStableScale

dynamicStableScale은 traffic weight에 맞춰 기존 stable ReplicaSet의 크기도 함께 줄이는 기능입니다.

이 기능은 리소스를 절약할 수 있지만 이번 문제의 해결책은 아닙니다.

핵심 사고 경로는

rollbackWindow → step index 끝으로 이동 → 마지막 setWeight 역탐색 → 100% 선택

입니다.

dynamicStableScale을 켠다고 이 선택 과정이 사라지는 것은 아닙니다.

오히려 stable ReplicaSet까지 줄어들면 문제가 발생했을 때 즉시 돌아갈 warm standby가 없어질 수 있습니다.

현재 구성처럼 stable을 유지하는 방식에서는 canary 쪽에 문제가 생겨도 traffic을 기존 stable로 빠르게 돌릴 수 있습니다.

따라서 이번 문제를 해결하기 위해 dynamicStableScale을 활성화하는 것은 적절하지 않습니다.

setCanaryScale

setCanaryScale을 사용하면 traffic weight와 별개로 canary ReplicaSet을 미리 확장할 수 있습니다.

예를 들어:

- setCanaryScale: replicas: 20

처럼 롤백 대상 파드를 먼저 띄우는 방법을 생각할 수 있습니다.

하지만 rollbackWindow는 step index 자체를 끝으로 이동시킵니다.

따라서 일반적인 step 처리를 건너뛴 뒤에는 이 설정이 항상 보호막으로 남아 있다고 볼 수 없습니다.

정상 배포에서 canary를 미리 warm-up 하는 용도로는 유효하지만 이번 rollbackWindow 경로를 직접 막는 해결책은 아닙니다.

minPodsPerReplicaSet을 늘리면 되지 않을까

수학적으로는 가능합니다.

예를 들어 100% traffic을 안전하게 받고 싶다면 초기 canary ReplicaSet 자체가 전체 replica만큼 떠 있어야 합니다.

전체 replicas = 20 minPodsPerReplicaSet = 20

이렇게 하면 20대가 준비되기 전에 traffic이 넘어가는 문제는 없어집니다.

하지만 그 순간 Canary의 장점도 대부분 사라집니다.

5% traffic을 검증하기 위해서도 새 버전을 20대 전부 띄우게 됩니다.

따라서 minPodsPerReplicaSet최소한의 Canary 용량을 보장하는 옵션으로 써야지, traffic 100% 사고를 막기 위해 전체 replicas까지 올리는 방식으로 사용하기에는 비용이 큽니다.

그리고 우리 환경에서는 이 값 자체가 다른 문제를 만든 이력이 있습니다.

그 이야기를 다음 장에서 봅니다.

4. minPodsPerReplicaSet: 2는 왜 존재했나

2026-08-21 사고에서 롤백 대상 ReplicaSet이 처음 2대로 뜬 것은 우연이 아닙니다.

base chart의

minPodsPerReplicaSet: 2

기본값 때문입니다.

이 값은 작은 Canary weight에서도 최소 두 개의 파드를 유지해 단일 Pod에 traffic이 몰리는 것을 막기 위한 의도로 들어갔습니다.

하지만 전체 replica 수가 작아지면서 다른 문제가 나타났습니다.

위로 막힌다 — 승격이 수렴하지 않는다아래로 샌다 — 스케일이 멈추지 않는다CheckMinPodsPerReplicaSet두 조건절이 각각 한 방향desired 1KEDA min=max=1canary 2 + stable1하한 2 · 합계 3 vsdesired 1DegradedProgressDeadlineExceededdesired 0컨슈머 정지하한 1 > 목표 0count == 0 분기를 못 탄다파드 진동생성과 삭제 반복
같은 함수의 두 조건절이 방향에 따라 정반대 증상을 냅니다. desired 가 1이면 canary 2 + stable 1 = 3 이 되어 승격 조건이 영영 성립하지 않고, desired 가 0이면 하한이 목표보다 커서 스케일이 진동합니다. 원인은 한 곳이고 증상은 서로 닮은 데가 없습니다.

예를 들어 전체 desired replica가 1인데 minPodsPerReplicaSet: 2라면 Canary ReplicaSet은 최소 2대가 됩니다.

spec.replicas = 1 minPodsPerReplicaSet = 2 stable = 1 canary = 2

Controller가 기대하는 전체 상태와 실제 ReplicaSet 규모가 어긋나면서 Rollout이 Healthy 조건에 도달하지 못할 수 있습니다.

반대로 replica를 0으로 줄이는 Consumer류 workload에서는 최소 Pod 설정이 scale-to-zero와 충돌할 수 있습니다.

즉 같은 값이 워크로드 규모에 따라 서로 반대 방향의 문제를 만듭니다.

타임라인

위로 막힌다 — 승격이 수렴하지 않는다아래로 샌다 — 스케일이 멈추지 않는다CheckMinPodsPerReplicaSet두 조건절이 각각 한 방향desired 1KEDA min=max=1canary 2 + stable1하한 2 · 합계 3 vsdesired 1DegradedProgressDeadlineExceededdesired 0컨슈머 정지하한 1 > 목표 0count == 0 분기를 못 탄다파드 진동생성과 삭제 반복
같은 함수의 두 조건절이 방향에 따라 정반대 증상을 냅니다. desired 가 1이면 canary 2 + stable 1 = 3 이 되어 승격 조건이 영영 성립하지 않고, desired 가 0이면 하한이 목표보다 커서 스케일이 진동합니다. 원인은 한 곳이고 증상은 서로 닮은 데가 없습니다.

중요한 변화만 추리면 다음과 같습니다.

시점변화
2025-05minPodsPerReplicaSet: 2 도입
2025-06rollbackWindow.revisions: 3 도입
2025-08현재와 유사한 traffic routing 구조 적용
2025 하반기소규모 워크로드에서 minPodsPerReplicaSet 예외가 서비스별로 증가
2026-07비용 절감을 위해 비프로덕션 최소 replicas를 대폭 축소
2026-08replica 0/1 워크로드에서 minPods 충돌이 대규모로 드러남
2026-08-21이번 rollbackWindow 사고 발생

여기서 중요한 것은 2라는 숫자 자체가 잘못됐다는 것이 아닙니다.

문제는 하나의 base 기본값이

replicas 0 replicas 1 replicas 20 replicas 100+

처럼 규모가 크게 다른 워크로드에 동일하게 적용됐다는 점입니다.

결국 서비스별 예외가 계속 추가됐고, 어떤 워크로드가 어떤 값을 가져야 하는지를 CI가 검증하지 못한 상태가 오래 유지됐습니다.

이번 사고에서도 마찬가지입니다.

minPodsPerReplicaSet: 2가 사고의 원인은 아닙니다.

2대만 준비된 상태에서 100% traffic을 먼저 전달한 것이 원인입니다.

다만 이 값이 사고 당시 노출된 용량을 결정했습니다.

따라서 앞으로는

최소 Canary Pod 수 × 마지막 Canary traffic weight × 해당 서비스의 최대 Replica 규모

를 함께 봐야 합니다.

5. abort / rollback에서 어떤 수단을 써야 하는가

인시던트 중 사용할 수 있는 명령도 같은 의미를 갖지는 않습니다.

수단목적이번 상황에서
retry실패한 Rollout을 다시 진행Analysis부터 다시 시작할 수 있어 부적합
promote현재 pause를 진행abort 자체를 해제하는 수단은 아님
promote --fullstep/Analysis를 건너뛰고 전체 승격수동 탈출 경로로 사용 가능
GitOps rollback / undo이전 Pod template으로 되돌림rollbackWindow 경로와 연결

특히 retry는 장애 상황에서 주의해야 합니다.

2부에서 본 것처럼 Analysis가 서비스 전체 오류율을 보는 상태라면 다시 시작한 AnalysisRun이 같은 높은 오류율을 읽고 또 abort될 수 있습니다.

반면 promote --full은 별도의 weight 보호 경로를 가지고 있습니다.

따라서 이미 정상 버전으로 되돌아왔고 남은 문제가 Rollout 상태뿐인 경우 수동 탈출 수단으로 사용할 수 있습니다.

다만 이것은 근본 해결책이 아니라 운영 런북의 비상 경로입니다.

GitOps 환경에서는 선언 상태와 실제 상태도 함께 맞춰야 합니다.

따라서 인시던트 대응과 이후 Git 정합성 복구는 구분해서 운영해야 합니다.

6. 업스트림 상태

이 문제는 우리 환경에서만 발생한 것은 아닙니다.

붙은 가드 넷 — 우리 v1.8.2 에 있는 것은 셋통과통과무관부재재발대기미가용 상태의 가중치canary 2대 · weight100%:217 Available 00대일 때만 막는다:266 가용량 게이트#3878 · stable 만 본다:229 동결#1683 · promote --full전용#4639 조기 리셋master 전용 · v1.8.2없음걸리는 가드 없음2 / 20 인데 100%#3941 재발2026-04 · v1.8.3PR #4852가용 replica 비례 캡 ·미머지
2021 년부터 붙은 가드 넷은 모두 이 구멍의 옆을 지킵니다. 둘은 canary 가 0대일 때만, 하나는 stable 만 검사하고, 하나는 promote --full 전용입니다. 게다가 #4639 는 master 전용이라 우리가 쓰는 v1.8.2 에는 없습니다 — 실제로 작동하는 가드는 넷이 아니라 셋입니다. #3878 이 stable 만 가드했기 때문에 v1.8.3 에서 #3941 이 재발했고, 그 자리를 메우는 PR #4852 는 2026-07-24 APPROVED 뒤에도 2026-08-27 조회 시점까지 미머지입니다.

Argo Rollouts에서는 과거에도 ReplicaSet의 실제 가용량보다 traffic weight가 먼저 증가하는 문제가 여러 경로에서 반복적으로 보고됐습니다.

특히 promote --full 경로에서는 유사한 문제가 이미 수정됐고, 이후 stable ReplicaSet의 용량을 확인하는 guard도 추가됐습니다.

하지만 rollbackWindow 경로에서는 여전히 한 가지 빈틈이 남았습니다.

기존 guard들은 대략 다음을 확인합니다.

Guard확인하는 것
Canary Available = 0Canary가 하나도 없으면 traffic을 보내지 않음
Stable capacity guardStable이 남은 traffic을 감당할 수 있는지 확인
promote --full guardCanary Available에 맞춰 traffic 증가를 제한

문제의 경우는

Canary Available = 2 Canary Desired = 20 Canary Weight = 100% Stable Weight = 0%

입니다.

Canary는 0대가 아니므로 첫 guard를 통과합니다.

Stable traffic은 0%이므로 stable capacity guard도 통과합니다.

그리고 rollbackWindowpromote --full 전용 보호 경로를 사용하지 않습니다.

Canary가 “0대보다 많다”는 것과 “100% traffic을 받을 만큼 충분하다”는 것 사이의 빈 구간이 남습니다.

이 문제를 직접 다루는 upstream 수정안도 같은 방향입니다.

핵심은 단순합니다.

Canary traffic weight를 실제 Available Replica 비율 이상으로 올리지 않는다.

이 방식이 Controller에 정식으로 반영되면 이번에 values에서 적용하는 workaround의 중요도는 크게 낮아집니다.

하지만 Controller 변경이 모든 클러스터에 실제 배포되기 전까지는 현재 방어선을 유지하는 편이 안전합니다.

또한 Controller 업그레이드만으로 해결됐다고 가정해서도 안 됩니다.

우리 환경에서는 여러 클러스터가 서로 다른 Controller 버전을 사용할 수 있기 때문에 실제 버전과 해당 버전의 rollback 동작을 확인한 뒤 변경해야 합니다.

7. 검증 — rollback drill

설정 변경은 정상 배포만 테스트해서는 충분하지 않습니다.

이번 문제는 정상 배포가 아니라 rollbackWindow 전용 경로에서만 발생했기 때문입니다.

따라서 회귀 테스트도 실제 rollback을 포함해야 합니다.

적용 경로가 두 개이므로 검증 역시 두 레인으로 나눕니다.

레인대상확인할 것
A서비스 자체 steps overriderollback 시 weight가 100 대신 앞의 낮은 rung에 머무는지
Bbase chart 상속 서비스base 변경이 렌더 결과에 정상적으로 전파되는지

레인 A — 실제 rollback

예를 들어 BEFORE 설정을

steps: - setWeight: 5 - pause: duration: 10s - setWeight: 100

으로 두고 rollbackWindow를 재현합니다.

확인할 값은 다음입니다.

BEFORE rollback → 초기 ReplicaSet이 완전히 준비되기 전에 weight 100이 관측되는가

그다음 마지막 100을 제거합니다.

steps: - setWeight: 5 - pause: duration: 10s

같은 rollback을 다시 수행합니다.

AFTER rollback → 초기 ReplicaSet이 준비 중일 때 weight 5가 유지되는가 → 전체 ReplicaSet 준비 후 100% promotion 되는가

레인 B — base 전파

base chart 변경은 다음 순서로 확인합니다.

helm template → 변경 전/후 manifest 비교 → base를 상속하는 서비스 1개 적용 → 실제 Rollout 관찰 → 적용 범위 확대

차트 변경 자체와 실제 서비스 적용은 별개입니다.

서비스가 자체 steps를 선언했다면 base 변경이 전파되지 않으므로 반드시 최종 렌더 결과를 기준으로 확인해야 합니다.

또한 작은 stage 환경에서는

20 Pods 중 2 Pods에 100%

같은 실제 사고 비율을 그대로 재현하지 못할 수 있습니다.

따라서 이 drill의 목표는 피해량 재현이 아니라 traffic weight 결정 경로의 회귀 확인입니다.

8. 정리

이번 문제는 세 단계로 정리할 수 있습니다.

1부에서는 정상 Canary가 안전한 이유를 봤습니다.

step을 순서대로 진행 → 새 ReplicaSet 준비 확인 → 준비가 안 됐으면 이전 weight 유지 → AnalysisRun으로 이상 감지 → promotion

2부에서는 rollbackWindow가 이 전제를 어떻게 바꾸는지 봤습니다.

rollbackWindow → step index를 끝으로 이동 → AnalysisRun skip → 새 ReplicaSet은 아직 일부만 Available → 이전 weight 역탐색 → 마지막 setWeight: 100 선택 → 준비되지 않은 ReplicaSet에 100% traffic

이번 글의 처방은 그 역탐색 결과를 바꾸는 것입니다.

5 → pause → 100

5 → pause

로 바꾸면 정상 배포의 최종 결과는 그대로입니다.

하지만 rollbackWindow에서는

이전 weight = 100

이 아니라

이전 weight = 5

가 됩니다.

즉 마지막 setWeight: 100 제거의 의미는 최종 traffic을 100%로 만들지 않겠다는 것이 아닙니다.

100%를 적용할 시점을 step 안에서 강제로 앞당기지 않겠다는 것입니다.

실제 적용에서는 다음을 함께 가져갑니다.

  • 마지막 setWeight: 100 제거
  • 서비스 override까지 별도 점검
  • 마지막으로 남는 weight와 초기 Canary 용량의 관계 검증
  • CI에서 위험한 step 패턴 검출
  • rollback drill을 Controller 업그레이드 회귀 테스트에 포함
  • 인시던트 런북에 retry, promote, promote --full의 차이 명시

그리고 upstream에서 Canary Available에 맞춰 traffic weight를 제한하는 수정이 실제 릴리스되고 모든 클러스터에 적용되면 이 workaround를 다시 평가할 수 있습니다.

9. 남는 위험

이 해결 방법은 현재 Controller가

ReplicaSet이 준비되지 않았을 때 이전 setWeight를 역탐색한다.

는 동작을 한다는 전제 위에 있습니다.

Controller 버전이 올라가면서 이 로직이나 rollbackWindow의 처리 순서가 바뀌면 같은 values가 다른 의미를 가질 수 있습니다.

따라서 Argo Rollouts 업그레이드에서는 일반 Canary 성공 여부만 확인해서는 부족합니다.

최소한 다음 시퀀스를 회귀 테스트로 유지해야 합니다.

정상 배포 → 이전 revision으로 rollback → rollbackWindow 진입 확인 → 초기 ReplicaSet 준비 중 traffic weight 확인 → 전체 ReplicaSet 준비 → promotion → abort / promote --full 탈출 경로 확인

특히 여러 클러스터에서 서로 다른 Argo Rollouts 버전을 사용한다면 values가 같아도 동작이 같다고 가정하면 안 됩니다.

최종적으로 필요한 것은 특정 설정 한 줄보다 Rollout의 traffic weight와 ReplicaSet capacity가 항상 함께 검증되는 구조입니다.

이번 수정은 upstream에서 그 관계를 직접 보장하기 전까지 사용하는 방어선입니다.

02 rollbackWindow는 왜 그 안전장치를 깨는가

01 정상 Canary는 왜 안전한가: step과 AnalysisRun