LabHub
배우기 러닝패스 코스

ICA — Istio Certified Associate

Designing Routing Rules

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

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 가 설치돼 있지 않기 때문이며, 시험에서 요구하는 능력 역시 "매니페스트를 정확히 쓰는 것"입니다.

단계

  1. 네임스페이스 ica-traffic 을 만들고 라벨 istio-injection=enabled 를 붙이세요.
  2. 네임스페이스 ica-traffic 에 디플로이먼트 reviews-v1reviews-v2 를 각각 1 레플리카로 배포하세요. 두 파드 템플릿 모두 라벨 app=reviews 를 갖고, reviews-v1version=v1, reviews-v2version=v2 를 추가로 가져야 합니다. 이미지는 nginx:1.27-alpine 을 쓰세요.
  3. 같은 네임스페이스에 서비스 reviews 를 만드세요. 포트는 9080, 포트 이름은 http, selector 는 app=reviews 하나만 씁니다.
  4. /root/ica-traffic/dr-reviews.yaml 에 DestinationRule reviews 를 작성하세요. spec.hostreviews.ica-traffic.svc.cluster.local, subsets 는 v1(labels version: v1), v2(labels version: v2) 순서입니다.
  5. /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 을 줍니다.
  6. /root/ica-traffic/vs-reviews-header.yaml 에 VirtualService 를 작성하세요. 규칙은 두 개입니다. 첫 규칙은 헤더 x-qa-usertrue 인 요청을 subset v2 로 보내고, 두 번째 규칙은 match 없이 subset v1 로 보냅니다.
  7. /root/ica-traffic/vs-reviews-rewrite.yaml 에 VirtualService 를 작성하세요. uri.prefix/api/v2/ 인 요청의 경로를 / 로 재작성해 subset v2 로 보냅니다. redirect 는 쓰지 마세요.
  8. /root/ica-traffic/vs-reviews-final.yaml 에 이름이 reviews-final 인 VirtualService 를 작성하세요. 규칙 세 개를 순서대로 둡니다. (1) 헤더 x-qa-user: true 이면 v2, (2) uri.prefix/api/v2/ 이면서 동시에 method.exactGET 이면 v2, (3) match 없는 catch-all 은 v1.

참고

메시에 편입될 네임스페이스 만들기

네임스페이스 ica-traffic 을 만들고 라벨 istio-injection=enabled 를 붙이세요.

네임스페이스만 만들면 사이드카가 주입되지 않습니다. 자동 주입을 켜는 라벨 하나를 더 붙여야 합니다. 라벨 키는 istio-injection 입니다.

버전 라벨이 다른 두 디플로이먼트 배포

네임스페이스 ica-traffic 에 디플로이먼트 reviews-v1reviews-v2 를 각각 1 레플리카로 배포하세요. 두 파드 템플릿 모두 라벨 app=reviews 를 갖고, reviews-v1version=v1, reviews-v2version=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.hostreviews.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-usertrue 인 요청을 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.exactGET 이면 v2, (3) match 없는 catch-all 은 v1.

가장 구체적인 규칙이 맨 위, 포괄 규칙이 맨 아래입니다. 경로와 메서드를 AND 로 묶으려면 match 항목을 두 개 만들지 말고 한 항목 안에 두 조건을 나란히 두세요.