ICA — 이스티오 인증 어소시에이트 · 게이트웨이와 인그레스 · 이론
Gateway 는 문을 열고, VirtualService 는 길을 낸다
한 줄 요약
Gateway 는 어떤 포트·호스트·TLS 로 트래픽을 받을 것인가만 정하고, 받은 뒤의 라우팅은 전부 VirtualService 가 합니다. 둘을 잇는 것은 VirtualService 의 gateways 필드 한 줄입니다.
왜 이게 필요했나
쿠버네티스의 Ingress 는 한 리소스에 진입점과 라우팅이 뒤섞여 있고 표현력이 부족했습니다. 헤더 기반 라우팅, 가중치 분배, TLS 통과 모드 같은 요구는 전부 컨트롤러별 애너테이션으로 흘러갔고, 결과적으로 매니페스트가 특정 인그레스 컨트롤러에 묶여 버렸습니다.
Istio 는 이 문제를 책임 분리로 풀었습니다. Gateway 는 게이트웨이 파드의 리스너를 선언하고, 라우팅은 메시 내부에서 쓰던 VirtualService 를 그대로 재사용합니다. 덕분에 "내부 east-west 라우팅"과 "외부에서 들어오는 north-south 라우팅"을 같은 문법으로 쓸 수 있게 됐습니다.
어떻게 동작하나
Gateway 는 spec.selector 로 어느 게이트웨이 파드에 이 설정을 붙일지 고릅니다. 보통 istio: ingressgateway 입니다. Gateway 리소스는 프록시를 만들지 않습니다. 이미 떠 있는 게이트웨이 Deployment 에 리스너 설정을 얹을 뿐입니다.
TLS 모드는 셋을 구분해야 합니다.
| 모드 | 게이트웨이가 하는 일 | 필요한 것 |
| --- | --- | --- |
| SIMPLE | TLS 를 종료하고 평문으로 뒤에 전달 | 서버 인증서(credentialName) |
| MUTUAL | TLS 종료 + 클라이언트 인증서 검증 | 서버 인증서 + CA |
| PASSTHROUGH | 종료하지 않고 SNI 만 보고 전달 | 인증서 불필요 |
PASSTHROUGH 는 프로토콜을 HTTPS 가 아니라 TLS 로 적어야 합니다. 게이트웨이가 HTTP 를 파싱하지 않기 때문이고, 그래서 이 경우 라우팅도 HTTP 규칙이 아니라 tls 블록의 sniHosts 로 합니다. credentialName 이 가리키는 kubernetes.io/tls 시크릿은 게이트웨이 파드가 떠 있는 네임스페이스에 있어야 합니다. 애플리케이션 네임스페이스에 두고 왜 안 붙느냐고 묻는 사고가 잦습니다.
바인딩은 두 조건이 모두 맞아야 성립합니다. VirtualService 의 gateways 에 Gateway 이름이 있어야 하고, hosts 가 Gateway 의 server hosts 와 겹쳐야 합니다. 메시 내부 트래픽에도 같은 규칙을 적용하려면 gateways 에 예약어 mesh 를 추가합니다.
ServiceEntry 는 반대 방향, 즉 메시 밖의 서비스를 안으로 데려오는 리소스입니다. 등록하고 나면 외부 API 에도 타임아웃·재시도·미러링·메트릭을 붙일 수 있습니다. resolution 은 STATIC(endpoints 에 적은 IP 사용), DNS(이름 조회), NONE(원래 요청 주소 사용)을 구분해 두면 됩니다. 메시 전역에서 outboundTrafficPolicy: REGISTRY_ONLY 를 켜면 ServiceEntry 에 없는 외부 호스트는 차단됩니다.
Sidecar 리소스는 성격이 다릅니다. 기본적으로 모든 사이드카는 메시의 모든 서비스 설정을 받습니다. 서비스가 수천 개가 되면 이 설정만으로 Envoy 메모리가 수백 MiB 로 부풀어 오릅니다. Sidecar 로 egress.hosts 를 좁히면 그 워크로드가 알아야 할 범위만 내려옵니다. 형식은 네임스페이스/호스트 이고, ./* 는 자기 네임스페이스, istio-system/* 는 컨트롤 플레인 네임스페이스입니다.
앞으로의 방향도 알아 두어야 합니다. 신규 인그레스는 Kubernetes Gateway API(Gateway + HTTPRoute)로 쓰는 것이 권장되고, 앰비언트 모드의 waypoint 프록시 자체가 Gateway API 의 Gateway 리소스로 선언됩니다. Istio 고유의 Gateway/VirtualService 는 계속 지원되지만 새 표준 기능은 Gateway API 쪽에 먼저 실립니다.
현장에서 만나는 모습
저자의 홈랩에서는 Cilium 의 Gateway API 구현을 올리다가 한 번 막혔습니다. Gateway API CRD 를 v1.2 로 설치했더니 컨트롤러가 기동을 거부했는데, 원인은 tlsroutes 와 referencegrants 가 아직 v1 이 아니었기 때문이었습니다. CRD 를 v1.6.1 로 올리고서야 붙었습니다.
교훈은 Istio 에도 그대로 적용됩니다. Gateway API 는 클러스터에 CRD 가 먼저 있어야 하는 별도 프로젝트이고, 구현체(Istio, Cilium)와 CRD 버전이 맞아야 합니다. "istioctl install 했는데 왜 HTTPRoute 를 못 만드냐"는 질문의 답이 이것입니다. 같은 홈랩에서 hubble-relay 와 hubble-ui 가 Pending 에 머물렀던 것도 비슷한 결의 문제였습니다. 이들은 DaemonSet 이 아니라 Deployment 라 컨트롤 플레인 taint 를 톨러레이트하지 않았고, 워커가 조인하자 바로 해소됐습니다. 게이트웨이 Deployment 역시 같은 이유로 스케줄되지 않는 일이 흔합니다.
다음 실습에서 할 것
백엔드 워크로드와 kubernetes.io/tls 시크릿을 실제로 만든 다음, SIMPLE 과 PASSTHROUGH 서버를 한 Gateway 에 담고, VirtualService 로 바인딩하고, 외부 결제 API 를 ServiceEntry 로 등록한 뒤, Sidecar 로 그 워크로드의 시야를 세 항목으로 좁힙니다.