Running a Canary With Weights, Headers and Mirroring
한국어 원문으로 표시합니다.
목표
가중치·헤더·미러링 세 가지 분할 방식을 상황에 맞게 골라 쓰고, 되돌릴 조건이 명시된 카나리 계획을 만들 수 있게 됩니다.
왜 중요한가
카나리의 본질은 "조금 준다"가 아니라 "언제 멈출지를 먼저 정한다" 입니다. 가중치를 올리는 일은 누구나 할 수 있지만, 나쁜 지표를 보고 되돌리는 판단은 사람에게 맡기면 흔들립니다. 그래서 단계마다 판단 기준을 적어 두고, 그 기준이 곧 자동화의 입력이 되게 만듭니다. 또 하나 중요한 것은 파드 개수와 트래픽 비율의 분리입니다. 메시에서는 새 버전을 다 띄워 놓고도 트래픽은 0% 로 둘 수 있고, 문제가 보이면 배포 없이 가중치만 0 으로 되돌릴 수 있습니다.
이 실습은 두 종류의 채점이 섞여 있습니다. 1·2·4·5번은 저장된 파일을 보고, 6·7·8번은 클러스터에 실제로 적용된 상태를 봅니다. 그래서 단계마다 파일을 따로 남겨야 하고, 하나를 계속 덮어쓰면 앞 단계가 다시 실패합니다. 각 vs-*.yaml 파일에는 VirtualService 문서 하나만 넣으세요(여러 문서를 한 파일에 담으면 채점이 첫 문서를 특정하지 못합니다).
단계
시작 전 준비. 실습 파드는 실습마다 새로 뜨므로 앞 실습의 메시 설정은 남아 있지 않습니다. kubectl get crd virtualservices.networking.istio.io 가 비어 있으면 istioctl manifest generate --set profile=minimal > /root/istio/manifest.yaml 후 kubectl apply -f /root/istio/manifest.yaml 을 두 번 실행하고, kubectl create ns mesh-lab && kubectl label ns mesh-lab istio-injection=enabled 로 네임스페이스를 만드세요. 6번은 살아 있는 파드를 라벨로 조회하므로 픽스처 워크로드의 파드가 Running 이 될 때까지 기다려야 합니다.
- 먼저
/opt/lab/fixtures/istio/workload-v1v2.yaml을mesh-lab에 적용하고,spec.subsets에v1(labels: {version: v1})·v2(labels: {version: v2})를 가진 DestinationRulereviews를 적용해 두세요. 그다음/root/istio/canary/vs-baseline.yaml을 만드세요 — VirtualService 하나이며spec.http[0].route에 항목이 정확히 두 개,subset: v1의weight는 100,subset: v2의weight는 0 입니다. /root/istio/canary/vs-90-10.yaml을 만드세요. v1 은weight: 90, v2 는weight: 10입니다(합은 100). 이 파일을kubectl apply하고 그 출력을/root/istio/canary/out/applied-10.txt에 저장하세요(configured/created/unchanged중 하나가 보여야 합니다).- 가중치 합이 100 이 아닌 파일(예:
/root/istio/canary/vs-bad.yaml에 v1 90 / v2 20)을 만들어istioctl validate -f로 검사하고, 그 거부 메시지를 표준 에러까지 포함해/root/istio/canary/out/weight-error.txt에 저장하세요. 그리고/root/istio/canary/out/weight-note.txt에 가중치 합이 100 이어야 한다는 규칙을 적으세요. /root/istio/canary/vs-header.yaml을 만드세요. 헤더x-canary가 정확히true인 요청을 고르는 라우트를 앞쪽에 두고 목적지는subset: v2,weight: 100입니다. 그 뒤에 조건 없는 기본 라우트를 하나 더 두세요(조건부 라우트가 마지막이면 안 됩니다)./root/istio/canary/vs-mirror.yaml을 만드세요.spec.http[0].route는subset: v1에weight: 100이고, 같은 항목에mirror(host: reviews,subset: v2)와mirrorPercentage.value: 10을 두세요. 그리고/root/istio/canary/out/mirror-note.txt에 미러된 요청의 응답이 버려진다는 점과 쓰기 작업의 부작용 위험을 적으세요.- 먼저
vs-90-10.yaml을 다시 적용해 v1·v2 를 모두 참조하는 상태로 만드세요. 그다음 DestinationRulereviews의 subset 이름v2를 잠시v2-canary로 바꿔 적용하고istioctl analyze -n mesh-lab결과를/root/istio/canary/out/analyze-mismatch.txt에 저장하세요. 이름을v2(labelsversion: v2)로 되돌려 적용한 뒤 다시 분석해/root/istio/canary/out/analyze-clean.txt에 저장하세요(여기에는Error [가 없어야 합니다). - DestinationRule
reviews에trafficPolicy.loadBalancer.consistentHash.httpHeaderName: x-user-id를 추가해 적용하세요. 그리고/root/istio/canary/out/sticky-note.txt(50바이트 이상)에 같은 사용자가 버전 사이를 왔다 갔다 하면 왜 문제가 되는지 적으세요. /root/istio/canary/rollout.yaml을 만드세요. 최상위에stages배열(5단계 이상)과rollback키가 있어야 합니다. 각 stage 에는weight(v2 가중치)와criteria(다음 단계로 넘어갈 판단 기준)가 모두 있어야 하고, weight 는 0 으로 시작해 100 으로 끝나며 중간에 줄어들면 안 됩니다. 마지막으로 실제 VirtualServicereviews를 v1 50 / v2 50 으로 적용하세요(spec.http의 마지막 항목 기준).istioctl analyze -n mesh-lab결과는/root/istio/canary/out/final-analyze.txt에 저장하고 오류가 없어야 합니다.
참고
- 실습 파드는 실습마다 새로 뜨므로 앞 실습의 클러스터 상태는 남아 있지 않습니다. 그래서 메시 설정을 매니페스트로 남겨 두는 것이 곧 재현 가능성입니다. 이 실습이 단계마다 파일을 따로 남기라고 요구하는 이유도 같습니다 — 클러스터는 사라져도 파일은 남습니다.
kubectl get pods -n mesh-lab -l app=reviews --show-labels로 파드의version라벨이 실제로 붙어 있는지 먼저 확인하세요. 6번 채점이 이 라벨로 파드를 찾습니다.- 3번의
istioctl validate는 실패로 끝나므로istioctl validate -f 파일 > 출력 2>&1 || true처럼 저장하세요. - 6번에서 subset 이름을 바꾸면 VirtualService 가 참조하는
v2가 사라져 분석이 즉시 잡아냅니다. 라벨만 바꾸는 것보다 확실한 실험입니다. - 8번의
rollout.yaml은 Istio 리소스가 아니라 여러분이 설계한 계획 파일입니다. 형식은 자유지만stages·weight·criteria·rollback키 이름은 그대로 쓰세요. - 흔한 실수 1: 파일 하나를 계속 고쳐 쓰는 것. 단계마다 다른 파일이어야 앞 단계 채점이 유지됩니다.
- 흔한 실수 2: 5번에서 v1 의
weight: 100을 생략하는 것. 목적지가 하나면 생략해도 동작은 하지만, 미러링이 실제 응답을 바꾸지 않는다는 사실을 매니페스트에 명시적으로 남겨 두는 편이 안전합니다.
100/0 시작점 매니페스트 만들기
먼저 /opt/lab/fixtures/istio/workload-v1v2.yaml 을 mesh-lab 에 적용하고, spec.subsets 에 v1(labels: {version: v1})·v2(labels: {version: v2})를 가진 DestinationRule reviews 를 적용해 두세요. 그다음 /root/istio/canary/vs-baseline.yaml 을 만드세요 — VirtualService 하나이며 spec.http[0].route 에 항목이 정확히 두 개, subset: v1 의 weight 는 100, subset: v2 의 weight 는 0 입니다.
새 버전을 배포는 하되 트래픽은 주지 않는 상태입니다. 두 subset 을 모두 적어 두면 다음 단계부터는 숫자만 바꾸면 됩니다.
10% 를 새 버전으로 옮기기
/root/istio/canary/vs-90-10.yaml 을 만드세요. v1 은 weight: 90, v2 는 weight: 10 입니다(합은 100). 이 파일을 kubectl apply 하고 그 출력을 /root/istio/canary/out/applied-10.txt 에 저장하세요(configured/created/unchanged 중 하나가 보여야 합니다).
앞 단계 파일을 덮어쓰지 말고 새 파일로 남기세요. 적용 결과 출력도 증거로 저장해야 합니다.
가중치 합이 틀렸을 때 무슨 일이 나는지 보기
가중치 합이 100 이 아닌 파일(예: /root/istio/canary/vs-bad.yaml 에 v1 90 / v2 20)을 만들어 istioctl validate -f 로 검사하고, 그 거부 메시지를 표준 에러까지 포함해 /root/istio/canary/out/weight-error.txt 에 저장하세요. 그리고 /root/istio/canary/out/weight-note.txt 에 가중치 합이 100 이어야 한다는 규칙을 적으세요.
일부러 틀린 파일을 만들어 검증 도구에 물어보세요. 거부 메시지 자체가 이 단계의 산출물입니다. 명령이 실패로 끝나므로 표준 에러까지 저장해야 합니다.
무엇이 걸리고 무엇이 안 걸리는지가 이 단계의 핵심입니다. 합이 110 이어도 지금 istioctl 은 통과시킵니다 — 엔보이가 total_weight 로 정규화하도록 바뀌면서 합 100 규칙이 검증에서 빠졌습니다. 반면 합이 0 이면 거부됩니다. 둘 다 해 보고 결과를 함께 남기세요. 검증 도구가 모든 실수를 잡아 주지는 않는다는 것이 여기서 배울 것입니다.
내부 테스터만 새 버전으로 보내기
/root/istio/canary/vs-header.yaml 을 만드세요. 헤더 x-canary 가 정확히 true 인 요청을 고르는 라우트를 앞쪽에 두고 목적지는 subset: v2, weight: 100 입니다. 그 뒤에 조건 없는 기본 라우트를 하나 더 두세요(조건부 라우트가 마지막이면 안 됩니다).
지정한 사람은 100% 새 버전을 봐야 합니다. 조건부 라우트는 기본 경로보다 위에 있어야 하고, 기본 경로는 조건 없이 맨 끝에 둡니다.
응답을 버리는 미러링 걸기
/root/istio/canary/vs-mirror.yaml 을 만드세요. spec.http[0].route 는 subset: v1 에 weight: 100 이고, 같은 항목에 mirror(host: reviews, subset: v2)와 mirrorPercentage.value: 10 을 두세요. 그리고 /root/istio/canary/out/mirror-note.txt 에 미러된 요청의 응답이 버려진다는 점과 쓰기 작업의 부작용 위험을 적으세요.
미러링은 사용자에게 가는 응답을 바꾸지 않습니다. 실제 트래픽은 기존 버전이 100% 처리하고, 사본만 새 버전으로 갑니다. 비율 지정도 잊지 마세요.
subset 과 파드 라벨의 불일치 만들고 고치기
먼저 vs-90-10.yaml 을 다시 적용해 v1·v2 를 모두 참조하는 상태로 만드세요. 그다음 DestinationRule reviews 의 subset 이름 v2 를 잠시 v2-canary 로 바꿔 적용하고 istioctl analyze -n mesh-lab 결과를 /root/istio/canary/out/analyze-mismatch.txt 에 저장하세요. 이름을 v2(labels version: v2)로 되돌려 적용한 뒤 다시 분석해 /root/istio/canary/out/analyze-clean.txt 에 저장하세요(여기에는 Error [ 가 없어야 합니다).
라우트가 참조하는 subset 이 정의에서 사라지면 정적 분석이 잡아냅니다. 어긋난 상태와 고친 상태의 분석 결과를 각각 남기세요.
같은 사용자를 한 버전에 고정하기
DestinationRule reviews 에 trafficPolicy.loadBalancer.consistentHash.httpHeaderName: x-user-id 를 추가해 적용하세요. 그리고 /root/istio/canary/out/sticky-note.txt(50바이트 이상)에 같은 사용자가 버전 사이를 왔다 갔다 하면 왜 문제가 되는지 적으세요.
가중치 분할은 요청마다 다시 뽑습니다. 로드밸런서를 해시 기반으로 바꾸고 어떤 헤더를 키로 쓸지 정하세요.
단계별 카나리 계획 세우고 중간까지 진행하기
/root/istio/canary/rollout.yaml 을 만드세요. 최상위에 stages 배열(5단계 이상)과 rollback 키가 있어야 합니다. 각 stage 에는 weight(v2 가중치)와 criteria(다음 단계로 넘어갈 판단 기준)가 모두 있어야 하고, weight 는 0 으로 시작해 100 으로 끝나며 중간에 줄어들면 안 됩니다. 마지막으로 실제 VirtualService reviews 를 v1 50 / v2 50 으로 적용하세요(spec.http 의 마지막 항목 기준). istioctl analyze -n mesh-lab 결과는 /root/istio/canary/out/final-analyze.txt 에 저장하고 오류가 없어야 합니다.
계획에는 단계마다 가중치와 판단 기준이 필요하고, 전체에는 되돌리는 방법이 필요합니다. 그리고 실제 메시도 중간 단계까지 옮겨 두세요.