Istio 사이드카 모드 공식문서 전수 정리
참고자료
- Istio Documentation
- Istio Architecture
- Traffic Management
- Security
- Observability
- Envoy Proxy Documentation
- SPIFFE - Secure Production Identity Framework
- Istio - Sidecar Injection
- Istio - Wasm Plugin
- Istio - Multicluster Installation
배경
서비스 사이의 통신을 암호화하고, 어느 서비스가 어느 서비스를 부르는지 보고 싶었다. 애플리케이션마다 TLS를 붙이고 로그를 남기게 하면 되지만, 서비스 수만큼 같은 일을 반복해야 하고 언어와 프레임워크가 다르면 구현도 제각각이 된다.
서비스 메시가 이 문제를 애플리케이션 밖에서 푼다는 것은 알고 있었는데, “사이드카를 붙인다”는 설명이 실제로 무엇을 뜻하는지가 손에 안 잡혔다.
공식문서를 처음부터 따라가면서 정리했다.
정리하면서 확인하고 싶었던 것들이다.
- 애플리케이션 코드를 안 고치는데 어떻게 트래픽이 프록시를 지나가는가?
- 컨트롤 플레인이 프록시에게 설정을 어떻게 전달하는가?
- mTLS를 켜면 인증서는 누가 만들고 언제 갱신되는가?
- 사이드카 하나가 파드마다 붙는데 그 비용은 얼마나 되는가?
Istio Sidecar 모드는 프로덕션 환경에서 가장 오래 검증된 Service Mesh 배포 방식이다. 이 글에서는 공식 문서를 기반으로 Istio의 아키텍처, Sidecar Injection 메커니즘, xDS 프로토콜, 트래픽 관리, 보안, Observability를 단계별로 깊이 있게 정리한다.
1. Istio 소개
Service Mesh는 애플리케이션에 코드 변경 없이 제로 트러스트 보안, 관측성, 고급 트래픽 관리 기능을 제공하는 인프라 계층이다. Istio는 가장 인기 있고, 강력하며, 신뢰받는 Service Mesh이다. 2016년 Google, IBM, Lyft가 공동 창립했으며, Kubernetes, Prometheus와 함께 CNCF Graduated 프로젝트이다.
Istio는 마이크로서비스 간 네트워크 통신의 복잡성을 애플리케이션 코드에서 분리하여 인프라 계층에서 해결한다. 각 서비스가 개별적으로 재시도, 타임아웃, 암호화, 접근 제어를 구현하는 대신, 사이드카 프록시가 이 모든 것을 투명하게 처리한다.
1.1 핵심 기능
Istio 공식 문서에서 명시하는 핵심 기능은 다음과 같다.
| 기능 | 설명 |
|---|---|
| Secure by default | 워크로드 간 mTLS 자동 적용, 인증서 자동 로테이션 |
| Powerful traffic management | VirtualService, DestinationRule을 통한 세밀한 트래픽 제어 |
| Observable | 코드 변경 없이 메트릭, 로그, 분산 추적 자동 수집 |
| Extensible | WebAssembly 플러그인, Envoy 필터 체인을 통한 확장 |
2. Architecture (공식문서 기반)
Istio Service Mesh는 논리적으로 데이터 플레인과 컨트롤 플레인으로 나뉜다. 데이터 플레인은 사이드카로 배포되는 지능형 프록시(Envoy) 집합으로 구성된다. 이 프록시들은 마이크로서비스 간 모든 네트워크 통신을 중재하고 제어한다. 또한 모든 메시 트래픽에 대한 텔레메트리를 수집하고 보고한다. 컨트롤 플레인은 프록시를 관리하고 설정하여 트래픽을 라우팅한다.
이 아키텍처의 핵심은 관심사의 분리(Separation of Concerns)이다. 컨트롤 플레인은 “무엇을 할 것인가”를 결정하고, 데이터 플레인은 “어떻게 실행할 것인가”를 담당한다.
2.1 전체 아키텍처 다이어그램
graph TB
subgraph Control_Plane["Control Plane"]
istiod["istiod<br/>(Pilot + Citadel + Galley)"]
end
subgraph Data_Plane["Data Plane"]
subgraph Pod_A["Pod A"]
AppA["App Container"]
InitA["istio-init<br/>(iptables 설정)"]
ProxyA["Envoy Sidecar<br/>:15001 outbound<br/>:15006 inbound"]
AgentA["pilot-agent"]
end
subgraph Pod_B["Pod B"]
AppB["App Container"]
InitB["istio-init<br/>(iptables 설정)"]
ProxyB["Envoy Sidecar<br/>:15001 outbound<br/>:15006 inbound"]
AgentB["pilot-agent"]
end
subgraph Gateway["Istio Gateway"]
IGW["Ingress Gateway<br/>(Envoy)"]
EGW["Egress Gateway<br/>(Envoy)"]
end
end
subgraph External["External"]
Client["External Client"]
ExtSvc["External Service"]
end
K8sAPI["Kubernetes API Server"]
K8sAPI -->|"Watch: Service, Endpoint,<br/>VirtualService, DestinationRule"| istiod
istiod -->|"xDS API<br/>(LDS/RDS/CDS/EDS/SDS)"| ProxyA
istiod -->|"xDS API"| ProxyB
istiod -->|"xDS API"| IGW
istiod -->|"xDS API"| EGW
istiod -->|"SPIFFE X.509 인증서"| AgentA
istiod -->|"SPIFFE X.509 인증서"| AgentB
Client -->|"Ingress Traffic"| IGW
IGW --> ProxyA
AppA <--> ProxyA
ProxyA <-->|"mTLS"| ProxyB
AppB <--> ProxyB
ProxyB --> EGW
EGW -->|"Egress Traffic"| ExtSvc
2.2 Control Plane - istiod
Istio 1.5 이전에는 Pilot, Citadel, Galley가 별도 프로세스로 동작했지만, 1.5부터 istiod라는 단일 바이너리로 통합되었다. 이로 인해 운영 복잡도가 크게 감소했고, 컴포넌트 간 통신 오버헤드도 제거되었다.
istiod는 이전에 Pilot, Citadel, Galley, 사이드카 인젝터가 수행하던 기능을 하나의 바이너리로 통합한다.
각 컴포넌트의 역할은 다음과 같다.
| 컴포넌트 | 역할 | 상세 |
|---|---|---|
| Pilot | 서비스 디스커버리, Envoy 프록시 설정 | Kubernetes API Server를 watch하여 Service, Endpoint 변경을 감지하고 xDS API로 프록시에 push |
| Citadel | 워크로드 ID 발급, 인증서 관리 | SPIFFE X.509 인증서 발급, 자동 로테이션 (기본 24시간), Root CA 관리 |
| Galley | 설정 검증 및 분배 | VirtualService, DestinationRule 등 Istio CRD의 스키마 검증, 유효성 확인 후 Pilot에 전달 |
istiod는 다음과 같은 포트를 사용한다.
| 포트 | 프로토콜 | 용도 |
|---|---|---|
| 15010 | gRPC (plaintext) | xDS API (디버깅용) |
| 15012 | gRPC (mTLS) | xDS API (프로덕션) |
| 15014 | HTTP | 컨트롤 플레인 모니터링 |
| 15017 | HTTPS | Webhook (Sidecar Injection, Config Validation) |
| 443 | HTTPS | Webhook (15017로 리다이렉트) |
2.3 Data Plane - Envoy Proxy
Envoy는 대규모 현대 서비스 지향 아키텍처를 위해 설계된 L7 프록시이자 통신 버스이다.
Istio의 데이터 플레인에서 Envoy는 다음 기능을 수행한다.
- Dynamic service discovery: istiod로부터 xDS를 통해 서비스 목록을 동적으로 수신
- Load balancing: 다양한 알고리즘 지원 (ROUND_ROBIN, LEAST_REQUEST, RANDOM, RING_HASH)
- TLS termination: 인바운드/아웃바운드 mTLS 자동 처리
- HTTP/2 and gRPC proxies: 프로토콜 레벨 인식 및 최적화
- Circuit breakers: 연결 풀, 요청 수 기반 회로 차단
- Health checks: 능동적/수동적 헬스 체크
- Staged rollouts with %-based traffic split: 가중치 기반 트래픽 분할
- Fault injection: 지연, 중단 주입으로 카오스 테스팅
- Rich metrics: L4/L7 메트릭 자동 수집 및 보고
3. Sidecar Injection 메커니즘
Istio의 사이드카 주입은 Kubernetes의 MutatingAdmissionWebhook을 활용한다. Pod 생성 요청이 API Server에 도달하면, istiod의 웹훅이 Pod spec을 수정하여 istio-init init container와 istio-proxy sidecar container를 추가한다.
Istio의 모든 기능을 활용하려면 메시 내 Pod에 Istio 사이드카 프록시가 실행되어야 한다. 사이드카는 Mutating Webhook Admission Controller를 통해 자동으로 주입하거나, istioctl을 사용하여 수동으로 주입할 수 있다.
3.1 주입 제어 방법
| 방법 | 적용 범위 | 예시 |
|---|---|---|
| Namespace label | 네임스페이스 전체 | kubectl label namespace default istio-injection=enabled |
| Pod annotation | 개별 Pod | sidecar.istio.io/inject: "true" |
| Revision label | 특정 istiod revision | istio.io/rev=canary (카나리 업그레이드용) |
1
2
3
4
5
6
7
# Namespace 레벨 자동 주입 활성화
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
istio-injection: enabled
1
2
3
4
5
6
7
8
9
10
11
12
13
# Pod 레벨 주입 제어
apiVersion: v1
kind: Pod
metadata:
name: my-app
annotations:
sidecar.istio.io/inject: "true" # 주입 활성화
sidecar.istio.io/proxyCPU: "100m" # 사이드카 CPU 요청
sidecar.istio.io/proxyMemory: "128Mi" # 사이드카 메모리 요청
spec:
containers:
- name: my-app
image: my-app:v1
3.2 Sidecar Injection 시퀀스
sequenceDiagram
participant User as kubectl / CI/CD
participant API as Kubernetes API Server
participant Webhook as istiod<br/>(MutatingWebhook)
participant Kubelet as Kubelet
participant Init as istio-init
participant Agent as pilot-agent
participant Proxy as Envoy Proxy
participant Istiod as istiod<br/>(Control Plane)
User->>API: Pod 생성 요청
API->>Webhook: MutatingAdmissionWebhook 호출
Webhook->>Webhook: injection 조건 확인<br/>(namespace label, pod annotation)
Webhook->>API: Pod spec 수정 반환<br/>(istio-init + istio-proxy 추가)
API->>Kubelet: 수정된 Pod 스케줄링
Note over Kubelet,Init: Init Container 단계
Kubelet->>Init: istio-init 실행
Init->>Init: iptables 규칙 설정<br/>INBOUND → 15006<br/>OUTBOUND → 15001
Init->>Kubelet: 완료
Note over Kubelet,Proxy: Main Container 단계
Kubelet->>Agent: pilot-agent 시작
Agent->>Proxy: Envoy 프로세스 시작
Agent->>Istiod: SDS 요청 (인증서)
Istiod->>Agent: SPIFFE X.509 인증서 발급
Agent->>Proxy: 인증서 전달
Proxy->>Istiod: xDS 연결 수립<br/>(LDS/RDS/CDS/EDS)
Istiod->>Proxy: 초기 설정 push
Proxy->>Proxy: 트래픽 처리 시작
3.3 istio-init Container (iptables 설정)
istio-init은 init container로 실행되어 Pod의 네트워크 네임스페이스에 iptables 규칙을 설정한다. 이 규칙에 의해 모든 인바운드/아웃바운드 트래픽이 Envoy 프록시를 경유하게 된다.
Envoy는 Pod의 모든 인바운드 및 아웃바운드 트래픽을 가로챈다.
핵심 iptables 규칙의 동작 원리는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
# istio-init이 설정하는 iptables 규칙 (간소화 버전)
# 인바운드 트래픽: 모든 TCP → 0.0.0.0:15006 (Envoy inbound listener)
iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-ports 15006
# 아웃바운드 트래픽: 모든 TCP → 0.0.0.0:15001 (Envoy outbound listener)
iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT
iptables -t nat -A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN # Envoy 자체 트래픽 제외
iptables -t nat -A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN # Envoy 자체 트래픽 제외
iptables -t nat -A ISTIO_OUTPUT -j REDIRECT --to-ports 15001
| 포트 | 방향 | 용도 |
|---|---|---|
| 15006 | Inbound | Envoy 인바운드 리스너 (외부 → Pod) |
| 15001 | Outbound | Envoy 아웃바운드 리스너 (Pod → 외부) |
| 15020 | - | 헬스 체크 (merged Prometheus telemetry) |
| 15090 | - | Envoy Prometheus telemetry |
여기서 무한 루프가 나지 않는 이유가 있다. UID와 GID 1337(istio-proxy 사용자)에서 발생하는 트래픽은 iptables 규칙에서 제외된다. 이 예외가 없으면 Envoy가 자신이 내보낸 트래픽을 다시 가로채면서 끝없이 돌게 된다.
3.4 pilot-agent 역할
pilot-agent는 Envoy 프록시의 라이프사이클을 관리하는 프로세스이다. 사이드카 컨테이너의 ENTRYPOINT로 실행되며, 다음 역할을 수행한다.
- Envoy 프로세스 관리: 시작, 재시작, 그레이스풀 셧다운
- 인증서 로테이션: istiod로부터 SDS를 통해 인증서를 수신하고 Envoy에 전달
- 헬스 체크 프록시: 애플리케이션의 헬스 체크를 Envoy를 통해 노출
- Bootstrap 설정 생성: Envoy 초기 설정 파일 생성
- DNS 프록시:
.svc.cluster.local도메인 해석 (Istio DNS Proxy 기능)
graph LR
subgraph Sidecar_Container["istio-proxy container"]
PA["pilot-agent<br/>(PID 1)"]
EP["Envoy Proxy<br/>(child process)"]
end
Istiod["istiod"]
PA -->|"프로세스 관리"| EP
PA <-->|"SDS (인증서)"| Istiod
EP <-->|"xDS (설정)"| Istiod
PA -->|"Bootstrap 생성"| EP
4. xDS Protocol (상세)
xDS(x Discovery Service)는 Envoy와 컨트롤 플레인 간의 통신 프로토콜이다. istiod는 Kubernetes API Server의 리소스 변경을 감지하면 이를 Envoy 설정으로 변환하여 xDS를 통해 push한다.
Envoy는 파일시스템을 통해서 또는 하나 이상의 관리 서버에 쿼리하여 다양한 동적 리소스를 발견한다. 이러한 디스커버리 서비스와 해당 API를 통칭하여 xDS라고 한다.
4.1 xDS 프로토콜 종류
| 프로토콜 | Full Name | 역할 | Istio 리소스 매핑 |
|---|---|---|---|
| LDS | Listener Discovery Service | 리스너 설정 (포트, 프로토콜, 필터 체인) | Gateway, Sidecar |
| RDS | Route Discovery Service | 라우팅 규칙 (호스트, 경로, 가중치) | VirtualService |
| CDS | Cluster Discovery Service | 업스트림 클러스터 (로드밸런싱, 연결 풀) | DestinationRule |
| EDS | Endpoint Discovery Service | 엔드포인트 (Pod IP, 포트, 상태) | Kubernetes Endpoints |
| SDS | Secret Discovery Service | TLS 인증서 (mTLS, 서버 인증서) | PeerAuthentication |
4.2 xDS Push 흐름
sequenceDiagram
participant K8s as Kubernetes API Server
participant Istiod as istiod (Pilot)
participant Envoy as Envoy Proxy
K8s->>Istiod: Watch 이벤트<br/>(Service/Endpoint/CRD 변경)
Istiod->>Istiod: 변경 감지 및<br/>Envoy 설정 변환
Istiod->>Envoy: CDS push (클러스터 정보)
Envoy->>Istiod: ACK
Istiod->>Envoy: EDS push (엔드포인트)
Envoy->>Istiod: ACK
Istiod->>Envoy: LDS push (리스너)
Envoy->>Istiod: ACK
Istiod->>Envoy: RDS push (라우팅)
Envoy->>Istiod: ACK
Note over Istiod,Envoy: SDS는 별도 채널로<br/>인증서 로테이션 시 push
4.3 xDS 디버깅
실제 운영 시 Envoy가 수신한 xDS 설정을 확인하는 것은 트러블슈팅의 핵심이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 특정 Pod의 Envoy 설정 전체 확인
istioctl proxy-config all <pod-name> -n <namespace>
# 리스너 확인 (LDS)
istioctl proxy-config listeners <pod-name> -n <namespace>
# 라우트 확인 (RDS)
istioctl proxy-config routes <pod-name> -n <namespace>
# 클러스터 확인 (CDS)
istioctl proxy-config clusters <pod-name> -n <namespace>
# 엔드포인트 확인 (EDS)
istioctl proxy-config endpoints <pod-name> -n <namespace>
# 시크릿 확인 (SDS)
istioctl proxy-config secret <pod-name> -n <namespace>
# istiod-Envoy 동기화 상태 확인
istioctl proxy-status
5. Traffic Management (공식문서 상세)
Istio의 트래픽 라우팅 규칙을 사용하면 서비스 간 트래픽 흐름과 API 호출을 쉽게 제어할 수 있다. Istio는 서킷 브레이커, 타임아웃, 재시도와 같은 서비스 레벨 속성 설정을 단순화하고, A/B 테스트, 카나리 롤아웃, 퍼센트 기반 트래픽 분할과 같은 중요한 작업을 쉽게 설정할 수 있게 한다.
Istio의 트래픽 관리는 다음 CRD(Custom Resource Definition)를 통해 이루어진다.
graph TB
subgraph Traffic_Management_CRDs["Traffic Management CRDs"]
VS["VirtualService<br/>라우팅 규칙"]
DR["DestinationRule<br/>목적지 정책"]
GW["Gateway<br/>인그레스/이그레스"]
SE["ServiceEntry<br/>외부 서비스 등록"]
SC["Sidecar<br/>프록시 범위 제한"]
end
Client["Client"] --> GW
GW --> VS
VS --> DR
DR --> Service["Kubernetes Service"]
SE --> DR
SC -.->|"scope 제한"| VS
5.1 Virtual Services
VirtualService는 Istio 트래픽 라우팅의 핵심 리소스이다. Kubernetes Service로 향하는 트래픽을 어떻게 라우팅할지 정의한다.
VirtualService는 호스트에 접근할 때 적용할 트래픽 라우팅 규칙 집합을 정의한다.
5.1.1 기본 트래픽 분할 (카나리 배포)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-route
namespace: bookinfo
spec:
hosts:
- reviews # 대상 서비스 호스트명
http:
- route:
- destination:
host: reviews
subset: v1 # DestinationRule에서 정의한 subset
weight: 90 # 90% 트래픽 → v1
- destination:
host: reviews
subset: v2
weight: 10 # 10% 트래픽 → v2 (카나리)
5.1.2 헤더 기반 라우팅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-header-route
namespace: bookinfo
spec:
hosts:
- reviews
http:
- match: # 매칭 조건
- headers:
end-user:
exact: jason # end-user 헤더가 "jason"이면
route:
- destination:
host: reviews
subset: v3 # v3로 라우팅 (특정 사용자 테스트)
- route: # 기본 라우팅 (매칭 안 되면)
- destination:
host: reviews
subset: v1
5.1.3 URI 기반 라우팅 + 타임아웃 + 재시도 + 장애 주입
Envoy 프록시가 지정된 서비스의 응답을 기다리는 시간이다.
초기 호출이 실패했을 때 Envoy 프록시가 연결을 시도하는 최대 횟수이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: ratings-route
namespace: bookinfo
spec:
hosts:
- ratings
http:
# 1) /api/v2 경로 → v2 subset (타임아웃 + 재시도)
- match:
- uri:
prefix: /api/v2
method:
exact: GET
route:
- destination:
host: ratings
subset: v2
timeout: 3s # 3초 타임아웃
retries:
attempts: 3 # 최대 3회 재시도
perTryTimeout: 1s # 재시도당 1초 타임아웃
retryOn: "5xx,reset,connect-failure,retriable-4xx"
# 2) 장애 주입 (카오스 테스팅)
- match:
- headers:
x-chaos-test:
exact: "true"
fault:
delay:
percentage:
value: 50.0 # 50% 요청에 2초 지연 주입
fixedDelay: 2s
abort:
percentage:
value: 10.0 # 10% 요청에 500 에러 반환
httpStatus: 500
route:
- destination:
host: ratings
subset: v1
# 3) 기본 라우팅
- route:
- destination:
host: ratings
subset: v1
5.1.4 Match 조건 전체 목록
| 필드 | 설명 | 예시 |
|---|---|---|
uri | URI 경로 | exact: /api, prefix: /api/v1, regex: /api/v[0-9]+ |
headers | HTTP 헤더 | exact, prefix, regex |
method | HTTP 메서드 | exact: GET |
port | 포트 번호 | 80 |
queryParams | 쿼리 파라미터 | exact: debug |
sourceLabels | 소스 Pod 라벨 | app: frontend |
sourceNamespace | 소스 네임스페이스 | default |
5.2 Destination Rules
DestinationRule은 VirtualService가 라우팅한 트래픽이 목적지에 도달한 후 적용되는 정책을 정의한다.
DestinationRule은 라우팅이 발생한 후 서비스를 향하는 트래픽에 적용되는 정책을 정의한다.
5.2.1 Subset 정의 + 로드밸런싱
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-destination
namespace: bookinfo
spec:
host: reviews # 대상 서비스
trafficPolicy: # 기본 트래픽 정책
loadBalancer:
simple: LEAST_REQUEST # 최소 요청 수 기반 로드밸런싱
subsets:
- name: v1
labels:
version: v1 # version=v1 라벨을 가진 Pod
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN # v1 subset은 라운드 로빈
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
5.2.2 로드밸런싱 알고리즘
| 알고리즘 | 설명 | 적합한 상황 |
|---|---|---|
ROUND_ROBIN | 순차적 분배 (기본값) | 일반적인 무상태 서비스 |
LEAST_REQUEST | 가장 적은 활성 요청을 가진 인스턴스 | 요청 처리 시간이 불균일한 서비스 |
RANDOM | 무작위 분배 | 간단한 분산이 필요한 경우 |
PASSTHROUGH | 프록시가 로드밸런싱하지 않음 | 클라이언트가 직접 제어 |
LEAST_CONN | 최소 연결 수 기반 | 장시간 연결 유지 서비스 |
5.2.3 연결 풀 + 서킷 브레이커 (Outlier Detection)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-circuit-breaker
namespace: bookinfo
spec:
host: reviews
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100 # 최대 TCP 연결 수
connectTimeout: 5s # TCP 연결 타임아웃
http:
h2UpgradePolicy: DEFAULT
http1MaxPendingRequests: 100 # 최대 대기 요청 수
http2MaxRequests: 1000 # HTTP/2 최대 동시 요청
maxRequestsPerConnection: 10 # 연결당 최대 요청 수
maxRetries: 3 # 최대 재시도 수
outlierDetection: # 이상치 감지 (서킷 브레이커)
consecutive5xxErrors: 5 # 연속 5xx 에러 5회 발생 시
interval: 10s # 검사 주기
baseEjectionTime: 30s # 최소 제외 시간
maxEjectionPercent: 50 # 최대 제외 비율 (50%)
minHealthPercent: 30 # 최소 건강 비율
서킷 브레이커 동작 흐름은 다음과 같다.
stateDiagram-v2
[*] --> Closed: 정상 상태
Closed --> Open: 연속 5xx 에러 ≥ 5회
Open --> HalfOpen: baseEjectionTime(30s) 경과
HalfOpen --> Closed: 정상 응답 확인
HalfOpen --> Open: 에러 재발생
note right of Closed
모든 트래픽 정상 전달
end note
note right of Open
해당 엔드포인트 제외
(ejection)
end note
note right of HalfOpen
제한된 트래픽으로
상태 확인
end note
5.2.4 TLS 설정 (클라이언트 측)
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: external-tls
spec:
host: external-api.example.com
trafficPolicy:
tls:
mode: MUTUAL # 클라이언트 mTLS
clientCertificate: /etc/certs/client.pem
privateKey: /etc/certs/key.pem
caCertificates: /etc/certs/ca.pem
| TLS 모드 | 설명 |
|---|---|
DISABLE | TLS 비활성화 |
SIMPLE | 단방향 TLS (서버 인증만) |
MUTUAL | 양방향 mTLS (서버 + 클라이언트 인증) |
ISTIO_MUTUAL | Istio가 자동 관리하는 mTLS |
5.3 Gateways
Gateway는 메시 경계에서 인바운드/아웃바운드 트래픽을 관리한다.
Gateway는 주로 인그레스 트래픽을 관리하는 데 사용되지만, 이그레스 게이트웨이도 설정할 수 있다.
5.3.1 Ingress Gateway (North-South 트래픽)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: bookinfo
spec:
selector:
istio: ingressgateway # Istio Ingress Gateway Pod 선택
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE # 단방향 TLS
credentialName: bookinfo-tls # Kubernetes Secret 참조
hosts:
- "bookinfo.example.com"
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "bookinfo.example.com"
tls:
httpsRedirect: true # HTTP → HTTPS 리다이렉트
---
# Gateway와 연결되는 VirtualService
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo-vs
namespace: bookinfo
spec:
hosts:
- "bookinfo.example.com"
gateways:
- bookinfo-gateway # Gateway 참조
http:
- match:
- uri:
prefix: /productpage
route:
- destination:
host: productpage
port:
number: 9080
5.3.2 Egress Gateway (아웃바운드 제어)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: external-egress
namespace: istio-system
spec:
selector:
istio: egressgateway
servers:
- port:
number: 443
name: tls
protocol: TLS
tls:
mode: PASSTHROUGH
hosts:
- "external-api.example.com"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: external-egress-vs
spec:
hosts:
- "external-api.example.com"
gateways:
- mesh # 메시 내부 트래픽
- external-egress # 이그레스 게이트웨이
tls:
- match:
- gateways:
- mesh
sniHosts:
- "external-api.example.com"
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
port:
number: 443
- match:
- gateways:
- external-egress
sniHosts:
- "external-api.example.com"
route:
- destination:
host: "external-api.example.com"
port:
number: 443
5.4 Service Entries
ServiceEntry는 Istio의 내부 서비스 레지스트리에 외부 서비스를 등록한다. 이를 통해 외부 서비스에도 Istio의 트래픽 관리 기능(재시도, 타임아웃, 장애 주입 등)을 적용할 수 있다.
ServiceEntry는 Istio의 내부 서비스 레지스트리에 추가 항목을 등록하여, 메시에서 자동 발견된 서비스가 수동으로 지정된 서비스에 접근/라우팅할 수 있게 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-api
spec:
hosts:
- "api.external-service.com"
location: MESH_EXTERNAL # 메시 외부 서비스
ports:
- number: 443
name: https
protocol: TLS
resolution: DNS # DNS 기반 해석
---
# 외부 서비스에 DestinationRule 적용
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: external-api-dr
spec:
host: "api.external-service.com"
trafficPolicy:
tls:
mode: SIMPLE # TLS 활성화
connectionPool:
tcp:
maxConnections: 50
outlierDetection:
consecutive5xxErrors: 3
interval: 30s
baseEjectionTime: 60s
| resolution | 설명 |
|---|---|
NONE | 해석 없음 (IP 직접 사용) |
STATIC | endpoints 필드에 지정된 고정 IP 사용 |
DNS | DNS 조회로 IP 해석 |
DNS_ROUND_ROBIN | DNS 결과를 라운드 로빈으로 사용 |
5.5 Sidecar (프록시 범위 제한)
Sidecar 리소스는 Envoy 프록시가 수신하는 xDS 설정의 범위를 제한한다. 기본적으로 모든 Envoy 프록시는 메시 내 모든 서비스의 설정을 수신하는데, 대규모 클러스터에서는 이것이 메모리와 CPU 오버헤드를 크게 증가시킨다.
기본적으로 Istio는 메시 내 모든 사이드카 프록시에 메시의 모든 워크로드 인스턴스에 도달하는 데 필요한 설정과, 워크로드와 연관된 모든 포트에서 트래픽을 수신하는 설정을 프로그래밍한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: networking.istio.io/v1
kind: Sidecar
metadata:
name: default
namespace: bookinfo
spec:
workloadSelector: # 적용 대상 (없으면 네임스페이스 전체)
labels:
app: reviews
ingress:
- port:
number: 9080
protocol: HTTP
name: http
defaultEndpoint: 127.0.0.1:9080 # 앱 컨테이너 포트
egress:
- hosts:
- "./*" # 같은 네임스페이스의 모든 서비스
- "istio-system/*" # istio-system의 모든 서비스
port:
number: 443
protocol: HTTPS
대규모 클러스터(서비스 1000개 이상)에서는 Sidecar 리소스를 반드시 사용해야 한다. 각 Envoy가 전체 메시의 설정을 보유하면, 서비스 하나 변경 시 수천 개의 프록시에 xDS push가 발생하여 컨트롤 플레인에 부하를 가중시킨다.
5.6 Network Resilience
5.6.1 Timeouts
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: ratings-timeout
spec:
hosts:
- ratings
http:
- route:
- destination:
host: ratings
timeout: 3s # 3초 타임아웃
5.6.2 Retries
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: ratings-retry
spec:
hosts:
- ratings
http:
- route:
- destination:
host: ratings
retries:
attempts: 3 # 최대 3회 재시도
perTryTimeout: 2s # 재시도당 2초 타임아웃
retryOn: "5xx,reset,connect-failure,retriable-4xx"
retryRemoteLocalities: true # 다른 locality의 엔드포인트로 재시도
| retryOn 값 | 설명 |
|---|---|
5xx | 5xx 응답 시 재시도 |
gateway-error | 502, 503, 504 응답 시 재시도 |
reset | 연결 리셋 시 재시도 |
connect-failure | 연결 실패 시 재시도 |
retriable-4xx | 재시도 가능한 4xx (409 등) |
refused-stream | REFUSED_STREAM 에러 시 재시도 |
5.6.3 Circuit Breakers
서킷 브레이커는 DestinationRule의 connectionPool과 outlierDetection으로 구성된다. (5.2.3 섹션의 예시 참조)
동작 원리:
connectionPool: 동시 연결 수, 대기 요청 수를 제한하여 과부하 방지outlierDetection: 비정상 엔드포인트를 감지하여 로드밸런싱 풀에서 일시 제거
5.6.4 Fault Injection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: ratings-fault
spec:
hosts:
- ratings
http:
- fault:
delay:
percentage:
value: 10.0 # 10% 요청에 지연 주입
fixedDelay: 5s # 5초 지연
abort:
percentage:
value: 5.0 # 5% 요청에 에러 주입
httpStatus: 503 # 503 응답 반환
route:
- destination:
host: ratings
subset: v1
장애 주입은 애플리케이션의 회복력(resilience)을 테스트하는 카오스 엔지니어링의 핵심 도구이다. 코드 변경 없이 인프라 레벨에서 장애를 시뮬레이션할 수 있다.
6. Security (공식문서 상세)
Istio는 모든 워크로드에 워크로드의 서비스 계정을 기반으로 하는 강력한 ID를 제공하며, 이 ID는 워크로드 간 상호 TLS 연결을 수립하고 검증하는 데 사용된다.
Istio의 보안 모델은 세 가지 축으로 구성된다.
graph TB
subgraph Security["Istio Security Model"]
Auth["Authentication<br/>(누구인가?)"]
Authz["Authorization<br/>(무엇을 할 수 있는가?)"]
Encrypt["Encryption<br/>(통신이 안전한가?)"]
end
Auth --> PeerAuth["PeerAuthentication<br/>(mTLS)"]
Auth --> ReqAuth["RequestAuthentication<br/>(JWT)"]
Authz --> AuthzPolicy["AuthorizationPolicy<br/>(ALLOW/DENY/CUSTOM/AUDIT)"]
Encrypt --> mTLS["자동 mTLS<br/>(SPIFFE X.509)"]
6.1 Authentication (인증)
Istio는 두 가지 유형의 인증을 제공한다. Peer 인증은 연결을 생성하는 클라이언트를 검증하는 서비스 간 인증에 사용된다. Request 인증은 요청에 첨부된 자격 증명을 검증하는 최종 사용자 인증에 사용된다.
6.1.1 PeerAuthentication (mTLS 모드)
PeerAuthentication은 워크로드 간 mTLS 통신 정책을 정의한다. Mesh 전체, 네임스페이스, 개별 워크로드 수준으로 설정 가능하다.
PeerAuthentication은 트래픽이 사이드카로 터널링되는 방식(또는 터널링 여부)을 정의한다.
모드가 설정되지 않은 메시 전체 피어 인증 정책은 기본적으로 PERMISSIVE 모드를 사용한다. 메시 전체 피어 인증 정책은 하나만 존재할 수 있고, 네임스페이스별 피어 인증 정책도 네임스페이스당 하나만 존재할 수 있다.
| mTLS 모드 | 설명 | 사용 시점 |
|---|---|---|
STRICT | mTLS만 허용 (평문 거부) | 프로덕션 환경 (완전 전환 후) |
PERMISSIVE | mTLS + 평문 모두 허용 | 마이그레이션 과정 (기본값) |
DISABLE | mTLS 비활성화 | 특수한 경우 (레거시 연동) |
UNSET | 상위 정책 상속 | 명시적 설정 불필요 시 |
1
2
3
4
5
6
7
8
9
# 1) Mesh 전체 STRICT mTLS
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system # istio-system에 설정하면 mesh-wide
spec:
mtls:
mode: STRICT
1
2
3
4
5
6
7
8
9
# 2) 네임스페이스 레벨 PERMISSIVE (마이그레이션 중)
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: legacy-namespace
spec:
mtls:
mode: PERMISSIVE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 3) 특정 워크로드에만 적용 (포트별 제어)
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: finance-app-strict
namespace: finance
spec:
selector:
matchLabels:
app: finance-api
mtls:
mode: STRICT
portLevelMtls:
8080:
mode: PERMISSIVE # 8080 포트만 PERMISSIVE
정책 우선순위는 workload 범위, namespace 범위, mesh 범위 순이다. 더 구체적으로 지정한 정책이 이긴다.
6.1.2 RequestAuthentication (JWT 검증)
RequestAuthentication은 외부에서 들어오는 요청의 JWT 토큰을 검증한다.
RequestAuthentication은 워크로드가 지원하는 요청 인증 방법을 정의한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: bookinfo
spec:
selector:
matchLabels:
app: productpage
jwtRules:
- issuer: "https://accounts.google.com"
jwksUri: "https://www.googleapis.com/oauth2/v3/certs"
fromHeaders:
- name: Authorization
prefix: "Bearer "
fromParams:
- "access_token" # 쿼리 파라미터에서도 토큰 추출
forwardOriginalToken: true # 원본 토큰을 upstream에 전달
outputPayloadToHeader: "x-jwt-payload" # 디코딩된 페이로드를 헤더로 전달
Request 인증 정책은 JSON Web Token(JWT)을 검증하는 데 필요한 값을 지정한다. 요청에 토큰이 없으면 기본적으로 수락된다.
주의: RequestAuthentication은 JWT가 존재할 때만 검증하고, JWT가 없는 요청은 통과시킨다. JWT 없는 요청을 차단하려면 AuthorizationPolicy를 함께 사용해야 한다.
6.2 Authorization (인가)
6.2.1 AuthorizationPolicy
AuthorizationPolicy는 워크로드에 대한 접근 제어를 정의한다.
Istio Authorization Policy는 메시 내 워크로드에 대한 접근 제어를 활성화한다.
Istio의 인가 기능은 메시 내 워크로드에 대해 메시, 네임스페이스, 워크로드 수준의 접근 제어를 제공한다. 각 Envoy 프록시는 런타임에 요청을 인가하는 인가 엔진을 실행한다. Istio의 인가 기능을 명시적으로 활성화할 필요가 없으며, 설치 후 바로 사용 가능하다. 인가 정책이 적용되지 않은 워크로드에 대해 Istio는 모든 요청을 허용한다.
| Action | 설명 |
|---|---|
ALLOW | 조건에 맞으면 허용 |
DENY | 조건에 맞으면 거부 (ALLOW보다 우선) |
CUSTOM | 외부 인가 서비스에 위임 |
AUDIT | 감사 로그만 기록 (트래픽 영향 없음) |
평가 순서는 CUSTOM, DENY, 그다음 ALLOW이다. deny 정책이 allow 정책보다 우선한다.
정책은 CUSTOM, DENY, ALLOW 순으로 평가하고, 어느 정책에도 걸리지 않으면 마지막에 암묵적 허용으로 떨어진다. DENY가 ALLOW보다 먼저 평가되므로 명시적 거부가 항상 이긴다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1) DENY: 특정 소스 차단
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-untrusted
namespace: bookinfo
spec:
selector:
matchLabels:
app: productpage
action: DENY
rules:
- from:
- source:
notNamespaces: ["bookinfo", "istio-system"] # 허용 네임스페이스 외 차단
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 2) ALLOW: 세밀한 접근 제어
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-read
namespace: bookinfo
spec:
selector:
matchLabels:
app: reviews
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/bookinfo/sa/productpage" # 특정 서비스 어카운트만
namespaces:
- "bookinfo"
to:
- operation:
methods: ["GET"] # GET만 허용
paths: ["/api/v1/*"] # 특정 경로만
ports: ["9080"]
when:
- key: request.headers[x-api-version]
values: ["v1", "v2"] # 특정 헤더 값 조건
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3) JWT 기반 인가 (RequestAuthentication과 조합)
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: bookinfo
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["https://accounts.google.com/*"]
when:
- key: request.auth.claims[groups]
values: ["admin", "editor"] # JWT claims의 groups 필드 검증
1
2
3
4
5
6
7
8
# 4) 전체 네임스페이스 기본 거부 (deny-all)
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: bookinfo
spec:
{} # 빈 spec = 모든 트래픽 거부
6.2.2 Source 필드 상세
| 필드 | 설명 | 예시 |
|---|---|---|
principals | SPIFFE ID | cluster.local/ns/default/sa/my-sa |
notPrincipals | SPIFFE ID 제외 | (위와 동일 형식) |
namespaces | 소스 네임스페이스 | ["bookinfo"] |
notNamespaces | 네임스페이스 제외 | ["untrusted"] |
ipBlocks | 소스 IP 대역 | ["10.0.0.0/8"] |
notIpBlocks | IP 대역 제외 | ["10.0.1.0/24"] |
requestPrincipals | JWT subject | ["issuer/subject"] |
remoteIpBlocks | 원본 클라이언트 IP | X-Forwarded-For 기반 |
6.3 mTLS 내부 동작
6.3.1 SPIFFE Identity
ID는 모든 보안 인프라의 근본적인 개념이다.
Istio는 SPIFFE(Secure Production Identity Framework For Everyone) 표준을 따르는 ID를 모든 워크로드에 부여한다.
SPIFFE는 동적이고 이기종 환경에서 소프트웨어 시스템을 안전하게 식별하기 위한 오픈 소스 표준 집합이다.
SPIFFE ID 형식:
1
spiffe://cluster.local/ns/{namespace}/sa/{service-account}
예시:
spiffe://cluster.local/ns/bookinfo/sa/productpage- bookinfo 네임스페이스의 productpage 서비스 어카운트spiffe://cluster.local/ns/istio-system/sa/istiod- istiod 자체의 ID
6.3.2 인증서 발급 및 로테이션 흐름
istiod는 인증서 서명 요청(CSR)을 받기 위한 gRPC 서비스를 제공한다. 워크로드가 시작되면, Envoy는 같은 컨테이너에 있는 Istio 에이전트에게 Envoy SDS(Secret Discovery Service) API를 통해 인증서와 키를 요청한다.
sequenceDiagram
participant App as Application Pod
participant Agent as pilot-agent
participant Envoy as Envoy Proxy
participant Istiod as istiod (Citadel)
participant K8s as Kubernetes API
Note over Agent,Istiod: 인증서 초기 발급
Agent->>Agent: CSR(Certificate Signing Request) 생성
Agent->>Istiod: SDS 요청 + CSR
Istiod->>K8s: ServiceAccount 토큰 검증
K8s->>Istiod: 검증 결과
Istiod->>Istiod: SPIFFE X.509 인증서 서명
Istiod->>Agent: 서명된 인증서 + CA 번들
Agent->>Envoy: SDS로 인증서 전달
Note over Agent,Istiod: 인증서 자동 로테이션 (기본 24시간)
loop 만료 전 로테이션
Agent->>Agent: 새 CSR 생성
Agent->>Istiod: SDS 갱신 요청
Istiod->>Agent: 새 인증서 발급
Agent->>Envoy: Hot reload (연결 중단 없음)
end
핵심 포인트:
- 인증서 기본 수명: 24시간 (환경 변수로 조정 가능)
- 로테이션은 만료 전에 자동 수행되므로 서비스 중단이 없다
- SDS를 통해 인증서를 메모리에서 직접 전달하므로, 디스크에 인증서를 저장하지 않는다 (보안 강화)
6.3.3 mTLS Handshake 과정
Istio는 Envoy 프록시로 구현된 클라이언트 및 서버 측 PEP를 통해 서비스 간 통신을 터널링한다. 보안 명명 검사를 통해 서버 인증서에 제시된 서비스 어카운트가 대상 서비스를 실행할 권한이 있는지 검증한다. Istio는 TLSv1_2를 최소 TLS 버전으로 설정한다. Istio mTLS에는 permissive 모드가 있어 서비스가 평문 트래픽과 mTLS 트래픽을 동시에 수신할 수 있다.
sequenceDiagram
participant ClientApp as Client App
participant ClientProxy as Client Envoy
participant ServerProxy as Server Envoy
participant ServerApp as Server App
ClientApp->>ClientProxy: 평문 HTTP 요청<br/>(localhost → 15001)
ClientProxy->>ClientProxy: 목적지 확인 (xDS)<br/>mTLS 정책 확인
Note over ClientProxy,ServerProxy: TLS Handshake
ClientProxy->>ServerProxy: ClientHello + SPIFFE ID
ServerProxy->>ClientProxy: ServerHello + SPIFFE 인증서
ClientProxy->>ClientProxy: 서버 인증서 검증<br/>(CA 체인 + SPIFFE ID)
ClientProxy->>ServerProxy: 클라이언트 인증서 전송
ServerProxy->>ServerProxy: 클라이언트 인증서 검증<br/>(CA 체인 + SPIFFE ID)
Note over ClientProxy,ServerProxy: 암호화 채널 수립 완료
ClientProxy->>ServerProxy: 암호화된 요청
ServerProxy->>ServerApp: 평문 HTTP 요청<br/>(15006 → localhost)
ServerApp->>ServerProxy: 평문 HTTP 응답
ServerProxy->>ClientProxy: 암호화된 응답
ClientProxy->>ClientApp: 평문 HTTP 응답
7. Observability (공식문서 상세)
Istio는 Service Mesh 내 모든 통신에 대한 상세한 텔레메트리를 생성한다. 이 텔레메트리는 Service Mesh 동작에 대한 관측성을 제공하여, 운영자가 애플리케이션을 트러블슈팅하고 유지 관리하고 최적화할 수 있게 한다.
Istio의 관측성은 코드 변경 없이 프록시 레벨에서 자동으로 수집된다. 이것이 Service Mesh의 가장 큰 장점 중 하나이다.
7.1 Metrics
메트릭은 동작을 집계 수준에서 모니터링하고 이해하는 방법을 제공한다.
Istio는 모니터링의 4가지 “골든 시그널” – 지연 시간, 트래픽, 에러, 포화도 – 에 기반한 메트릭을 생성한다.
7.1.1 Proxy-level Metrics (Envoy Stats)
Envoy는 자체적으로 수백 개의 메트릭을 노출한다. 주요 메트릭은 다음과 같다.
| 메트릭 | 설명 |
|---|---|
envoy_cluster_upstream_cx_active | 활성 업스트림 연결 수 |
envoy_cluster_upstream_cx_total | 총 업스트림 연결 수 |
envoy_cluster_upstream_rq_total | 총 업스트림 요청 수 |
envoy_cluster_upstream_rq_timeout | 타임아웃 요청 수 |
envoy_cluster_upstream_rq_retry | 재시도 횟수 |
envoy_server_memory_allocated | Envoy 메모리 사용량 |
7.1.2 Service-level Metrics (Istio 표준)
Istio가 생성하는 표준 메트릭은 모든 서비스 통신에 대해 자동으로 수집된다.
| 메트릭 | 설명 | 라벨 |
|---|---|---|
istio_requests_total | 총 요청 수 | source, destination, response_code |
istio_request_duration_milliseconds | 요청 지연 시간 | source, destination (histogram) |
istio_request_bytes | 요청 바이트 수 | source, destination (histogram) |
istio_response_bytes | 응답 바이트 수 | source, destination (histogram) |
istio_tcp_connections_opened_total | TCP 연결 수립 | source, destination |
istio_tcp_connections_closed_total | TCP 연결 종료 | source, destination |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Istio Telemetry API로 메트릭 커스터마이징
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: custom-metrics
namespace: bookinfo
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
mode: CLIENT_AND_SERVER
tagOverrides:
request_host:
operation: UPSERT
value: "request.host"
7.1.3 Control Plane Metrics
istiod 자체도 다음 메트릭을 노출한다.
| 메트릭 | 설명 |
|---|---|
pilot_xds_pushes | xDS push 횟수 (type별) |
pilot_proxy_convergence_time | 프록시 설정 수렴 시간 |
pilot_conflict_inbound_listener | 인바운드 리스너 충돌 |
pilot_conflict_outbound_listener_tcp_over_current_tcp | 아웃바운드 리스너 충돌 |
citadel_server_csr_count | CSR 처리 횟수 |
galley_validation_failed | 설정 검증 실패 |
7.2 Distributed Tracing
분산 추적은 개별 요청이 메시를 통과할 때 이를 모니터링하여 동작을 모니터링하고 이해하는 방법을 제공한다.
분산 추적은 사용자가 여러 서비스에 분산된 메시를 통과하는 요청을 추적할 수 있게 한다.
Istio는 Envoy 프록시에서 자동으로 스팬(span)을 생성한다. 그러나 분산 추적이 정상적으로 동작하려면 애플리케이션이 트레이스 컨텍스트 헤더를 전파(propagation)해야 한다. 이는 Istio가 해결할 수 없는 애플리케이션 책임이다.
7.2.1 전파해야 하는 헤더
| 헤더 | 설명 | 형식 |
|---|---|---|
x-request-id | Envoy 생성 요청 ID | UUID |
x-b3-traceid | Zipkin B3 트레이스 ID | 64/128-bit hex |
x-b3-spanid | Zipkin B3 스팬 ID | 64-bit hex |
x-b3-parentspanid | 부모 스팬 ID | 64-bit hex |
x-b3-sampled | 샘플링 여부 | 0 or 1 |
x-b3-flags | 디버그 플래그 | 0 or 1 |
b3 | B3 단일 헤더 형식 | {traceid}-{spanid}-{sampled}-{parentspanid} |
traceparent | W3C Trace Context | {version}-{trace-id}-{parent-id}-{trace-flags} |
tracestate | W3C Trace State | 벤더별 추가 정보 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Python Flask 예시: 트레이스 헤더 전파
from flask import Flask, request
import requests
app = Flask(__name__)
# 전파해야 하는 헤더 목록
TRACE_HEADERS = [
'x-request-id',
'x-b3-traceid',
'x-b3-spanid',
'x-b3-parentspanid',
'x-b3-sampled',
'x-b3-flags',
'b3',
'traceparent',
'tracestate',
]
@app.route('/api/v1/products')
def get_products():
# 인바운드 요청에서 트레이스 헤더 추출
headers = {}
for header in TRACE_HEADERS:
value = request.headers.get(header)
if value:
headers[header] = value
# 다운스트림 서비스 호출 시 헤더 전파
reviews = requests.get(
'http://reviews:9080/api/v1/reviews',
headers=headers # 트레이스 헤더 포함
)
return reviews.json()
7.2.2 트레이싱 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Telemetry API로 트레이싱 설정
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: tracing-config
namespace: istio-system
spec:
tracing:
- providers:
- name: zipkin # 또는 jaeger, opentelemetry
randomSamplingPercentage: 1.0 # 1% 샘플링 (프로덕션 권장)
customTags:
environment:
literal:
value: "production"
7.3 Access Logs
액세스 로그는 개별 워크로드 인스턴스의 관점에서 동작을 모니터링하고 이해하는 방법을 제공한다.
Envoy 액세스 로그는 모든 요청/응답의 상세 정보를 기록한다.
Envoy 프록시는 요청 정보를 포함하는 액세스 로그를 제공하도록 설정할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
# Telemetry API로 액세스 로그 설정
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: access-log
namespace: istio-system
spec:
accessLogging:
- providers:
- name: envoy
filter:
expression: "response.code >= 400" # 4xx, 5xx만 로깅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# MeshConfig로 글로벌 액세스 로그 설정 (IstioOperator)
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: JSON
accessLogFormat: |
{
"protocol": "%PROTOCOL%",
"upstream_service_time": "%REQ(x-envoy-upstream-service-time)%",
"upstream_cluster": "%UPSTREAM_CLUSTER%",
"downstream_remote_address": "%DOWNSTREAM_REMOTE_ADDRESS%",
"requested_server_name": "%REQUESTED_SERVER_NAME%",
"route_name": "%ROUTE_NAME%",
"response_code": "%RESPONSE_CODE%",
"response_flags": "%RESPONSE_FLAGS%",
"bytes_sent": "%BYTES_SENT%",
"duration": "%DURATION%",
"authority": "%REQ(:AUTHORITY)%",
"path": "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%",
"method": "%REQ(:METHOD)%",
"user_agent": "%REQ(USER-AGENT)%"
}
주요 RESPONSE_FLAGS 값:
| Flag | 설명 |
|---|---|
UH | Upstream Healthy 없음 (no healthy upstream) |
UF | Upstream 연결 실패 |
UO | Upstream Overflow (서킷 브레이커) |
NR | No Route (라우팅 규칙 없음) |
URX | Upstream 재시도 한도 초과 |
DC | Downstream 연결 종료 |
LH | Local Health Check 실패 |
UT | Upstream 타임아웃 |
RL | Rate Limited |
UAEX | Unauthorized External (인가 실패) |
7.4 Observability 스택 통합 아키텍처
graph TB
subgraph Workloads["Workloads"]
Pod1["Pod + Envoy"]
Pod2["Pod + Envoy"]
Pod3["Pod + Envoy"]
end
subgraph Observability["Observability Stack"]
Prometheus["Prometheus<br/>(메트릭 수집)"]
Grafana["Grafana<br/>(대시보드)"]
Jaeger["Jaeger/Tempo<br/>(분산 추적)"]
Loki["Loki<br/>(로그 집계)"]
Kiali["Kiali<br/>(서비스 토폴로지)"]
end
Pod1 -->|"메트릭 (15090)"| Prometheus
Pod2 -->|"메트릭 (15090)"| Prometheus
Pod3 -->|"메트릭 (15090)"| Prometheus
Pod1 -->|"스팬"| Jaeger
Pod2 -->|"스팬"| Jaeger
Pod1 -->|"액세스 로그"| Loki
Pod2 -->|"액세스 로그"| Loki
Prometheus --> Grafana
Prometheus --> Kiali
Jaeger --> Kiali
8. 왜 사용하는가
Istio Sidecar 모드를 도입하는 핵심 이유를 정리한다.
1) 애플리케이션 코드 수정 없이 트래픽/보안 정책 중앙 관리
각 서비스가 재시도, 타임아웃, 서킷 브레이커, TLS 등을 개별 구현하면 코드 중복과 불일치가 발생한다. Istio는 이를 인프라 레벨로 추출하여 CRD 기반으로 선언적 관리가 가능하게 한다.
2) 카나리/블루그린/트래픽 분할 배포 전략
VirtualService의 weight 기반 라우팅으로 코드 변경 없이 카나리 배포를 구현할 수 있다. 배포 파이프라인에서 weight 값만 조정하면 된다.
3) 서비스 간 통신 가시성과 제어력 확보
마이크로서비스 아키텍처에서 서비스 간 호출 관계는 빠르게 복잡해진다. Istio는 모든 트래픽을 프록시가 중재하므로, 코드 계측(instrumentation) 없이도 트래픽 흐름, 지연 시간, 에러율을 자동으로 수집한다.
4) Zero-trust security 구현
기존의 경계 기반 보안(perimeter security)은 내부 네트워크를 신뢰하는 모델이다. Istio의 mTLS와 AuthorizationPolicy를 사용하면, 서비스 간 통신도 인증/인가/암호화가 적용되는 제로 트러스트 모델을 구현할 수 있다.
5) Observability 표준화
서비스별로 다른 모니터링 라이브러리와 설정을 사용하는 대신, Envoy 프록시가 일관된 형식의 메트릭, 로그, 트레이스를 자동 생성한다.
9. 사용하지 않으면 어떻게 되는가
Service Mesh 없이 마이크로서비스를 운영하면 다음과 같은 문제가 발생한다.
1) 각 서비스가 재시도/타임아웃/회로차단/암호화를 중복 구현
서비스 A는 Go의 go-retryablehttp, 서비스 B는 Java의 Resilience4j, 서비스 C는 Python의 tenacity를 사용하는 식이다. 동일한 정책이 언어별로 다르게 구현되고, 설정 변경 시 모든 서비스를 개별 배포해야 한다.
2) 보안/접근 정책이 팀별 파편화, 거버넌스 난이도 상승
팀 A는 mTLS를 적용했지만, 팀 B는 평문 통신이고, 팀 C는 자체 인증 방식을 사용한다. 조직 전체에 일관된 보안 정책을 적용하기 어렵고, 감사(audit)도 서비스별로 별도 수행해야 한다.
3) 장애 분석 시 서비스 간 트래픽 흐름 추적 어려움
서비스 A → B → C → D 체인에서 장애가 발생하면, 각 서비스의 로그를 수동으로 상관관계(correlation)시켜야 한다. 분산 추적이 없으면 근본 원인(root cause) 분석에 시간이 기하급수적으로 증가한다.
4) mTLS 개별 구현 부담
인증서 발급, 갱신, 배포, 서비스 간 인증서 검증을 서비스별로 구현하면 운영 복잡도가 크게 증가한다. 인증서 만료로 인한 장애도 빈번해진다.
10. 대체 기술 비교
| 항목 | Istio Sidecar | Linkerd | Consul Connect | Kuma |
|---|---|---|---|---|
| 프록시 | Envoy (C++) | linkerd2-proxy (Rust) | Envoy / built-in | Envoy |
| 기능 폭 | 매우 넓음 | 핵심 기능 중심 | 멀티런타임 (K8s + VM) | 중간 |
| 운영 복잡도 | 중~상 | 낮음 | 중 | 중 |
| 트래픽 정책 | 매우 풍부 (VirtualService, DestinationRule, Gateway) | 핵심 (TrafficSplit, HTTPRoute) | 풍부 (Intentions, Service Router) | 중간 |
| 보안 | mTLS + AuthorizationPolicy + JWT | mTLS + Server Authorization | mTLS + Intentions | mTLS + TrafficPermission |
| 학습 곡선 | 가파름 | 완만 | 중간 | 중간 |
| 리소스 오버헤드 | 높음 (~50-100m CPU, ~100-200Mi memory per sidecar) | 낮음 (~10m CPU, ~20Mi memory) | 중간 | 중간 |
| CNCF | Graduated | Graduated | - (HashiCorp) | Sandbox (→ Graduated 준비 중) |
| 멀티클러스터 | 지원 (Federation, Multi-primary) | 지원 (Multi-cluster) | 지원 (WAN Federation) | 지원 (Multi-zone) |
| VM 지원 | 지원 (WorkloadEntry) | 미지원 | 지원 (네이티브) | 지원 (Universal mode) |
선택 기준 요약:
- Istio: 기능이 가장 풍부하고 세밀한 제어가 필요한 대규모 프로덕션. 학습 비용을 감수할 수 있는 팀
- Linkerd: 빠른 도입, 낮은 리소스 오버헤드, 핵심 기능만 필요한 경우. CNCF Graduated로 커뮤니티 안정적
- Consul Connect: Kubernetes + VM 하이브리드 환경. HashiCorp 에코시스템(Vault, Nomad) 사용 시
- Kuma: Envoy 기반이지만 Istio보다 간단한 설정을 원하는 경우. 멀티존 아키텍처
11. 활용 시 주의점
11.1 사이드카 리소스 오버헤드
모든 Pod에 Envoy 프록시가 추가되므로 클러스터 전체의 리소스 사용량이 증가한다.
| 항목 | 기본값 | 프로덕션 권장 |
|---|---|---|
| CPU Request | 100m | 서비스 트래픽에 따라 조정 |
| CPU Limit | 2000m | 500m ~ 1000m |
| Memory Request | 128Mi | 서비스 엔드포인트 수에 따라 조정 |
| Memory Limit | 1Gi | 256Mi ~ 512Mi |
1
2
3
4
5
6
7
8
9
10
11
12
13
# 사이드카 리소스 제한 (annotation)
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/proxyCPU: "100m"
sidecar.istio.io/proxyCPULimit: "500m"
sidecar.istio.io/proxyMemory: "128Mi"
sidecar.istio.io/proxyMemoryLimit: "256Mi"
spec:
containers:
- name: app
image: app:v1
11.2 정책 기본값 설계
프로덕션 환경에서는 “기본 거부(deny by default)” 원칙을 적용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Step 1: Mesh-wide STRICT mTLS
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
---
# Step 2: Namespace deny-all
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: production
spec:
{}
---
# Step 3: 필요한 통신만 ALLOW
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/frontend"]
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/*"]
11.3 앱 장애 vs 메시 장애 분리 관찰
트래픽이 프록시를 경유하므로, 장애 발생 시 원인이 애플리케이션인지 Envoy/istiod인지 구분이 필요하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1) 프록시 상태 확인
istioctl proxy-status
# 2) 특정 Pod의 Envoy 설정 동기화 상태
istioctl analyze -n <namespace>
# 3) Envoy 내부 통계 직접 확인
kubectl exec <pod> -c istio-proxy -- pilot-agent request GET /stats
# 4) istiod 로그 확인 (push 실패 등)
kubectl logs -n istio-system -l app=istiod --tail=100
# 5) 프록시 로그 레벨 변경 (디버깅)
istioctl proxy-config log <pod> --level debug
11.4 Envoy 버전 호환성 확인
Istio 버전과 Envoy 버전의 호환성을 반드시 확인해야 한다. Istio는 특정 Envoy 버전과 함께 빌드/테스트되므로, 임의로 Envoy 버전을 변경하면 예기치 않은 동작이 발생할 수 있다.
1
2
3
4
5
# 현재 사용 중인 Envoy 버전 확인
istioctl version
# Pod별 Envoy 버전 확인
kubectl exec <pod> -c istio-proxy -- envoy --version
11.5 Large-scale 환경에서 xDS Push 최적화
서비스 수가 많은 클러스터에서는 Sidecar 리소스로 각 프록시의 xDS 범위를 제한해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
# 네임스페이스 기본 Sidecar (모든 Pod에 적용)
apiVersion: networking.istio.io/v1
kind: Sidecar
metadata:
name: default
namespace: bookinfo
spec:
egress:
- hosts:
- "./*" # 같은 네임스페이스
- "istio-system/*" # istio-system
- "monitoring/*" # 모니터링
# 전체 메시 대신 필요한 네임스페이스만 포함
xDS push 최적화 효과:
- 메모리: 전체 메시 설정 대신 관련 서비스 설정만 보유 (수십 배 절감 가능)
- CPU: 설정 변경 시 영향받는 프록시만 push
- 네트워크: xDS 트래픽 감소
11.6 업그레이드 전략 (Canary Revision)
Istio 업그레이드는 canary revision을 사용하여 점진적으로 수행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1) 새 revision 설치
istioctl install --set revision=1-22-0
# 2) 네임스페이스에 새 revision label 적용
kubectl label namespace bookinfo istio.io/rev=1-22-0 --overwrite
# 기존 istio-injection=enabled label 제거
kubectl label namespace bookinfo istio-injection-
# 3) 워크로드 재시작 (새 사이드카 주입)
kubectl rollout restart deployment -n bookinfo
# 4) 검증 후 이전 revision 제거
istioctl uninstall --revision 1-21-0
graph LR
subgraph Before["업그레이드 전"]
Old["istiod 1.21<br/>(stable)"]
PodOld1["Pod (1.21 sidecar)"]
PodOld2["Pod (1.21 sidecar)"]
end
subgraph During["Canary 진행 중"]
OldD["istiod 1.21<br/>(stable)"]
NewD["istiod 1.22<br/>(canary)"]
PodD1["Pod (1.21 sidecar)"]
PodD2["Pod (1.22 sidecar)"]
end
subgraph After["업그레이드 완료"]
New["istiod 1.22<br/>(stable)"]
PodNew1["Pod (1.22 sidecar)"]
PodNew2["Pod (1.22 sidecar)"]
end
Before --> During --> After
12. 부수 개념
12.1 xDS (x Discovery Service)
xDS API는 Envoy가 설정을 동적으로 발견하는 방법을 제공한다.
xDS는 Envoy의 동적 설정 프로토콜의 총칭이다. ‘x’는 L(Listener), R(Route), C(Cluster), E(Endpoint), S(Secret) 등 다양한 디스커버리 서비스를 의미한다. gRPC 양방향 스트림 기반으로 동작하며, Envoy와 컨트롤 플레인 간 실시간 설정 동기화를 담당한다.
12.2 SPIFFE / SPIRE
SPIFFE는 현대적이고 동적인 인프라의 모든 워크로드에 특별히 제작된 X.509 인증서 형태의 보안 ID를 제공한다.
- SPIFFE: ID 표준 (spiffe://trust-domain/path 형식)
- SPIRE: SPIFFE 구현체 (identity attestation, certificate issuance)
- Istio는 자체 Citadel에서 SPIFFE 호환 인증서를 발급하며, SPIRE와도 통합 가능하다
12.3 Envoy Filter
EnvoyFilter는 istiod가 생성하는 Envoy 설정을 직접 패치하는 고급 CRD이다. VirtualService나 DestinationRule로 표현할 수 없는 Envoy 네이티브 설정을 적용할 때 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-lua-filter
namespace: bookinfo
spec:
workloadSelector:
labels:
app: productpage
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(handle)
handle:headers():add("x-custom-header", "added-by-envoy")
end
주의: EnvoyFilter는 Istio 버전 업그레이드 시 호환성이 깨질 수 있으므로, 가능하면 VirtualService/DestinationRule 등 상위 API를 우선 사용해야 한다.
12.4 WebAssembly Plugin
WasmPlugin은 WebAssembly 필터를 통해 Istio 프록시의 기능을 확장하는 메커니즘을 제공한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: custom-auth
namespace: bookinfo
spec:
selector:
matchLabels:
app: productpage
url: oci://ghcr.io/my-org/custom-auth-wasm:v1.0
phase: AUTHN # 인증 단계에서 실행
pluginConfig:
api_key_header: "x-api-key"
WebAssembly 플러그인의 장점:
- EnvoyFilter보다 안전한 확장 방식 (샌드박스 실행)
- 다양한 언어로 작성 가능 (Rust, Go, C++ 등 → Wasm 컴파일)
- OCI 레지스트리에서 배포 가능
- Hot reload 지원
12.5 Istio CNI
Istio CNI 플러그인은 istio-init 컨테이너의 필요성을 제거한다.
istio-init container는 iptables 규칙을 설정하기 위해 NET_ADMIN과 NET_RAW capability가 필요하다. 보안 정책이 엄격한 환경(PodSecurityPolicy, PSA restricted)에서는 이것이 문제가 된다. Istio CNI 플러그인은 노드 레벨에서 네트워크 규칙을 설정하므로 init container가 불필요해진다.
12.6 Multi-cluster Mesh
Istio는 여러 클러스터에 걸쳐 설정할 수 있다.
| 모델 | 설명 | 적합한 상황 |
|---|---|---|
| Multi-primary | 각 클러스터에 istiod, 상호 설정 공유 | HA, 지역 분산 |
| Primary-remote | 한 클러스터에만 istiod, 나머지는 remote | 중앙 관리, 허브-스포크 |
| External Control Plane | 외부에 istiod, 모든 클러스터가 remote | 관리형 서비스, SaaS |
13. 실무 체크리스트
Istio Sidecar 모드를 프로덕션에 도입할 때 점검해야 할 항목을 정리한다.
설치 및 초기 설정
- Istio 프로파일 선택 (demo, default, minimal, ambient)
- istiod 리소스 설정 (CPU/Memory request/limit)
- Ingress Gateway 배포 및 LoadBalancer/NodePort 설정
- Istio CNI 사용 여부 결정 (보안 요구사항에 따라)
- 네임스페이스 라벨링 전략 수립 (
istio-injection=enabled또는 revision label)
트래픽 관리
- VirtualService/DestinationRule 기본 템플릿 작성
- 타임아웃 기본값 설정 (서비스별 SLA 기반)
- 재시도 정책 설정 (idempotent 요청만 재시도)
- 서킷 브레이커 임계값 설정 (connectionPool, outlierDetection)
- Sidecar 리소스로 xDS scope 제한 (서비스 50개 이상일 때)
- ServiceEntry로 외부 서비스 명시적 등록
보안
- PeerAuthentication mesh-wide STRICT 적용
- AuthorizationPolicy deny-all 기본 정책 적용
- 필요한 통신 경로만 ALLOW 정책 추가
- RequestAuthentication 설정 (외부 API 엔드포인트)
- 인증서 로테이션 주기 확인 (기본 24시간)
Observability
- Prometheus 메트릭 수집 설정
- Grafana Istio 대시보드 배포
- 분산 추적 백엔드 설정 (Jaeger, Tempo, Zipkin)
- 애플리케이션 트레이스 헤더 전파 구현
- 액세스 로그 설정 (에러만 로깅 또는 전체)
- Kiali 서비스 토폴로지 대시보드 배포
리소스 및 성능
- 사이드카 리소스 제한 설정 (annotation 또는 global)
- 사이드카 제외 대상 설정 (DaemonSet, batch Job 등)
- HPA 설정 시 사이드카 리소스 고려
- 프록시 동시성(concurrency) 설정 (기본 2 worker threads)
운영
- Canary revision 기반 업그레이드 절차 수립
- istioctl analyze 기반 설정 검증 자동화
- istioctl proxy-status 모니터링 (SYNCED 상태 확인)
- istiod HA 구성 (replicas >= 2)
- Envoy 드레인 타임아웃 설정 (graceful shutdown)
- 장애 시 사이드카 바이패스 절차 문서화
정리하며
처음 던진 질문들에 대한 답이다.
코드를 안 고치는데 어떻게 프록시를 지나가는가. 파드가 만들어질 때 웹훅이 끼어들어 프록시 컨테이너와 초기화 컨테이너를 파드 정의에 끼워 넣는다. 초기화 컨테이너가 파드의 네트워크 이름공간에서 iptables 규칙을 심어서, 들어오고 나가는 트래픽을 전부 프록시 포트로 돌린다. 애플리케이션은 여전히 원래 주소로 연결하지만 커널이 경로를 바꾼다.
컨트롤 플레인이 설정을 어떻게 전달하는가. xDS라는 프로토콜로 전달한다. 프록시가 컨트롤 플레인에 연결을 열어두고, 설정이 바뀌면 컨트롤 플레인이 밀어준다. 폴링이 아니라 밀어주는 방식이라 반영이 빠르고, 프록시를 재시작할 필요가 없다.
mTLS 인증서는 누가 만들고 언제 갱신되는가. 컨트롤 플레인이 인증 기관 역할을 한다. 프록시가 자기 신원을 증명하는 요청을 보내면 짧은 수명의 인증서를 발급해준다. 수명이 짧기 때문에 프록시가 알아서 주기적으로 다시 받아간다. 사람이 갱신할 일이 없고, 유출돼도 금방 만료된다.
사이드카의 비용. 파드마다 프록시가 하나씩 더 뜨므로 메모리와 CPU가 그만큼 곱해진다. 그리고 요청이 프록시를 두 번 지나가므로(보내는 쪽과 받는 쪽) 지연이 붙는다. 파드 수가 많은 클러스터에서는 이 곱셈이 무시할 수 없는 크기가 된다. Ambient 모드가 나온 이유가 여기 있고, 따로 정리한 글에서 다뤘다.
문서를 따라가면서 가장 크게 남은 것은 서비스 메시가 새로운 기능을 주는 것이 아니라 이미 하던 일을 옮기는 것이라는 감각이었다. 재시도, 타임아웃, 회로 차단기, TLS, 추적은 전부 애플리케이션에서 하던 일이다. 그것을 프록시로 옮기면 언어와 무관해지고 설정으로 바뀌는 대신, 프록시라는 새 운영 대상이 생긴다.