Istio Deep Dive — Why It Flows That Way
Turn Subsets into Clusters and Trace Them by Name
한국어 원문으로 표시합니다.
목표
DestinationRule 에서 클러스터 이름을 규칙으로 도출하고, 그 이름 그대로 Envoy 를 구성해 서브셋별 라우팅·통계 이름·없는 서브셋의 503 을 직접 확인한다.
왜 중요한가
Istio 장애 조사의 절반은 proxy-config clusters 와 통계를 읽는 일이다. 클러스터 이름은 규칙으로 만들어지므로 규칙을 알면 이름만 보고 서비스·포트·서브셋을 알아볼 수 있고, '서브셋이 없다', '엔드포인트가 비었다', '통계 이름이 바뀌었다' 를 몇 초 만에 가를 수 있다.
단계
/root/ist2-name/dr.yaml에 DestinationRule 을 쓰세요 — 이름reviews, 네임스페이스default,host는reviews.default.svc.cluster.local, 서브셋v1(라벨version: v1)과v2(라벨version: v2).istioctl validate -f /root/ist2-name/dr.yaml의 출력과 종료 코드를/root/ist2-name/01-validate.txt에 담으세요(마지막 줄rc=0).- 서비스
reviews는 포트 9080 을 씁니다./root/ist2-name/dr.yaml로 사이드카들이 갖게 될 클러스터 이름 네 개를/root/ist2-name/02-names.txt에 한 줄에 하나씩 적으세요 — 다른 파드가 reviews 로 나갈 때 쓰는 것 셋(서브셋 없는 것 하나와 서브셋마다 하나), 그리고 reviews 파드 자신이 들어오는 요청을 앱으로 넘길 때 쓰는 것 하나. /root/ist2-name/name.yaml에 Envoy 설정을 쓰세요 — 관리 포트9983, 리스너127.0.0.1:10083(HTTP),route_config이름9080, 모든 경로를outbound|9080|v1|reviews.default.svc.cluster.local로 보냅니다. 클러스터는 나가는 쪽 셋 —outbound|9080||reviews.default.svc.cluster.local(엔드포인트127.0.0.1:8103과127.0.0.1:8104둘),outbound|9080|v1|reviews.default.svc.cluster.local(8103만),outbound|9080|v2|reviews.default.svc.cluster.local(8104만). 업스트림 둘을8103·8104에ok로 띄우고 Envoy 를 띄운 뒤,curl localhost:10083/결과를/root/ist2-name/03-v1.txt에status=와body=두 줄로 적으세요./root/ist2-name/name.yaml을/root/ist2-name/split.yaml로 복사하고, 라우트를 가중치 라우트로 바꾸세요 —outbound|9080|v1|reviews.default.svc.cluster.local75,outbound|9080|v2|reviews.default.svc.cluster.local25. Envoy 를split.yaml로--concurrency 1을 붙여 다시 띄운 뒤curl localhost:10083/를 정확히 40 번 보내 응답 본문으로 어느 서브셋에 갔는지 세고,/root/ist2-name/04-split.txt에v1=,v2=,total=세 줄로 적으세요./root/ist2-name/split.yaml의outbound|9080|v2|reviews.default.svc.cluster.local클러스터에alt_stat_name: outbound_9080_v2_reviews를 더하고(다른 것은 그대로) 다시 띄운 뒤 요청을 20 번 이상 보내세요. 관리 포트의/stats에서 두 줄을 그대로 옮겨/root/ist2-name/05-stats.txt에 저장하세요 — v1 클러스터의upstream_rq_200줄, 그리고 v2 클러스터의upstream_rq_200줄(이제 바뀐 이름으로 나옵니다)./root/ist2-name/split.yaml을/root/ist2-name/missing.yaml로 복사하고 두 가지를 바꾸세요 —route_config에validate_clusters: false를 더하고, 기존 라우트 앞에 경로 접두사/v3를outbound|9080|v3|reviews.default.svc.cluster.local로 보내는 라우트를 더합니다(이 클러스터는 만들지 않습니다). 그리고missing.yaml에서validate_clusters: false줄만 뺀 사본/root/ist2-name/missing-strict.yaml도 만드세요.missing.yaml로 띄운 뒤curl localhost:10083/v3를 한 번 보내고/root/ist2-name/06-missing.txt에 세 줄을 적으세요 —status=(HTTP 코드),no_cluster=(통계http.outbound_0.0.0.0_9080.no_cluster의 값),strict_rc=(missing-strict.yaml을envoy --mode validate한 종료 코드).- 떠 있는 Envoy 의
localhost:9983/clusters에서reviews의 세 클러스터가 각각 엔드포인트를 몇 개 가졌는지 세어/root/ist2-name/07-endpoints.txt에<클러스터 이름> <개수>꼴로 세 줄 적으세요. /root/ist2-name/08-report.md에default_cluster=,inbound_cluster=,v2_stat_name=,missing_subset_code=네 줄을 적고(각각 서브셋 없는 나가는 쪽 클러스터 이름, 들어오는 쪽 클러스터 이름, 5단계에서 바꾼 v2 의 통계 이름, 6단계에서 받은 HTTP 코드), 그 아래-로 시작하는 설명을 네 줄 이상 적으세요.
참고
- 이 파드에는 진짜 istiod 도 진짜 사이드카도 없습니다. 그래서
istioctl proxy-config로 실제 생성물을 볼 수 없고, 번역 규칙을 알고 손으로 등가 Envoy 설정을 만들어 동작을 확인합니다. 같은 규칙이 운영 클러스터의proxy-config출력에 그대로 보입니다. - 분배를 세는 4단계부터는 Envoy 를
--concurrency 1로 띄우세요. 워커가 여럿이면 가중치 실험이 더 흔들립니다. /stats와/clusters의 줄에는|가 들어 있습니다.grep에서는\|로 이스케이프하거나grep -F를 쓰세요.- 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 에서는 반드시 따옴표로 감쌉니다.
서브셋 둘을 가진 DestinationRule 을 쓴다
/root/ist2-name/dr.yaml 에 DestinationRule 을 쓰세요 — 이름 reviews, 네임스페이스 default, host 는 reviews.default.svc.cluster.local, 서브셋 v1(라벨 version: v1)과 v2(라벨 version: v2). istioctl validate -f /root/ist2-name/dr.yaml 의 출력과 종료 코드를 /root/ist2-name/01-validate.txt 에 담으세요(마지막 줄 rc=0).
서브셋은 '같은 서비스의 파드 중 이 라벨이 붙은 것' 이라는 이름 붙은 선택자입니다. 이 자체로는 트래픽을 바꾸지 않고, VirtualService 가 subset: v1 으로 가리킬 때 비로소 쓰입니다. host 는 짧은 이름도 되지만 Istio 는 결국 FQDN 으로 풀어서 씁니다 — 여기서는 처음부터 FQDN 으로 적어 두면 다음 단계의 이름 도출이 쉽습니다. istioctl validate 는 클러스터 없이 파일만으로 스키마를 검사합니다.
규칙으로 클러스터 이름 네 개를 도출한다
서비스 reviews 는 포트 9080 을 씁니다. /root/ist2-name/dr.yaml 로 사이드카들이 갖게 될 클러스터 이름 네 개를 /root/ist2-name/02-names.txt 에 한 줄에 하나씩 적으세요 — 다른 파드가 reviews 로 나갈 때 쓰는 것 셋(서브셋 없는 것 하나와 서브셋마다 하나), 그리고 reviews 파드 자신이 들어오는 요청을 앱으로 넘길 때 쓰는 것 하나.
이름은 방향|포트|서브셋|호스트 네 칸입니다. 방향은 outbound 또는 inbound, 포트는 서비스 포트, 서브셋이 없으면 그 칸을 비워 || 가 됩니다. 들어오는 쪽은 자기 파드의 앱으로 보내는 것이라 서브셋도 호스트도 필요 없어서 뒤 두 칸이 모두 빕니다. 호스트 칸은 DestinationRule 의 host 를 FQDN 으로 쓴 것입니다. yq 로 .spec.subsets[].name 을 뽑아 반복문으로 찍으면 오타가 없습니다.
그 이름 그대로 Envoy 를 세워 v1 로 보낸다
/root/ist2-name/name.yaml 에 Envoy 설정을 쓰세요 — 관리 포트 9983, 리스너 127.0.0.1:10083(HTTP), route_config 이름 9080, 모든 경로를 outbound|9080|v1|reviews.default.svc.cluster.local 로 보냅니다. 클러스터는 나가는 쪽 셋 — outbound|9080||reviews.default.svc.cluster.local(엔드포인트 127.0.0.1:8103 과 127.0.0.1:8104 둘), outbound|9080|v1|reviews.default.svc.cluster.local(8103 만), outbound|9080|v2|reviews.default.svc.cluster.local(8104 만). 업스트림 둘을 8103·8104 에 ok 로 띄우고 Envoy 를 띄운 뒤, curl localhost:10083/ 결과를 /root/ist2-name/03-v1.txt 에 status= 와 body= 두 줄로 적으세요.
istiod 는 서비스 하나에 '서브셋 없는 클러스터' 를 늘 만들고, DestinationRule 의 서브셋마다 클러스터를 하나씩 더 만듭니다. 서브셋 클러스터의 엔드포인트는 서비스 전체 엔드포인트 중 라벨이 맞는 것만 추린 것입니다 — 여기서는 포트로 흉내 냅니다(8103 = version v1 파드, 8104 = version v2 파드). 클러스터 이름에 | 가 있으니 따옴표로 감싸고, route_config 이름도 숫자처럼 보이지만 문자열이라 따옴표를 붙입니다.
서브셋 가중치를 마흔 번 세어 본다
/root/ist2-name/name.yaml 을 /root/ist2-name/split.yaml 로 복사하고, 라우트를 가중치 라우트로 바꾸세요 — outbound|9080|v1|reviews.default.svc.cluster.local 75, outbound|9080|v2|reviews.default.svc.cluster.local 25. Envoy 를 split.yaml 로 --concurrency 1 을 붙여 다시 띄운 뒤 curl localhost:10083/ 를 정확히 40 번 보내 응답 본문으로 어느 서브셋에 갔는지 세고, /root/ist2-name/04-split.txt 에 v1=, v2=, total= 세 줄로 적으세요.
VirtualService 의 route[].weight 는 Envoy 의 weighted_clusters 가 됩니다. 가중치는 요청마다 주사위를 굴리는 것이라 마흔 번에 정확히 30 대 10 이 나오지는 않습니다 — 숫자가 조금 어긋나도 정상입니다. --concurrency 1 은 워커를 하나로 묶어 실험을 흔들림 없게 합니다. 본문의 포트(ok:8103 인지 ok:8104 인지)로 서브셋을 가르면 됩니다.
통계 이름은 클러스터 이름이다 — alt_stat_name 으로 바꾼다
/root/ist2-name/split.yaml 의 outbound|9080|v2|reviews.default.svc.cluster.local 클러스터에 alt_stat_name: outbound_9080_v2_reviews 를 더하고(다른 것은 그대로) 다시 띄운 뒤 요청을 20 번 이상 보내세요. 관리 포트의 /stats 에서 두 줄을 그대로 옮겨 /root/ist2-name/05-stats.txt 에 저장하세요 — v1 클러스터의 upstream_rq_200 줄, 그리고 v2 클러스터의 upstream_rq_200 줄(이제 바뀐 이름으로 나옵니다).
Envoy 는 클러스터 통계를 cluster.<클러스터 이름>.<지표> 로 쌓습니다. Istio 의 클러스터 이름에는 | 가 들어가서 프로메테우스로 옮길 때 다루기 번거롭습니다. 그래서 메시 설정의 outboundClusterStatName 에 무늬를 주면 istiod 가 각 클러스터에 alt_stat_name 을 붙여 통계 이름만 바꿉니다 — 라우팅은 여전히 원래 이름으로 합니다. /stats?filter=upstream_rq_200 처럼 거르면 두 줄을 찾기 쉽습니다.
없는 서브셋을 가리키면 503 이 된다
/root/ist2-name/split.yaml 을 /root/ist2-name/missing.yaml 로 복사하고 두 가지를 바꾸세요 — route_config 에 validate_clusters: false 를 더하고, 기존 라우트 앞에 경로 접두사 /v3 를 outbound|9080|v3|reviews.default.svc.cluster.local 로 보내는 라우트를 더합니다(이 클러스터는 만들지 않습니다). 그리고 missing.yaml 에서 validate_clusters: false 줄만 뺀 사본 /root/ist2-name/missing-strict.yaml 도 만드세요. missing.yaml 로 띄운 뒤 curl localhost:10083/v3 를 한 번 보내고 /root/ist2-name/06-missing.txt 에 세 줄을 적으세요 — status=(HTTP 코드), no_cluster=(통계 http.outbound_0.0.0.0_9080.no_cluster 의 값), strict_rc=(missing-strict.yaml 을 envoy --mode validate 한 종료 코드).
VirtualService 가 DestinationRule 에 없는 서브셋을 가리키는 것은 Istio 에서 아주 흔한 실수입니다. istiod 는 라우트를 RDS 로 내려보내는데, 동적으로 받은 라우트는 가리키는 클러스터가 없어도 받아들여집니다(validate_clusters 기본값이 동적일 때 false). 그러면 요청 때 가서야 503 이 나고, 접근 로그에는 응답 플래그 NC (no cluster)가 찍힙니다. 정적 설정은 기본값이 true 라 같은 설정을 아예 거절합니다 — 두 모습을 나란히 보는 단계입니다.
서브셋은 같은 서비스 엔드포인트의 부분집합이다
떠 있는 Envoy 의 localhost:9983/clusters 에서 reviews 의 세 클러스터가 각각 엔드포인트를 몇 개 가졌는지 세어 /root/ist2-name/07-endpoints.txt 에 <클러스터 이름> <개수> 꼴로 세 줄 적으세요.
/clusters 는 엔드포인트마다 이름::주소::지표::값 줄을 여럿 찍습니다. 엔드포인트 하나당 한 번만 나오는 지표(예: cx_active)로 줄을 골라 클러스터 이름으로 세면 됩니다. 서브셋 없는 클러스터가 두 서브셋의 엔드포인트를 모두 갖는 것이 핵심입니다 — 서브셋은 새 서비스가 아니라 같은 엔드포인트 목록을 라벨로 나눈 것입니다. 그래서 라벨이 없는 파드는 어느 서브셋에도 들지 않고, 서브셋 없는 클러스터로만 갑니다.
이름을 읽는 법으로 정리한다
/root/ist2-name/08-report.md 에 default_cluster=, inbound_cluster=, v2_stat_name=, missing_subset_code= 네 줄을 적고(각각 서브셋 없는 나가는 쪽 클러스터 이름, 들어오는 쪽 클러스터 이름, 5단계에서 바꾼 v2 의 통계 이름, 6단계에서 받은 HTTP 코드), 그 아래 - 로 시작하는 설명을 네 줄 이상 적으세요.
앞 단계 파일에서 옮기세요. 설명 줄에는 proxy-config clusters 출력을 처음 보는 동료에게 이름 읽는 법을 알려 준다고 생각하고 쓰면 좋습니다.