ルーティング規則を設計する
한국어 원문으로 표시합니다.
목표
VirtualService 와 DestinationRule 의 역할을 손으로 갈라 보고, 매칭 규칙의 순서와 AND/OR 결합이 실제 라우팅 결과를 어떻게 바꾸는지 익힙니다.
왜 중요한가
ICA 출제 비중 40%가 트래픽 관리입니다. 그런데 이 영역의 실무 사고는 대부분 문법이 아니라 역할 분담을 몰라서 생깁니다. "v2 로 10% 보내기"는 VirtualService 가 하지만 "v2 란 무엇인가"는 DestinationRule 이 정의합니다. 둘 중 하나만 만들면 Envoy 안에는 갈 곳 없는 라우트나 아무도 참조하지 않는 클러스터가 남고, 결과는 503 입니다.
규칙 순서도 마찬가지입니다. Istio 는 첫 매치에서 평가를 멈추므로, 포괄 규칙을 위에 두면 그 아래 규칙은 영원히 실행되지 않습니다. 반대로 마지막에 catch-all 이 없으면 예상 못 한 요청이 NR 로 떨어집니다. 이 두 가지는 코드 리뷰에서 잡아야 하는 항목이고, 그러려면 눈에 익어야 합니다.
이 실습에서 Kubernetes 기본 리소스는 실제로 apply 하고, Istio CRD 는 /root/ica-traffic/ 아래 파일로 작성합니다. 실습 클러스터에 Istio CRD 가 설치돼 있지 않기 때문이며, 시험에서 요구하는 능력 역시 "매니페스트를 정확히 쓰는 것"입니다.
단계
- 네임스페이스
ica-traffic을 만들고 라벨istio-injection=enabled를 붙이세요. - 네임스페이스
ica-traffic에 디플로이먼트reviews-v1과reviews-v2를 각각 1 레플리카로 배포하세요. 두 파드 템플릿 모두 라벨app=reviews를 갖고,reviews-v1은version=v1,reviews-v2는version=v2를 추가로 가져야 합니다. 이미지는nginx:1.27-alpine을 쓰세요. - 같은 네임스페이스에 서비스
reviews를 만드세요. 포트는9080, 포트 이름은http, selector 는app=reviews하나만 씁니다. /root/ica-traffic/dr-reviews.yaml에 DestinationRulereviews를 작성하세요.spec.host는reviews.ica-traffic.svc.cluster.local, subsets 는v1(labelsversion: v1),v2(labelsversion: v2) 순서입니다./root/ica-traffic/vs-reviews-weight.yaml에 VirtualService 를 작성하세요.spec.hosts[0]은reviews.ica-traffic.svc.cluster.local, http 규칙 하나에 destination 두 개를 두고 subsetv1에 weight 90, subsetv2에 weight 10 을 줍니다./root/ica-traffic/vs-reviews-header.yaml에 VirtualService 를 작성하세요. 규칙은 두 개입니다. 첫 규칙은 헤더x-qa-user가true인 요청을 subsetv2로 보내고, 두 번째 규칙은 match 없이 subsetv1로 보냅니다./root/ica-traffic/vs-reviews-rewrite.yaml에 VirtualService 를 작성하세요.uri.prefix가/api/v2/인 요청의 경로를/로 재작성해 subsetv2로 보냅니다. redirect 는 쓰지 마세요./root/ica-traffic/vs-reviews-final.yaml에 이름이reviews-final인 VirtualService 를 작성하세요. 규칙 세 개를 순서대로 둡니다. (1) 헤더x-qa-user: true이면v2, (2)uri.prefix가/api/v2/이면서 동시에method.exact가GET이면v2, (3) match 없는 catch-all 은v1.
참고
- 매니페스트 골격은
kubectl create deployment ... --dry-run=client -o yaml로 뽑아 편집하면 빠릅니다. - 파일 문법 확인은
yq '.spec' 파일명으로 합니다. 값이null로 나오면 그 경로가 틀린 것입니다. - 흔한 실수 1: 서비스 selector 에
version을 넣어 한 버전만 잡히게 만드는 것. 그러면 가중치가 아무 의미가 없습니다. - 흔한 실수 2: DestinationRule 의 subset 라벨을
v1같은 subset 이름으로 적는 것. labels 는 파드 라벨과 같아야 합니다. - 8단계의 AND 조건은 match 항목 하나 안에
uri와method를 나란히 두어야 합니다. 항목을 두 개로 나누면 OR 이 됩니다.
메시에 편입될 네임스페이스 만들기
네임스페이스 ica-traffic 을 만들고 라벨 istio-injection=enabled 를 붙이세요.
네임스페이스만 만들면 사이드카가 주입되지 않습니다. 자동 주입을 켜는 라벨 하나를 더 붙여야 합니다. 라벨 키는 istio-injection 입니다.
버전 라벨이 다른 두 디플로이먼트 배포
네임스페이스 ica-traffic 에 디플로이먼트 reviews-v1 과 reviews-v2 를 각각 1 레플리카로 배포하세요. 두 파드 템플릿 모두 라벨 app=reviews 를 갖고, reviews-v1 은 version=v1, reviews-v2 는 version=v2 를 추가로 가져야 합니다. 이미지는 nginx:1.27-alpine 을 쓰세요.
두 디플로이먼트의 파드가 같은 서비스로 묶이려면 공통 라벨(app)이 같아야 하고, subset 으로 갈리려면 구분 라벨(version)이 달라야 합니다. 라벨은 파드 템플릿 쪽에 있어야 의미가 있습니다.
두 버전을 함께 묶는 서비스 만들기
같은 네임스페이스에 서비스 reviews 를 만드세요. 포트는 9080, 포트 이름은 http, selector 는 app=reviews 하나만 씁니다.
서비스 selector 에 version 을 넣으면 한 버전만 잡혀서 가중치 분배가 불가능해집니다. 버전 구분은 서비스가 아니라 DestinationRule 의 몫입니다. 포트 이름도 프로토콜을 알 수 있게 지으세요.
subset 정의하기
/root/ica-traffic/dr-reviews.yaml 에 DestinationRule reviews 를 작성하세요. spec.host 는 reviews.ica-traffic.svc.cluster.local, subsets 는 v1(labels version: v1), v2(labels version: v2) 순서입니다.
subset 의 labels 는 파드 라벨과 글자 그대로 같아야 합니다. 어긋나면 클러스터는 생기는데 엔드포인트가 0개가 되어 503 UH 를 만납니다. host 는 짧은 이름 대신 FQDN 으로 적으세요.
90/10 가중치 분배
/root/ica-traffic/vs-reviews-weight.yaml 에 VirtualService 를 작성하세요. spec.hosts[0] 은 reviews.ica-traffic.svc.cluster.local, http 규칙 하나에 destination 두 개를 두고 subset v1 에 weight 90, subset v2 에 weight 10 을 줍니다.
가중치는 route 배열의 각 destination 에 붙습니다. 합이 100 이 되어야 하고, subset 이름은 4단계에서 만든 것과 정확히 같아야 합니다.
헤더 기반 라우팅과 catch-all
/root/ica-traffic/vs-reviews-header.yaml 에 VirtualService 를 작성하세요. 규칙은 두 개입니다. 첫 규칙은 헤더 x-qa-user 가 true 인 요청을 subset v2 로 보내고, 두 번째 규칙은 match 없이 subset v1 로 보냅니다.
규칙은 위에서 아래로 평가되고 첫 매치가 이깁니다. 헤더 조건이 붙은 규칙을 먼저, match 가 아예 없는 규칙을 마지막에 두세요. exact 값은 문자열입니다.
URI 접두사 재작성
/root/ica-traffic/vs-reviews-rewrite.yaml 에 VirtualService 를 작성하세요. uri.prefix 가 /api/v2/ 인 요청의 경로를 / 로 재작성해 subset v2 로 보냅니다. redirect 는 쓰지 마세요.
rewrite 는 요청을 프록시하면서 경로를 바꾸고, redirect 는 클라이언트에게 3xx 를 돌려줍니다. 이 단계에서 필요한 것은 백엔드가 눈치채지 못하게 경로를 바꾸는 쪽입니다.
세 규칙을 한 VirtualService 로 합치기
/root/ica-traffic/vs-reviews-final.yaml 에 이름이 reviews-final 인 VirtualService 를 작성하세요. 규칙 세 개를 순서대로 둡니다. (1) 헤더 x-qa-user: true 이면 v2, (2) uri.prefix 가 /api/v2/ 이면서 동시에 method.exact 가 GET 이면 v2, (3) match 없는 catch-all 은 v1.
가장 구체적인 규칙이 맨 위, 포괄 규칙이 맨 아래입니다. 경로와 메서드를 AND 로 묶으려면 match 항목을 두 개 만들지 말고 한 항목 안에 두 조건을 나란히 두세요.