Istio 심화 — 왜 그렇게 흐르는가 · VirtualService 가 라우트 표가 되기까지 · 실습
VirtualService 를 라우트 표로 번역해 순서와 재시도를 확인한다
목표
VirtualService 가 Envoy 라우트 표로 번역되는 규칙을 따라 손으로 표를 세우고, Host 헤더·첫 매치 우선·가중치·재시도를 요청으로 확인한다.
왜 중요한가
VirtualService 의 실수는 대개 규칙 하나가 아니라 규칙 사이의 순서와 겹침에서 나온다. 정적 분석은 그것을 잡지 못하므로, 번역 규칙을 알고 Envoy 에서 어떻게 동작할지 그릴 줄 알아야 변경 리뷰에서 걸러 낼 수 있다.
단계
1. /root/ist2-route/dr.yaml(DestinationRule reviews, host reviews.default.svc.cluster.local, 서브셋 v1·v2·broken — 라벨 version 이 각각 같은 이름)과 /root/ist2-route/vs.yaml(VirtualService reviews, hosts [reviews])을 쓰세요. vs.yaml 의 http 는 이 순서로 네 개입니다 — jason(헤더 end-user 가 정확히 jason 이면 v2), api(경로 접두사 /api 면 v1), flaky(경로 접두사 /flaky 면 broken, retries: {attempts: 3, retryOn: 5xx}, timeout: 2s), default(v1 에 weight 75, v2 에 25). istioctl analyze --use-kube=false vs.yaml dr.yaml 의 출력과 종료 코드를 /root/ist2-route/01-analyze.txt 에 담으세요(마지막 줄 rc=0).
2. 서비스 reviews 는 네임스페이스 default, 포트 9080 입니다. 이 VirtualService 가 사이드카에서 만드는 라우트 표의 이름들을 /root/ist2-route/02-names.txt 에 세 줄로 적으세요 — route_config=(라우트 표 이름), virtual_host=(가상 호스트 이름), domains=(그 가상 호스트의 도메인 중 짧은 이름 네 가지를 쉼표로, 순서 무관).
3. /root/ist2-route/route.yaml 에 Envoy 설정을 쓰세요 — 관리 포트 9984, 리스너 127.0.0.1:10084, 2단계의 라우트 표 이름·가상 호스트 이름·domains 네 개. 라우트는 이름을 붙여 이 순서로 셋 — jason(경로 / + 헤더 end-user 정확히 jason → outbound|9080|v2|reviews.default.svc.cluster.local), api(접두사 /api → outbound|9080|v1|reviews.default.svc.cluster.local), default(접두사 / → outbound|9080|v1|reviews.default.svc.cluster.local). 클러스터는 v1(127.0.0.1:8105)·v2(127.0.0.1:8106) 둘. 업스트림 둘을 ok 로 띄우고 Envoy 를 띄운 뒤 Host 헤더 세 가지로 / 를 불러 /root/ist2-route/03-hosts.txt 에 reviews=, reviews.default.svc.cluster.local=, ratings= 세 줄로 HTTP 코드를 적으세요.
4. route.yaml 로 떠 있는 Envoy 에 Host reviews 로 세 요청을 보내고, 응답 본문의 포트로 서브셋을 가려 /root/ist2-route/04-match.txt 에 적으세요 — anonymous=(헤더 없이 /), jason=(end-user: jason 으로 /), api_as_jason=(end-user: jason 으로 /api/list). 값은 v1 또는 v2 입니다.
5. vs.yaml 에서 default 규칙을 맨 앞으로 옮긴 /root/ist2-route/vs-bad.yaml 을 만들고 istioctl analyze --use-kube=false vs-bad.yaml dr.yaml 의 종료 코드를 확인하세요. 같은 실수를 Envoy 로: route.yaml 에서 default 라우트를 맨 앞으로 옮긴 /root/ist2-route/route-bad.yaml 로 Envoy 를 다시 띄우고 end-user: jason 으로 / 를 불러 보세요. /root/ist2-route/05-order.txt 에 analyze_rc=(vs-bad 분석의 종료 코드), jason_after=(route-bad 에서 jason 이 간 서브셋) 두 줄을 적으세요. 확인한 뒤에는 route.yaml 로 되돌려 띄워 두세요.
6. route.yaml 을 /root/ist2-route/route-split.yaml 로 복사하고 default 라우트만 weighted_clusters 로 바꾸세요(v1 75, v2 25 — VirtualService 의 default 규칙 그대로). --concurrency 1 로 다시 띄운 뒤 Host reviews 로 / 를 정확히 40 번 보내 /root/ist2-route/06-split.txt 에 v1=, v2=, total= 세 줄을 적으세요.
7. route-split.yaml 을 /root/ist2-route/route-retry.yaml 로 복사하고 두 가지를 더하세요 — 클러스터 outbound|9080|broken|reviews.default.svc.cluster.local(127.0.0.1:8114, 늘 503 을 내는 업스트림), 그리고 default 앞에 flaky 라우트(접두사 /flaky → 그 클러스터, timeout: 2s, retry_policy: {retry_on: 5xx, num_retries: 3}). 업스트림을 8114 에 fail 로 띄우고 Envoy 를 다시 띄운 뒤 /flaky 를 한 번만 부르세요. /root/ist2-route/07-retry.txt 에 status=(HTTP 코드), upstream_rq_retry=, upstream_rq_total=(broken 클러스터의 두 통계 값)을 적으세요.
8. /root/ist2-route/08-report.md 에 route_config=, virtual_host=, first_match_wins=(5단계에서 본 대로 처음 맞는 라우트 하나만 쓰이면 yes), retry_attempts=(VirtualService 의 attempts 값) 네 줄을 적고, 그 아래 - 로 시작하는 설명을 네 줄 이상 적으세요.
참고
- 이 파드에는 진짜 istiod 도 진짜 사이드카도 없습니다. 그래서
istioctl proxy-config로 실제 생성물을 볼 수 없고, 번역 규칙을 알고 손으로 등가 Envoy 설정을 만들어 동작을 확인합니다. 같은 규칙이 운영 클러스터의proxy-config출력에 그대로 보입니다. - 모든 요청에
-H 'Host: reviews'를 붙이세요. 가상 호스트는 Host 헤더로 고릅니다. - 분배와 재시도를 세는 6·7단계는 Envoy 를
--concurrency 1로 띄우세요. 통계는 누적되므로 다시 띄운 직후에 셉니다. - Envoy 를 띄울 때는
setsid --fork nohup envoy -c <파일> --log-level warn > <로그> 2>&1 </dev/null로 셸에서 완전히 떼어 놓으세요. 다시 띄우기 전에는pkill -x envoy로 정리합니다 (pkill -f 'envoy -c'는 그 문자열이 든 셸 자신까지 죽입니다). - 업스트림 흉내용 서버가 이미지에 있습니다:
python3 /opt/lab/envoy/upstream.py <포트> ok|fail|slow. 응답 본문은<모드>:<포트> <경로>입니다. - 설정을 고친 뒤에는 띄우기 전에
envoy --mode validate -c <파일>로 먼저 거르세요. 클러스터 이름에|가 들어가므로 YAML 에서는 반드시 따옴표로 감쌉니다.
8단계
- 라우트 네 개짜리 VirtualService 를 쓰고 분석을 통과시킨다
- 라우트 표·가상 호스트·도메인의 이름을 도출한다
- 그 이름으로 라우트 표를 세우고 Host 헤더로 고르는 것을 본다
- 헤더 매치와 경로 매치가 겹칠 때 누가 이기는가
- catch-all 을 앞에 두면 — 분석은 조용하고 트래픽은 틀린다
- weight 는 weighted_clusters 가 된다 — 마흔 번 센다
- retries 와 timeout 이 retry_policy 가 된다 — 몇 번 두드리는지 센다
- VirtualService 번역표로 정리한다