TT Lab
시작하기
배우기 러닝패스 코스

ICA — 이스티오 인증 어소시에이트

istiod 는 왜 하나로 합쳐졌나

TT Lab 에서 이어서 보기

한 줄 요약

Istio 는 "설정을 만드는 쪽(istiod)"과 "패킷을 만지는 쪽(Envoy)"을 완전히 분리했습니다. 이 분리 덕분에 컨트롤 플레인이 죽어도 트래픽은 흐르고, 반대로 컨트롤 플레인만 고쳐도 전체 메시의 행동이 바뀝니다.

왜 이게 필요했나

Istio 1.5 이전에는 Pilot(트래픽), Citadel(인증서), Galley(설정 검증), Mixer(정책·텔레메트리)가 각각 별도 파드로 떠 있었습니다. 문제는 이 넷이 서로를 호출하면서 생기는 운영 비용이었습니다. 구성요소 하나가 죽으면 어느 기능이 멈추는지 파악하기 어려웠고, 특히 Mixer 는 요청마다 컨트롤 플레인을 호출하는 구조라 데이터 경로의 지연과 장애가 컨트롤 플레인에 직결됐습니다.

그래서 1.5 에서 Pilot·Citadel·Galley 가 istiod 라는 단일 바이너리로 합쳐졌고, Mixer 는 1.8 에서 아예 제거됐습니다. 텔레메트리는 Envoy 안의 필터가 직접 생성하는 방식으로 바뀌었습니다. 요점은 "컴포넌트를 줄였다"가 아니라 데이터 경로에서 컨트롤 플레인 호출을 완전히 걷어냈다는 것입니다.

데이터 경로가 컨트롤 플레인을 부르던 때와 걷어낸 뒤

본문의 역사 설명이다. 1.5 이전과 이후를 데이터 경로의 관점에서 견준다. 버전 번호는 본문의 서술을 그대로 옮겼다.

  • 1.5 이전: 구성요소 넷이 따로 떠 있었다Pilot, Citadel, Galley, Mixer 가 각각 별도 파드였고 서로를 호출하는 운영 비용이 컸다. 하나가 죽으면 어느 기능이 멈추는지 파악하기 어려웠다. 특히 Mixer 는 요청마다 컨트롤 플레인을 호출해서 데이터 경로의 지연과 장애가 컨트롤 플레인에 직결됐다.
  • 이후: istiod 하나와 Envoy 안의 텔레메트리1.5 에서 Pilot, Citadel, Galley 가 istiod 라는 단일 바이너리로 합쳐졌고 Mixer 는 1.8 에서 제거됐다. 텔레메트리는 Envoy 안의 필터가 직접 만든다.

여기서 구분할 것 요점은 컴포넌트를 줄였다는 것이 아니라 데이터 경로에서 컨트롤 플레인 호출을 완전히 걷어냈다는 것이다.

잠깐, 예측해 보세요 istiod 로 합친 이득을 파드 개수가 줄어든 것뿐이라고 정리한 동료가 있다. 무엇을 덧붙여야 할까?

설명 확인 · 채점 없는 자가 점검

요청마다 컨트롤 플레인을 부르던 Mixer 식 호출을 데이터 경로에서 없앴다는 점이다. 그래서 설정을 만드는 쪽과 패킷을 만지는 쪽이 분리되고, 컨트롤 플레인이 멈춰도 트래픽은 흐른다.

근거 문서

어떻게 동작하나

istiod 는 쿠버네티스 API 를 감시해 Service·Endpoint·Pod 와 Istio CRD 의 변화를 읽고, 그것을 Envoy 가 이해하는 설정으로 번역해 gRPC 스트림으로 밀어 넣습니다. 이 프로토콜이 xDS 입니다.

API 무엇을 내려보내나
LDS 리스너 — 어떤 포트를 어떤 프로토콜로 듣는가
RDS 라우트 — 어떤 요청을 어떤 클러스터로 보내는가
CDS 클러스터 — 목적지 그룹의 정의(LB, 서킷브레이커, TLS)
EDS 엔드포인트 — 그 클러스터에 실제로 들어 있는 파드 IP
SDS 인증서와 키

Istio 는 이 다섯을 ADS(Aggregated Discovery Service) 라는 하나의 gRPC 스트림으로 묶어 보냅니다. 이유는 대역폭이 아니라 순서입니다. 클러스터(CDS)가 정의되기 전에 엔드포인트(EDS)가 도착하면 Envoy 는 갈 곳 없는 주소를 받게 되고, 라우트(RDS)가 리스너(LDS)보다 먼저 오면 붙일 곳이 없습니다. 스트림이 하나면 순서가 보장되고, 설정이 원자적으로 갈아 끼워집니다.

Envoy 안에서 목적지는 이런 이름으로 존재합니다.

outbound|9080|v2|reviews.default.svc.cluster.local
방향     포트 subset  FQDN

istioctl proxy-config cluster 에서 이 문자열을 읽을 줄 알면 절반은 끝난 것입니다. subset 자리가 비어 있으면 DestinationRule 이 없다는 뜻이고, 이름이 아예 없으면 그 서비스가 이 프록시의 시야 밖이라는 뜻입니다.

파드 안에서는 istio-init 컨테이너가 iptables 규칙을 심어 트래픽을 프록시로 꺾습니다. 인바운드는 15006, 아웃바운드는 15001 로 갑니다. 이때 UID 1337 의 트래픽만은 리다이렉트에서 제외되는데, 그 UID 가 바로 istio-proxy 자신이기 때문입니다. 제외하지 않으면 프록시가 내보낸 패킷이 다시 프록시로 돌아와 무한 루프가 됩니다. 그 밖에 15008(HBONE 터널), 15020(에이전트 통합 헬스·메트릭), 15021(헬스 체크), 15090(프로메테우스 메트릭)을 외워 두면 시험에서 포트 문제를 놓치지 않습니다.

마지막으로 중요한 성질 하나. istiod 가 전부 죽어도 이미 떠 있는 Envoy 는 마지막으로 받은 설정으로 계속 트래픽을 처리합니다. 멈추는 것은 새 설정 전파와 인증서 갱신이지 데이터 경로가 아닙니다. 그래서 istiod 장애는 "즉시 전면 장애"가 아니라 "시한부 상태"이고, 인증서 수명(기본 24시간)이 실질적인 타이머가 됩니다.

현장에서 만나는 모습

저자의 홈랩은 7노드(cp-1/2/3 + gpu-a/b/c/d), 쿠버네티스 v1.34.10, containerd 1.7.27, 커널 6.14 위에 Cilium 1.20.1 로 서 있습니다. 사이드카 메시는 올라가 있지 않은데, 이 대비가 오히려 Istio 를 이해하는 데 도움이 됩니다.

이 클러스터는 kubeadm init --skip-phases=addon/kube-proxy 로 kube-proxy 를 처음부터 설치하지 않고 세웠습니다. 한 번이라도 돈 kube-proxy 는 노드에 KUBE-SERVICES / KUBE-SVC-* / KUBE-SEP-* 체인을 새겨 놓고, DaemonSet 을 지워도 그 규칙은 남아 eBPF 데이터패스와 충돌합니다. 실측 결과 kube-proxy 파드 0개, iptables KUBE- 체인 0개였습니다.

여기서 배울 점은 Istio 에도 똑같이 적용됩니다. 사이드카 주입은 파드 네트워크 네임스페이스 안에 iptables 규칙을 새기는 일이고, 주입 라벨을 나중에 지워도 이미 뜬 파드의 규칙은 파드를 재시작하기 전까지 그대로 남습니다. "라벨은 지웠는데 왜 아직 프록시를 타지?"라는 질문의 답이 이것입니다. 설정은 선언적이지만 노드와 파드에 남는 흔적은 명령적입니다.

istiod 가 전부 죽었을 때 멈추는 것과 계속되는 것

본문이 컨트롤 플레인과 데이터 경로의 분리가 만드는 성질로 꼽은 대목이다.

  • 멈추는 것새 설정 전파와 인증서 갱신이 멈춘다.
  • 계속되는 것이미 떠 있는 Envoy 는 마지막으로 받은 설정으로 계속 트래픽을 처리한다. 데이터 경로는 멈추지 않는다.

여기서 구분할 것 이 장애는 즉시 전면 장애가 아니라 시한부 상태이다. 본문은 인증서 수명(기본 24 시간)이 실질적인 타이머가 된다고 설명한다.

잠깐, 예측해 보세요 새벽에 istiod 가 죽었는데 서비스 호출은 계속 성공한다. 아침까지 그대로 두어도 괜찮을까?

설명 확인 · 채점 없는 자가 점검

기한이 있다. 호출이 성공하는 것은 Envoy 가 마지막 설정으로 일하기 때문이고, 새 설정 전파와 인증서 갱신은 멈춰 있다. 본문 기준으로 인증서 수명(기본 24 시간)이 지나기 전에 복구해야 한다.

근거 문서

다음 퀴즈에서 확인할 것

이 모듈은 개념만 다룹니다. 퀴즈로 아키텍처 감각을 점검한 뒤, 다음 모듈에서 VirtualService 와 DestinationRule 을 직접 써서 위에서 본 outbound|포트|subset|FQDN 이 어떻게 만들어지는지 손으로 확인합니다.