LabHub
배우기 러닝패스 코스

Istio深化 — なぜそう流れるのか

何が何を担当するのか

LabHub 에서 이어서 보기

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

한 줄 요약

VirtualService 는 "어디로 보낼지" 를, DestinationRule 은 "보낸 뒤 어떻게 다룰지" 를 정한다. 카나리 배포에 둘 다 필요한 이유가 이것이다.

概念マップ: VirtualService 는 "어디로 보낼지"・DestinationRule 은 "보낸 뒤 어떻게 다룰지"・DestinationRule 에서 정의・클러스터

왜 이게 필요했나

Istio 를 처음 쓰면 대부분 이 실수를 한다.

# VirtualService 만 쓴 카나리 — 동작하지 않는다
http:
  - route:
      - destination: { host: shop, subset: v1 }
        weight: 90
      - destination: { host: shop, subset: v2 }
        weight: 10

subset: v1 이 무엇을 가리키는지 아무도 모른다. 서브셋은 DestinationRule 에서 정의한다.

# DestinationRule — 서브셋의 정의
spec:
  host: shop
  subsets:
    - name: v1
      labels: { version: v1 }
    - name: v2
      labels: { version: v2 }

이제야 v1 이 version: v1 라벨이 붙은 파드를 뜻하게 된다. 앞 코스에서 본 Envoy 용어로 옮기면 — DestinationRule 의 subset 이 클러스터를 만들고(outbound|8080|v1|shop...), VirtualService 의 weight 가 라우트의 가중치가 된다.

네 리소스

리소스 하는 일 Envoy 로는
Gateway 메시 바깥에서 들어오는 트래픽의 입구(포트·호스트·TLS) Listener
VirtualService 어떤 요청을 어디로 보낼지(매칭·가중치·재시도·타임아웃) Route
DestinationRule 목적지를 어떻게 다룰지(서브셋·LB·커넥션풀·이상치·TLS) Cluster
ServiceEntry 메시가 모르는 외부 서비스를 목록에 등록 Cluster + Endpoint

Gateway 는 입구만 연다. Gateway 하나로는 트래픽이 흐르지 않는다 — 그 Gateway 를 gateways: 로 참조하는 VirtualService 가 있어야 비로소 라우팅이 생긴다. 이것도 흔한 함정이다.

mTLS 는 언제 걸리나

PeerAuthentication 이 mode 를 정한다.

mode
PERMISSIVE 평문도 mTLS 도 받는다 (기본값, 마이그레이션용)
STRICT mTLS 만 받는다
DISABLE mTLS 안 씀

기본이 PERMISSIVE 인 이유는 사이드카가 없는 파드가 남아 있을 수 있어서다. 그래서 "Istio 를 깔았으니 암호화된다" 는 말은 틀렸다. STRICT 로 바꾸기 전까지는 평문도 그대로 통한다.

STRICT 로 바꿀 때 흔히 깨지는 것: 사이드카가 없는 파드(예: Job), 헬스체크를 보내는 kubelet, 그리고 메시 밖의 모니터링. kubelet 은 Istio 가 프로브 경로를 우회시켜 처리하지만, 직접 만든 체크 스크립트는 깨진다.

설정이 실제로 프록시에 닿았는지 확인하기

이스티오에서 가장 흔한 상황은 YAML 은 적용되었는데 동작이 안 바뀌는 것이다. 컨트롤 플레인이 받아들인 것과 사이드카가 들고 있는 것이 다를 수 있으므로, 확인은 프록시 쪽에서 한다.

istioctl proxy-status                 # 각 프록시가 최신 설정과 동기인지
istioctl analyze -n prod              # 설정끼리의 모순을 정적으로 찾는다
istioctl proxy-config routes deploy/frontend -n prod
istioctl proxy-config cluster deploy/frontend -n prod --fqdn api.prod.svc.cluster.local

proxy-statusSTALE 이면 그 프록시는 옛 설정으로 돌고 있다. SYNCED 인데도 동작이 다르면 설정 자체가 의도와 다른 것이므로 routescluster 를 직접 읽는다.

VirtualService 는 붙는 자리가 있어야 한다. hosts 에 적은 이름이 실제 서비스와 다르거나, gateways 를 안 적어서 메시 안쪽에만 적용되는 경우가 많다. 게이트웨이로 들어오는 트래픽에 적용하려면 그 게이트웨이의 이름을 명시해야 하고, 다른 네임스페이스의 게이트웨이라면 네임스페이스/이름 으로 적는다.

DestinationRule 의 서브셋은 라벨이지 배포가 아니다. subset: v2 는 그 이름의 라벨을 가진 파드를 가리킬 뿐이다. 배포를 새로 만들면서 라벨을 안 붙이면 서브셋은 빈 목적지가 되고, 요청은 503 으로 떨어진다. proxy-config endpoint 로 실제 주소가 몇 개인지 확인하는 것이 가장 빠르다.

istioctl proxy-config endpoint deploy/frontend -n prod | grep api

적용 순서가 있다. 같은 호스트에 VirtualService 가 여럿이면 규칙이 합쳐지지 않고 먼저 만들어진 것이 이긴다. 팀마다 하나씩 만들다 보면 다른 팀의 규칙이 조용히 무시되는 상황이 생긴다. 호스트 하나에 리소스 하나를 원칙으로 두고, 경로별로 나눠야 한다면 한 리소스 안에서 나눈다.

mTLS 를 죄기 전에 무엇이 평문으로 오는지 본다. PeerAuthenticationSTRICT 로 바꾸는 순간, 사이드카가 없는 워크로드와 쿠버네티스의 상태 검사 중 일부가 끊긴다. 먼저 PERMISSIVE 로 두고 텔레메트리에서 평문 비율이 0이 되는 것을 확인한 다음에 죈다.

흔한 착각

"Istio 를 넣으면 관측성이 생긴다" — 사이드카가 내는 지표는 L7 요청 지표(요청 수·지연·상태코드)다. 애플리케이션 안에서 무슨 일이 있었는지는 여전히 모른다. 트레이스도 마찬가지로, 사이드카는 스팬을 만들지만 애플리케이션이 헤더를 이어 주지 않으면 체인이 끊긴다. 코드를 안 고쳐도 되는 것은 아니다.

실무에서 진짜 중요한 것

설정이 의도대로 갔는지는 프록시에게 묻는다.

istioctl analyze                     # 정적 검사 — 서브셋 미정의 같은 것을 잡는다
istioctl proxy-status                # 각 사이드카가 최신 설정을 받았나(SYNCED)
istioctl proxy-config route <pod>    # 실제로 받은 라우트
istioctl proxy-config cluster <pod> --fqdn shop.default.svc.cluster.local

proxy-statusSTALE 이면 설정이 아직 안 갔다는 뜻이고, 그때 YAML 을 아무리 봐도 소용없다.