- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- Istio 아키텍처 개요
- istiod: 통합된 컨트롤 플레인
- Envoy 사이드카 주입 메커니즘
- xDS 프로토콜 상세
- Envoy 필터 체인 아키텍처
- 워크로드 아이덴티티: SPIFFE
- 구성 변환: Istio CRD에서 Envoy 구성으로
- 구성 동기화 및 디버깅
- 성능 고려사항
- 마무리
들어가며
Istio는 Kubernetes 환경에서 가장 널리 사용되는 서비스 메시입니다. 하지만 "VirtualService를 만들면 트래픽이 라우팅된다"는 수준을 넘어, 내부에서 실제로 어떤 일이 일어나는지 이해하는 것은 운영과 트러블슈팅에 큰 차이를 만듭니다.
이 글에서는 Istio의 컨트롤 플레인과 데이터 플레인이 어떻게 상호작용하고, 사용자가 정의한 CRD가 어떻게 Envoy 구성으로 변환되는지 내부 메커니즘을 분석합니다.
Istio 아키텍처 개요
Istio는 크게 두 부분으로 구성됩니다:
┌─────────────────────────────────────────────────┐
│ Control Plane │
│ ┌───────────────────────────────────────────┐ │
│ │ istiod │ │
│ │ ┌─────────┐ ┌─────────┐ ┌──────────┐ │ │
│ │ │ Pilot │ │ Citadel │ │ Galley │ │ │
│ │ │ (xDS) │ │ (CA) │ │(Validate)│ │ │
│ │ └─────────┘ └─────────┘ └──────────┘ │ │
│ └───────────────────────────────────────────┘ │
├─────────────────────────────────────────────────┤
│ Data Plane │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ App + EP │ │ App + EP │ │ App + EP │ │
│ │ (Pod A) │ │ (Pod B) │ │ (Pod C) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ EP = Envoy Proxy (istio-proxy sidecar) │
└─────────────────────────────────────────────────┘
istiod: 통합된 컨트롤 플레인
역사적 배경
Istio 1.5 이전에는 Pilot, Citadel, Galley, Mixer가 각각 별도의 마이크로서비스로 배포되었습니다. Istio 1.5부터 이들이 istiod라는 단일 바이너리로 통합되었고, Mixer는 1.8에서 완전히 제거되었습니다.
Pilot: 트래픽 관리 엔진
Pilot은 istiod의 핵심으로, 다음 역할을 수행합니다:
- 서비스 디스커버리: Kubernetes API 서버를 감시하여 Service, Endpoint, Pod 변경을 추적
- 구성 변환: Istio CRD(VirtualService, DestinationRule 등)를 Envoy 구성으로 변환
- xDS 서버: 변환된 구성을 gRPC 스트림으로 각 Envoy 프록시에 푸시
Kubernetes API Server
│
▼
┌─────────┐
│ Pilot │ ← Istio CRD 감시 (VirtualService, DestinationRule, Gateway...)
│ │ ← Kubernetes 리소스 감시 (Service, Endpoints, Pod...)
└────┬────┘
│ xDS (gRPC stream)
▼
┌─────────┐
│ Envoy │ ← LDS, RDS, CDS, EDS, SDS 수신
└─────────┘
Citadel: 인증서 관리
Citadel(현재 istiod에 통합)은 메시 내 워크로드의 아이덴티티와 인증서를 관리합니다:
- CA(Certificate Authority) 역할 수행
- 각 워크로드에 X.509 인증서 발급
- SPIFFE 표준 기반 아이덴티티 부여
- 인증서 자동 로테이션 (기본 24시간)
Galley: 구성 검증
Galley는 Istio 구성의 유효성을 검증합니다:
- Kubernetes Admission Webhook을 통한 구성 검증
- CRD 스키마 검증
- 구성 간 참조 무결성 확인 (예: VirtualService가 참조하는 Gateway 존재 여부)
Envoy 사이드카 주입 메커니즘
MutatingWebhookConfiguration
Istio의 사이드카 주입은 Kubernetes의 MutatingAdmissionWebhook을 활용합니다:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: istio-sidecar-injector
webhooks:
- name: sidecar-injector.istio.io
namespaceSelector:
matchLabels:
istio-injection: enabled
rules:
- apiGroups: ['']
apiVersions: ['v1']
operations: ['CREATE']
resources: ['pods']
파드가 생성될 때 다음 과정이 진행됩니다:
1. kubectl apply -f deployment.yaml
│
2. Kubernetes API Server가 Admission Webhook 호출
│
3. istiod의 Sidecar Injector가 파드 스펙 수정
│
4. 수정된 파드 스펙이 반환
│
5. 수정된 스펙으로 파드 생성
주입되는 컨테이너
사이드카 주입 시 두 개의 컨테이너가 추가됩니다:
1. istio-init (Init Container)
initContainers:
- name: istio-init
image: proxyv2
command:
- istio-iptables
- '-p'
- '15001' # Envoy outbound 포트
- '-z'
- '15006' # Envoy inbound 포트
- '-u'
- '1337' # istio-proxy UID (이 UID의 트래픽은 리다이렉트 제외)
- '-m'
- 'REDIRECT'
securityContext:
capabilities:
add: ['NET_ADMIN', 'NET_RAW']
istio-init 컨테이너는 iptables 규칙을 설정하여 모든 인바운드/아웃바운드 트래픽을 Envoy 프록시로 리다이렉트합니다.
2. istio-proxy (Sidecar Container)
containers:
- name: istio-proxy
image: proxyv2
ports:
- containerPort: 15090 # Prometheus 메트릭
- containerPort: 15021 # 헬스 체크
env:
- name: ISTIO_META_CLUSTER_ID
value: 'Kubernetes'
- name: PILOT_CERT_PROVIDER
value: 'istiod'
iptables 트래픽 리다이렉트
istio-init이 설정하는 iptables 규칙의 흐름:
[인바운드 트래픽]
외부 → Pod IP:Port
→ iptables PREROUTING
→ ISTIO_INBOUND 체인
→ REDIRECT to 15006 (Envoy inbound listener)
→ Envoy가 처리 후 localhost:AppPort로 전달
[아웃바운드 트래픽]
App → 외부 서비스 IP:Port
→ iptables OUTPUT
→ ISTIO_OUTPUT 체인
→ REDIRECT to 15001 (Envoy outbound listener)
→ Envoy가 처리 후 실제 목적지로 전달
[예외]
UID 1337 (istio-proxy)의 트래픽은 리다이렉트 제외 → 무한 루프 방지
xDS 프로토콜 상세
xDS(x Discovery Service)는 Envoy가 동적으로 구성을 수신하는 API 프로토콜입니다.
xDS API 종류
| API | 전체 이름 | 역할 |
|---|---|---|
| LDS | Listener Discovery Service | 리스너 구성 (포트, 프로토콜) |
| RDS | Route Discovery Service | HTTP 라우팅 규칙 |
| CDS | Cluster Discovery Service | 업스트림 클러스터 정의 |
| EDS | Endpoint Discovery Service | 클러스터 내 실제 엔드포인트 목록 |
| SDS | Secret Discovery Service | TLS 인증서 및 키 |
구성 푸시 흐름
[1] 사용자가 VirtualService 생성
│
[2] Pilot이 Kubernetes API 감시를 통해 변경 감지
│
[3] Pilot이 VirtualService를 Envoy RDS 구성으로 변환
│
[4] 관련 CDS, EDS 구성도 함께 생성
│
[5] gRPC 스트림으로 해당 워크로드의 Envoy에 푸시
│
[6] Envoy가 새 구성을 핫 리로드 (연결 끊김 없음)
ADS (Aggregated Discovery Service)
Istio는 ADS를 사용하여 모든 xDS 응답을 단일 gRPC 스트림으로 통합합니다. 이는 구성 일관성을 보장합니다:
- CDS와 EDS 간의 순서 보장 (클러스터 정의 먼저, 엔드포인트 나중)
- LDS와 RDS 간의 순서 보장
- 원자적 구성 업데이트
구성 확인 방법
# 특정 파드의 Envoy 리스너 확인
istioctl proxy-config listeners PODNAME.NAMESPACE
# 라우트 구성 확인
istioctl proxy-config routes PODNAME.NAMESPACE
# 클러스터 구성 확인
istioctl proxy-config clusters PODNAME.NAMESPACE
# 엔드포인트 확인
istioctl proxy-config endpoints PODNAME.NAMESPACE
# 전체 Envoy 구성 덤프
istioctl proxy-config all PODNAME.NAMESPACE -o json
Envoy 필터 체인 아키텍처
Envoy 프록시는 계층적 필터 체인으로 요청을 처리합니다:
[요청 흐름]
Listener (포트 바인딩)
│
▼
Filter Chain (일치하는 필터 체인 선택)
│
├── Network Filters
│ ├── TCP Proxy Filter (L4)
│ └── HTTP Connection Manager (L7)
│ │
│ ├── HTTP Filters
│ │ ├── RBAC Filter (인가)
│ │ ├── JWT Authn Filter (인증)
│ │ ├── Fault Injection Filter
│ │ ├── CORS Filter
│ │ ├── Stats Filter (메트릭)
│ │ └── Router Filter (최종 라우팅)
│ │
│ └── Route Configuration
│ ├── Virtual Host 선택
│ └── Route 매칭 및 Cluster 결정
│
▼
Cluster (업스트림 선택)
│
▼
Endpoint (실제 대상 파드)
Listener 구조
Listener 0.0.0.0:15006 (Inbound)
├── FilterChain: App 포트 (예: 8080)
│ ├── TLS Inspector
│ ├── HTTP Connection Manager
│ │ ├── istio_authn filter
│ │ ├── envoy.filters.http.rbac
│ │ └── envoy.filters.http.router
│ └── Route: inbound|8080|http|service.ns.svc.cluster.local
└── FilterChain: Default (passthrough)
Listener 0.0.0.0:15001 (Outbound)
├── FilterChain: 서비스별 매칭
│ ├── HTTP Connection Manager
│ │ ├── envoy.filters.http.fault
│ │ ├── envoy.filters.http.cors
│ │ ├── istio.stats
│ │ └── envoy.filters.http.router
│ └── Route: 서비스별 VirtualHost
└── FilterChain: PassthroughCluster (매칭되지 않는 트래픽)
워크로드 아이덴티티: SPIFFE
SPIFFE ID 체계
Istio는 SPIFFE(Secure Production Identity Framework For Everyone) 표준을 사용합니다:
spiffe://TRUST_DOMAIN/ns/NAMESPACE/sa/SERVICE_ACCOUNT
예시:
spiffe://cluster.local/ns/production/sa/frontend
인증서 발급 흐름 (CSR Flow)
[1] istio-agent (파드 내)가 키 쌍 생성
│
[2] CSR(Certificate Signing Request) 생성
│
[3] CSR을 istiod에 전송 (gRPC, 이미 부트스트랩 토큰으로 인증)
│
[4] istiod가 CSR 검증:
- ServiceAccount 토큰 유효성
- 네임스페이스 소속 확인
│
[5] istiod의 CA가 X.509 인증서 서명
│
[6] 서명된 인증서를 istio-agent에 반환
│
[7] istio-agent가 SDS를 통해 Envoy에 인증서 전달
│
[8] Envoy가 mTLS에 인증서 사용
SDS (Secret Discovery Service)
인증서는 파일 시스템이 아닌 SDS를 통해 Envoy에 전달됩니다:
- istio-agent가 로컬 SDS 서버 역할
- Envoy가 SDS API로 인증서 요청
- 인증서 로테이션 시 Envoy 재시작 불필요
- 인증서가 디스크에 기록되지 않아 보안성 향상
구성 변환: Istio CRD에서 Envoy 구성으로
VirtualService 변환 예시
사용자가 정의한 VirtualService:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
이것이 Envoy RDS 구성으로 변환됩니다:
{
"name": "reviews.default.svc.cluster.local:9080",
"virtual_hosts": [
{
"name": "reviews.default.svc.cluster.local:9080",
"domains": ["reviews.default.svc.cluster.local"],
"routes": [
{
"match": {
"prefix": "/",
"headers": [
{
"name": "end-user",
"string_match": {
"exact": "jason"
}
}
]
},
"route": {
"cluster": "outbound|9080|v2|reviews.default.svc.cluster.local"
}
},
{
"match": {
"prefix": "/"
},
"route": {
"cluster": "outbound|9080|v1|reviews.default.svc.cluster.local"
}
}
]
}
]
}
DestinationRule 변환 예시
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: reviews-destination
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
이것은 Envoy CDS 구성으로 변환됩니다:
{
"name": "outbound|9080|v1|reviews.default.svc.cluster.local",
"type": "EDS",
"eds_cluster_config": {
"service_name": "outbound|9080|v1|reviews.default.svc.cluster.local"
},
"circuit_breakers": {
"thresholds": [
{
"max_connections": 100
}
]
},
"transport_socket": {
"name": "envoy.transport_sockets.tls",
"typed_config": {
"common_tls_context": {
"tls_certificate_sds_secret_configs": [
{
"name": "default",
"sds_config": {
"api_config_source": {
"api_type": "GRPC",
"grpc_services": [
{
"envoy_grpc": {
"cluster_name": "sds-grpc"
}
}
]
}
}
}
]
}
}
}
}
구성 동기화 및 디버깅
proxy-status로 동기화 상태 확인
$ istioctl proxy-status
NAME CDS LDS EDS RDS ECDS ISTIOD
frontend-v1-xxx.prod SYNCED SYNCED SYNCED SYNCED istiod-abc
reviews-v1-yyy.prod SYNCED SYNCED SYNCED SYNCED istiod-abc
ratings-v1-zzz.prod STALE SYNCED SYNCED SYNCED istiod-abc
상태 코드:
- SYNCED: 프록시가 최신 구성을 받음
- NOT SENT: istiod가 아직 구성을 보내지 않음
- STALE: istiod가 구성을 보냈지만 ACK를 받지 못함
구성 차이 비교
# istiod가 보낸 구성과 프록시가 가진 구성 비교
istioctl proxy-config all PODNAME -o json > proxy-config.json
istioctl proxy-status PODNAME --diff
성능 고려사항
컨트롤 플레인 확장
- istiod는 수평 확장 가능 (여러 복제본)
- 각 Envoy는 하나의 istiod 인스턴스에 연결
- istiod 장애 시 Envoy는 마지막으로 받은 구성으로 계속 동작
대규모 메시에서의 최적화
- Sidecar 리소스 사용: 각 워크로드가 알아야 할 서비스 범위 제한
- exportTo 설정: CRD의 가시성 범위 제한
- 이벤트 배치 처리: istiod는 짧은 기간 내 여러 변경을 묶어서 푸시
- 증분 xDS(Delta xDS): 변경된 부분만 전송
# Sidecar 리소스로 Envoy 메모리 최적화
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: default
namespace: production
spec:
egress:
- hosts:
- './*' # 같은 네임스페이스 서비스
- 'istio-system/*' # Istio 시스템 서비스
- 'monitoring/prometheus' # 특정 외부 서비스
마무리
Istio의 내부 아키텍처를 이해하면 다음과 같은 이점이 있습니다:
- 트러블슈팅 능력 향상: xDS 동기화 문제, 사이드카 주입 실패, 인증서 만료 등을 빠르게 진단
- 성능 최적화: Sidecar 리소스, 연결 풀 튜닝, 구성 범위 제한 등을 적절히 활용
- 보안 강화: mTLS 동작 원리를 이해하고 올바른 PeerAuthentication 설정
다음 글에서는 트래픽 관리 엔진의 내부 동작을 더 깊이 살펴보겠습니다.