何が何を担当するのか
한국어 원문으로 표시합니다.
한 줄 요약
VirtualService 는 "어디로 보낼지" 를, 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-status 가 STALE 이면 그 프록시는 옛 설정으로 돌고 있다. SYNCED 인데도
동작이 다르면 설정 자체가 의도와 다른 것이므로 routes 와 cluster 를 직접 읽는다.
VirtualService 는 붙는 자리가 있어야 한다. hosts 에 적은 이름이 실제
서비스와 다르거나, gateways 를 안 적어서 메시 안쪽에만 적용되는 경우가 많다.
게이트웨이로 들어오는 트래픽에 적용하려면 그 게이트웨이의 이름을 명시해야 하고,
다른 네임스페이스의 게이트웨이라면 네임스페이스/이름 으로 적는다.
DestinationRule 의 서브셋은 라벨이지 배포가 아니다. subset: v2 는 그
이름의 라벨을 가진 파드를 가리킬 뿐이다. 배포를 새로 만들면서 라벨을 안 붙이면
서브셋은 빈 목적지가 되고, 요청은 503 으로 떨어진다. proxy-config endpoint
로 실제 주소가 몇 개인지 확인하는 것이 가장 빠르다.
istioctl proxy-config endpoint deploy/frontend -n prod | grep api
적용 순서가 있다. 같은 호스트에 VirtualService 가 여럿이면 규칙이 합쳐지지 않고 먼저 만들어진 것이 이긴다. 팀마다 하나씩 만들다 보면 다른 팀의 규칙이 조용히 무시되는 상황이 생긴다. 호스트 하나에 리소스 하나를 원칙으로 두고, 경로별로 나눠야 한다면 한 리소스 안에서 나눈다.
mTLS 를 죄기 전에 무엇이 평문으로 오는지 본다. PeerAuthentication 을
STRICT 로 바꾸는 순간, 사이드카가 없는 워크로드와 쿠버네티스의 상태 검사 중
일부가 끊긴다. 먼저 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-status 가 STALE 이면 설정이 아직 안 갔다는 뜻이고, 그때 YAML 을 아무리 봐도 소용없다.