Istio Traffic Management Reference

VirtualService ↔ DestinationRule
매핑 구조와 디버깅 플레이북

VS·DR·subset의 역할 분담, spec.hosts의 실제 매칭 대상, 두 리소스를 연결하는 매핑 키, istiod → Envoy xDS 변환 경로, 설정이 꼬였을 때의 계층별 진단 절차를 정리함.

00 / SUMMARY

핵심 요약

  • 발동 조건 VS spec.hosts = 요청의 목적지 이름과 매칭 (HTTP는 :authority 헤더, TLS는 SNI, TCP는 Service VIP). DR과는 무관함.
  • 매핑 키 ① VS route.destination.host ⟷ DR spec.host — FQDN 정규화 후 문자열 비교임.
  • 매핑 키 ② VS destination.subset ⟷ DR subsets[].name — subset labels가 Pod label과 일치해야 endpoint가 채워짐.
  • 진단 축 503 response flag로 원인 계층 구분: NC=cluster 부재(DR/host 문제), UH=endpoint 부재(label/Pod 문제), NR=route 부재(VS/hosts 문제).
01 / RESOURCES

리소스 역할 분담

Istio는 트래픽 제어를 라우팅 결정목적지 정책으로 분리함. 변경 주기·소유자가 다른 관심사를 리소스 단위로 나눈 설계임.

리소스책임답하는 질문Envoy 대응
VirtualServiceL7 라우팅 규칙 (match / rewrite / weight / retry / timeout / fault)"이 요청을 어디로 보낼까"Route (RDS)
DestinationRule목적지 정책 (LB, connection pool, outlier detection, mTLS 모드) + subset 정의"그 목적지로 가는 트래픽을 어떻게 다룰까"Cluster (CDS)
subset같은 Service 뒤 Pod들을 label로 나눈 논리적 버전 그룹"목적지 안에서 어느 그룹인가"별도 Cluster + endpoint 필터 (EDS)
Service / ServiceEntryservice registry 등록 — VS·DR이 참조 가능한 이름의 원천"mesh가 아는 이름인가"Cluster·Endpoint의 기반
Gatewayedge에서 수신할 port·protocol·host 선언"외부 트래픽을 어디서 받을까"Listener (LDS)

subset은 라우팅 대상 그룹의 "정의"만 담당하고, 그 그룹을 "선택"하는 것은 VS의 몫임. 정의(DR)와 선택(VS)이 분리되어 있어 이름 참조로만 연결됨 — 이 참조가 끊기는 것이 대부분의 장애 원인임.

02 / SPEC.HOSTS

spec.hosts는 무엇과 매칭되는가

spec.hosts"요청이 향하는 목적지 이름"과 매칭되어 이 VS의 발동 여부를 결정함. DR의 host와 비교되는 필드가 아님. 매칭은 두 단계로 일어남.

단계 1 — 컴파일 타임 (istiod)

istiod가 hosts:를 보고 이 VS의 규칙을 어느 Envoy virtualHost에 부착할지 결정함. sidecar(mesh) 트래픽의 경우 host는 service registry에 등록된 이름(K8s Service 또는 ServiceEntry)이어야 함. registry에 없는 이름을 쓰면 규칙이 어디에도 부착되지 않고 조용히 무시됨 — 에러가 나지 않아 발견이 늦어지는 유형임.

단계 2 — 런타임 (Envoy)

프로토콜에 따라 매칭 재료가 다름. L7 정보가 있는 프로토콜만 이름 기반 매칭이 가능함.

프로토콜매칭 재료비고
HTTP/1.1, HTTP/2, gRPC:authority (Host) 헤더virtualHost domains에 FQDN·short name·Service VIP 등 변형이 모두 등록되어 어느 형태로 불러도 매칭됨
TLS (passthrough)SNItls: 라우트 블록 사용 시
Plain TCP목적지 IP (Service VIP)L7 헤더가 없어 이름 매칭 불가 — Service VIP 기준 listener 매칭임

부착 위치에 따른 차이

gateways 필드적용 범위hosts 매칭 대상
미지정 또는 mesh모든 sidecar의 outboundmesh 내부 요청의 목적지 이름 (service registry 등록 필수)
[my-gateway]해당 ingress gatewayGateway servers[].hosts와의 교집합 + 외부 인입 요청의 Host/SNI. 외부 도메인(api.example.com) 사용 가능
[mesh, my-gateway]둘 다각각 위 규칙 적용
정리spec.hosts = "요청의 목적지 이름과 매칭해 이 VS를 발동시킬지", route.destination.host = "발동 후 실제로 보낼 곳(= DR 매칭 키)". 단순 케이스에선 둘이 같지만, hosts: [reviews]로 받아 destination.host: reviews-canary로 보내는 식으로 다를 수 있음.
03 / MAPPING KEYS

매핑 키 — 무엇이 무엇과 연결되는가

VS와 DR을 잇는 키는 정확히 두 개임. 그 외 필드는 매핑에 관여하지 않음.

Client request :authority = reviews.default.svc.cluster.local ① VS 발동 여부 결정 (spec.hosts 매칭) VirtualService spec.hosts: [reviews.default...] ← 요청 매칭용 http.route[0].destination: host: reviews.default.svc... subset: v2 weight: 10 DestinationRule spec.host: reviews.default.svc... subsets: - name: v2 labels: { version: v2 } trafficPolicy: { ... } KEY ① host (FQDN 정규화) KEY ② subset name ② istiod가 subset마다 Envoy cluster 생성 (CDS) Envoy cluster: outbound|9080|v2|reviews.default.svc.cluster.local ③ subset labels로 Service endpoint 필터 (EDS) Pods (version: v2) reviews-v2-abc 10.4.1.8 reviews-v2-def 10.4.2.3 Pods (version: v1) reviews-v1-xyz 10.4.0.5 ← v2 cluster에서 제외됨 K8s Service (registry) reviews ClusterIP :9080 spec.hosts·host가 참조 가능한 이름의 원천
fig 1. 요청 → VS 발동 → 매핑 키 2개 → Envoy cluster → label 필터된 endpoint
KEY ① destination.host ⟷ DR.hostKEY ② destination.subset ⟷ subsets[].name

FQDN 정규화 규칙

host: reviews처럼 short name을 쓰면 그 리소스가 정의된 namespace 기준으로 reviews.<ns>.svc.cluster.local로 확장됨. 호출자 namespace 기준이 아님. VS와 DR이 서로 다른 namespace에 있으면 같은 short name이 다른 FQDN으로 확장되어 매핑이 조용히 끊어짐. 운영 환경에서는 FQDN 명시가 원칙임.

04 / XDS PIPELINE

istiod → Envoy 변환 경로

디버깅 시 "어느 계층에서 끊겼는지"를 판단하려면 각 리소스가 어떤 xDS로 변환되는지 알아야 함. istioctl proxy-config의 서브커맨드가 이 계층과 1:1 대응임.

Istio API (istiod가 병합·검증) Gatewayedge port/host 선언 VirtualServicematch / route / weight DestinationRulesubset / policy Service/Endpointregistry + Pod IP Envoy xDS ↔ istioctl proxy-config LDS Listener 수신 port·protocol $ pc listener RDS Route virtualHost.domains ← hosts $ pc route CDS Cluster outbound|port|subset|fqdn $ pc cluster EDS Endpoint label 필터된 Pod IP $ pc endpoint pc = istioctl proxy-config · 트래픽 처리 순서도 Listener → Route → Cluster → Endpoint 순임
fig 2. Istio API → xDS 매핑. 디버깅은 이 순서를 따라 내려가며 끊긴 계층을 찾는 작업임
05 / EXAMPLE

완전한 예제 — v1/v2 가중치 분배

# DestinationRule — subset 정의 + 목적지 정책
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
  namespace: default
spec:
  host: reviews.default.svc.cluster.local   # KEY ①
  trafficPolicy:
    loadBalancer:
      simple: LEAST_REQUEST
  subsets:
  - name: v1                                # KEY ②
    labels:
      version: v1                            # Pod label과 일치 필요
  - name: v2
    labels:
      version: v2
---
# VirtualService — 라우팅 규칙
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
  namespace: default
spec:
  hosts:
  - reviews.default.svc.cluster.local        # 요청 매칭용 (DR과 무관)
  http:
  - route:
    - destination:
        host: reviews.default.svc.cluster.local  # KEY ① → DR.host
        subset: v1                                # KEY ② → subsets[].name
      weight: 90
    - destination:
        host: reviews.default.svc.cluster.local
        subset: v2
      weight: 10

검증 커맨드는 06 디버깅 플레이북의 각 단계에 포함함. 정상 상태 기준의 예상 출력도 함께 표기함.

06 / DEBUG PLAYBOOK

디버깅 플레이북 — 설정이 꼬였을 때

원칙: 정적 검증 → 동기화 확인 → xDS 계층 순회(Route → Cluster → Endpoint) → 런타임 관측 순으로 내려감. 각 단계는 "여기까지는 정상"을 확정하고 다음 계층으로 넘어가는 이분 탐색임.

1

정적 검증 — istioctl analyze

리소스 간 참조 무결성을 배포 전/후 검사함. subset 참조 오류, Gateway-VS 불일치, 미등록 host 등 대부분의 설정 오류를 클러스터에 트래픽을 흘리기 전에 잡아냄.

istioctl analyze -n default          # 또는 --all-namespaces
# 대표 경고:
#  IST0101 referenced DestinationRule subset not found → subset 이름 오타/DR 누락
#  IST0132 host not found in registry → hosts에 미등록 이름
2

동기화 확인 — istioctl proxy-status

istiod가 만든 설정이 각 sidecar에 실제 전파됐는지 확인함. STALE이면 이후 단계를 봐도 의미 없음 — istiod 로그와 리소스 상태부터 확인 필요.

istioctl proxy-status
# 모든 컬럼(CDS/LDS/EDS/RDS)이 SYNCED 여야 함. STALE → istiod 쪽 문제
3

대상 요약 — istioctl x describe

특정 Pod에 어떤 VS·DR이 적용되는지, mTLS 상태, 경고를 한 번에 요약함. "이 Pod에 내 설정이 붙긴 했나"를 가장 빨리 확인하는 방법임.

istioctl experimental describe pod reviews-v2-abc -n default
4

Route 계층 — VS가 라우트로 변환됐는가

호출자 Pod 기준으로 RDS를 조회함. virtualHost domains에 대상 host가 있고, 내 route 규칙(weight 등)이 원하는 cluster 이름을 가리키는지 확인함.

istioctl proxy-config route deploy/productpage -n default --name 9080 -o json \
  | jq '.[0].virtualHosts[] | select(.name | startswith("reviews"))'
# 기대: weightedClusters에 outbound|9080|v1|... =90, |v2|... =10
# 규칙이 안 보임 → VS hosts가 registry 미등록이거나 exportTo로 가려짐
5

Cluster 계층 — DR·subset이 cluster로 변환됐는가

istioctl proxy-config cluster deploy/productpage -n default \
  --fqdn reviews.default.svc.cluster.local
# 기대: subset 컬럼에 v1, v2 행이 각각 존재
# subset 행 없음 → DR 미적용 (host FQDN 불일치, exportTo, namespace 확인)
6

Endpoint 계층 — label 필터 결과가 비어있지 않은가

istioctl proxy-config endpoint deploy/productpage -n default \
  --cluster "outbound|9080|v2|reviews.default.svc.cluster.local"
# 기대: version=v2 Pod IP들이 HEALTHY
# 0개 → subset labels와 Pod label 불일치. 아래로 교차 확인:
kubectl get pods -n default -l app=reviews --show-labels
kubectl get endpointslices -n default -l kubernetes.io/service-name=reviews
7

런타임 관측 — access log response flag

실제 요청이 어느 계층에서 실패하는지는 호출자 sidecar의 access log flag가 알려줌. flag → 계층 매핑이 진단의 핵심임 (아래 표 참조).

kubectl logs deploy/productpage -n default -c istio-proxy --tail=100 | grep -E ' 50[03] '
# "... 503 NC ..." → cluster 부재   "... 503 UH ..." → endpoint 부재
8

최후 수단 — config dump / Envoy 로그 레벨

# Envoy 전체 설정 스냅샷 (istioctl 출력의 원본)
kubectl exec deploy/productpage -n default -c istio-proxy -- \
  curl -s localhost:15000/config_dump > dump.json
# 라우팅 판단 과정을 로그로 직접 관찰
istioctl proxy-config log deploy/productpage -n default --level router:debug,upstream:debug

Response flag 색인

표는 색인이며, 각 flag의 진단 방향은 아래 해설 참조.

Flag의미의심 계층1차 확인
NRNoRoute — 매칭되는 route 없음VS / hostspc route, VS hosts 철자·registry 등록
NCNoCluster — route가 가리키는 cluster 없음DR / host·subsetpc cluster, DR host FQDN·exportTo
UHNoHealthyUpstream — cluster는 있으나 endpoint 0개subset labels / Podpc endpoint, Pod label·readiness
UFUpstreamConnectionFailure — 연결 실패mTLS / NetworkPolicy / 포트DR tls 모드 ↔ PeerAuthentication 정합, Calico policy
UOUpstreamOverflow — circuit breaker 발동DR connectionPoolpc cluster -o json의 thresholds, :15000/statsupstream_rq_pending_overflow
URX재시도 한도 초과VS retries / upstream 불안정upstream 5xx 원인 추적
DCDownstreamConnectionTermination — 클라이언트가 끊음클라이언트 timeout호출자 timeout vs VS timeout 비교

증상 → 진입점 매핑

증상진입 단계전형적 원인
배포 직후 전면 5031 → 7 (flag 확인)subset 오타(NC), DR host 불일치(NC)
특정 namespace에서만 5034, 5VS/DR exportTo 제한, short name의 namespace 확장 차이
가중치가 반영 안 됨4다른 VS가 같은 host 선점(host당 sidecar 기준 VS 규칙 충돌), match 순서
일부 요청만 간헐 5036, 7일부 Pod not-ready(UH 간헐), outlier detection ejection, rollout 중 label 전환
설정 바꿨는데 반영 안 됨2proxy STALE, istiod 재시작 필요 상태, webhook 오류로 리소스 미반영
mTLS 관련 연결 실패7 (UF)DR tls 모드 ↔ PeerAuthentication 불일치
07 / FAILURE SCENARIOS

실패 시나리오 — 어떻게 관측되는가

시나리오 A — subset 참조 대상 DR 부재 503 NC

VS가 subset: v2를 참조하는데 DR이 없거나 host FQDN이 불일치하는 경우. cluster outbound|9080|v2|... 자체가 생성되지 않아 route가 존재하지 않는 cluster 이름을 가리킴. istioctl analyze의 IST0101로 사전 탐지 가능함.

시나리오 B — subset labels와 일치하는 Pod 없음 503 UH

DR은 정상 적용됐으나 version: v2 label을 가진 Pod가 0개(오타, rollout 중 label 변경, 전부 not-ready). cluster는 존재하지만 EDS 결과가 빈 목록임. 정적 검증으로는 안 잡히고 런타임에만 드러남 — pc endpoint가 유일한 확정 수단임.

시나리오 C — short name의 namespace 확장 차이 조용한 미적용

VS는 team-a, DR은 team-b에 있고 둘 다 host: reviews로 작성한 경우. 각각 reviews.team-a..., reviews.team-b...로 확장되어 KEY ①이 불일치함. 에러 없이 DR 정책만 미적용되는 형태라 발견이 늦음. subset까지 참조했다면 NC로 표면화되지만, trafficPolicy만 있는 DR이면 증상 없이 정책만 사라짐.

시나리오 D — exportTo로 가려진 리소스 호출자 위치 의존 503

DR에 exportTo: ["."]가 걸려 있으면 다른 namespace의 sidecar에는 subset cluster가 생성되지 않음. "같은 namespace에서는 되는데 다른 namespace에서 호출하면 NC"라는 위치 의존적 증상이 시그니처임. 호출자 Pod 기준으로 pc cluster를 조회해야 보이는 문제이므로, 반드시 실패하는 쪽 Pod를 기준으로 proxy-config를 확인해야 함.

공통 원칙 — proxy-config 조회는 항상 호출자(client) Pod 기준으로 수행함. 라우팅 결정은 호출자 sidecar의 outbound에서 일어나며, exportTo·Sidecar 리소스에 의해 Pod마다 보이는 설정이 다를 수 있음.