LabHub
배우기 러닝패스 코스

Istio Deep Dive — Why It Flows That Way

Turn Subsets into Clusters and Trace Them by Name

LabHub 에서 이어서 보기

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

목표

DestinationRule 에서 클러스터 이름을 규칙으로 도출하고, 그 이름 그대로 Envoy 를 구성해 서브셋별 라우팅·통계 이름·없는 서브셋의 503 을 직접 확인한다.

왜 중요한가

Istio 장애 조사의 절반은 proxy-config clusters 와 통계를 읽는 일이다. 클러스터 이름은 규칙으로 만들어지므로 규칙을 알면 이름만 보고 서비스·포트·서브셋을 알아볼 수 있고, '서브셋이 없다', '엔드포인트가 비었다', '통계 이름이 바뀌었다' 를 몇 초 만에 가를 수 있다.

단계

  1. /root/ist2-name/dr.yaml 에 DestinationRule 을 쓰세요 — 이름 reviews, 네임스페이스 default, hostreviews.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).
  2. 서비스 reviews 는 포트 9080 을 씁니다. /root/ist2-name/dr.yaml 로 사이드카들이 갖게 될 클러스터 이름 네 개를 /root/ist2-name/02-names.txt 에 한 줄에 하나씩 적으세요 — 다른 파드가 reviews 로 나갈 때 쓰는 것 셋(서브셋 없는 것 하나와 서브셋마다 하나), 그리고 reviews 파드 자신이 들어오는 요청을 앱으로 넘길 때 쓰는 것 하나.
  3. /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:8103127.0.0.1:8104 둘), outbound|9080|v1|reviews.default.svc.cluster.local(8103 만), outbound|9080|v2|reviews.default.svc.cluster.local(8104 만). 업스트림 둘을 8103·8104ok 로 띄우고 Envoy 를 띄운 뒤, curl localhost:10083/ 결과를 /root/ist2-name/03-v1.txtstatus=body= 두 줄로 적으세요.
  4. /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.txtv1=, v2=, total= 세 줄로 적으세요.
  5. /root/ist2-name/split.yamloutbound|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 줄(이제 바뀐 이름으로 나옵니다).
  6. /root/ist2-name/split.yaml/root/ist2-name/missing.yaml 로 복사하고 두 가지를 바꾸세요 — route_configvalidate_clusters: false 를 더하고, 기존 라우트 앞에 경로 접두사 /v3outbound|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.yamlenvoy --mode validate 한 종료 코드).
  7. 떠 있는 Envoy 의 localhost:9983/clusters 에서 reviews 의 세 클러스터가 각각 엔드포인트를 몇 개 가졌는지 세어 /root/ist2-name/07-endpoints.txt<클러스터 이름> <개수> 꼴로 세 줄 적으세요.
  8. /root/ist2-name/08-report.mddefault_cluster=, inbound_cluster=, v2_stat_name=, missing_subset_code= 네 줄을 적고(각각 서브셋 없는 나가는 쪽 클러스터 이름, 들어오는 쪽 클러스터 이름, 5단계에서 바꾼 v2 의 통계 이름, 6단계에서 받은 HTTP 코드), 그 아래 - 로 시작하는 설명을 네 줄 이상 적으세요.

참고

서브셋 둘을 가진 DestinationRule 을 쓴다

/root/ist2-name/dr.yaml 에 DestinationRule 을 쓰세요 — 이름 reviews, 네임스페이스 default, hostreviews.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:8103127.0.0.1:8104 둘), outbound|9080|v1|reviews.default.svc.cluster.local(8103 만), outbound|9080|v2|reviews.default.svc.cluster.local(8104 만). 업스트림 둘을 8103·8104ok 로 띄우고 Envoy 를 띄운 뒤, curl localhost:10083/ 결과를 /root/ist2-name/03-v1.txtstatus=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.txtv1=, v2=, total= 세 줄로 적으세요.

VirtualService 의 route[].weight 는 Envoy 의 weighted_clusters 가 됩니다. 가중치는 요청마다 주사위를 굴리는 것이라 마흔 번에 정확히 30 대 10 이 나오지는 않습니다 — 숫자가 조금 어긋나도 정상입니다. --concurrency 1 은 워커를 하나로 묶어 실험을 흔들림 없게 합니다. 본문의 포트(ok:8103 인지 ok:8104 인지)로 서브셋을 가르면 됩니다.

통계 이름은 클러스터 이름이다 — alt_stat_name 으로 바꾼다

/root/ist2-name/split.yamloutbound|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_configvalidate_clusters: false 를 더하고, 기존 라우트 앞에 경로 접두사 /v3outbound|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.yamlenvoy --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.mddefault_cluster=, inbound_cluster=, v2_stat_name=, missing_subset_code= 네 줄을 적고(각각 서브셋 없는 나가는 쪽 클러스터 이름, 들어오는 쪽 클러스터 이름, 5단계에서 바꾼 v2 의 통계 이름, 6단계에서 받은 HTTP 코드), 그 아래 - 로 시작하는 설명을 네 줄 이상 적으세요.

앞 단계 파일에서 옮기세요. 설명 줄에는 proxy-config clusters 출력을 처음 보는 동료에게 이름 읽는 법을 알려 준다고 생각하고 쓰면 좋습니다.