Kubernetes 서비스 메시 핵심 기술
TL;DR
- HTTP/2 – 멀티플렉싱과 바이너리 프레이밍 3.
- 원문 전체는 아래 상세 내용에 그대로 포함했다.
1. 개념
HTTP/2 – 멀티플렉싱과 바이너리 프레이밍 3.
2. 배경
3. 이유
4. 특징
5. 상세 내용
Kubernetes 서비스 메시 핵심 기술
목차
- 개요
- HTTP/2 – 멀티플렉싱과 바이너리 프레이밍
- mTLS – 제로 트러스트 보안의 핵심
- Waypoint Proxy – Ambient Mesh의 L7 처리기
- Circuit Breaker – 연쇄 장애 방지
- 4가지 기술 통합 아키텍처
- 실전 시나리오별 적용 가이드
- YAML 설정 레퍼런스
- 프로덕션 체크리스트
- 기술 선택 가이드
- 자주 묻는 질문 (FAQ)
- 요약 및 키워드
1. 개요
Kubernetes 서비스 메시에서 가장 중요한 4가지 핵심 기술을 다룬다. 이 문서는 각 기술의 등장 배경, 동작 원리, K8s에서의 구현 방법, 그리고 실전 적용 패턴까지 포괄한다.
1.1 핵심 기술 관계도
┌──────────────────────────────────────────────────────────────────────┐
│ K8s 서비스 메시 핵심 기술 관계도 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ HTTP/2 │────────►│ mTLS │ │
│ │ (전송 프로토콜)│ │ (보안 계층) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ HTTP/2가 mTLS의 │ mTLS가 Waypoint│ │
│ 전송 기반 제공 │ 간 터널 보호 │ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Waypoint │◄────────│ Circuit │ │
│ │ Proxy │ │ Breaker │ │
│ │ (L7 처리 엔진)│ │ (장애 격리) │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ 관계 요약: │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ HTTP/2 → mTLS 위에서 바이너리 프레임 전송 │ │
│ │ mTLS → ztunnel/Waypoint 간 HBONE 터널 암호화 │ │
│ │ Waypoint → HTTP/2 프레임 파싱 후 L7 정책 적용 │ │
│ │ Circuit → Waypoint 내부에서 장애 엔드포인트 격리 │ │
│ │ Breaker │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
1.2 각 기술 한 줄 요약
| 기술 | 핵심 가치 | 한 줄 요약 |
|---|---|---|
| HTTP/2 | 전송 효율 | 하나의 TCP 연결에서 다수 요청을 동시에 처리 (멀티플렉싱) |
| mTLS | 보안 | 서비스 간 상호 인증 + 암호화로 Zero Trust 네트워크 구현 |
| Waypoint Proxy | L7 처리 | Sidecar 없이 L7 트래픽 관리를 수행하는 Ambient Mesh의 핵심 컴포넌트 |
| Circuit Breaker | 장애 격리 | 장애 서비스로의 요청을 차단하여 연쇄 장애(cascading failure) 방지 |
2. HTTP/2 – 멀티플렉싱과 바이너리 프레이밍
2.1 왜 등장했는가: HTTP/1.1 Head-of-Line Blocking
HTTP/1.1에서는 하나의 TCP 연결에서 요청/응답이 순차적으로 처리된다. 앞의 요청이 완료되기 전까지 뒤의 요청이 블로킹되는 문제가 Head-of-Line(HOL) Blocking이다.
┌───────────────────────────────────────────────────────────────┐
│ HTTP/1.1 Head-of-Line Blocking 문제 │
├───────────────────────────────────────────────────────────────┤
│ │
│ 클라이언트 서버 │
│ │ │ │
│ │──── GET /api/orders ──────────────►│ │
│ │ (대용량 응답) │ │
│ │◄─── 200 OK (100KB) ───────────────│ ← 3초 소요 │
│ │ │ │
│ │──── GET /api/users ───────────────►│ ← 3초 대기! │
│ │◄─── 200 OK (1KB) ────────────────│ ← 실제 처리 10ms │
│ │ │ │
│ 문제: /users 요청은 1KB 응답인데 3초를 대기 │
│ │
│ 해결 시도: 병렬 TCP 연결 (브라우저 기본 6개) │
│ ┌─ Connection 1: GET /api/orders │
│ ├─ Connection 2: GET /api/users │
│ ├─ Connection 3: GET /api/products │
│ ├─ Connection 4: GET /api/cart │
│ ├─ Connection 5: GET /api/reviews │
│ └─ Connection 6: GET /api/recommendations │
│ │
│ 문제점: │
│ - 각 연결마다 TCP 3-way handshake + TLS handshake 비용 │
│ - 서버 소켓/메모리 리소스 6배 소비 │
│ - 연결 수 제한으로 7번째 요청부터 다시 HOL Blocking │
└───────────────────────────────────────────────────────────────┘
2.2 HTTP/2의 등장 배경
HTTP/2는 Google SPDY 프로토콜에서 시작되었다.
- 2009: Google이 SPDY 실험 시작
- 2009-2015: SPDY 실험 결과 11~47% 페이지 로드 성능 개선 입증
- 2015.05: SPDY 기반으로 RFC 7540 (HTTP/2) 표준화
- 2022: RFC 9113으로 HTTP/2 업데이트
| 버전 | 연도 | 표준 | 핵심 변화 |
|---|---|---|---|
| HTTP/1.0 | 1996 | RFC 1945 | 요청/응답 모델, 비지속 연결 |
| HTTP/1.1 | 1997 | RFC 2068 | 지속 연결(Keep-Alive), 파이프라이닝 |
| HTTP/2 | 2015 | RFC 7540 | 바이너리 프레이밍, 멀티플렉싱 |
| HTTP/3 | 2022 | RFC 9114 | QUIC/UDP 기반, UDP 위의 멀티플렉싱 |
2.3 핵심 기능
Binary Framing Layer
HTTP/1.1의 텍스트 기반 프로토콜을 바이너리 프레이밍 계층으로 대체한다.
┌───────────────────────────────────────────────────────┐
│ HTTP/2 Binary Frame 구조 │
├───────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Length (24 bit) │ │
│ ├─────────────────────────────────────────────┤ │
│ │ Type (8 bit) │ Flags (8 bit) │ │
│ ├─────────────────────────────────────────────┤ │
│ │ R │ Stream Identifier (31 bit) │ │
│ ├─────────────────────────────────────────────┤ │
│ │ Frame Payload (가변 길이) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ 주요 프레임 타입: │
│ - HEADERS : 요청/응답 헤더 │
│ - DATA : 본문 데이터 │
│ - SETTINGS : 연결 설정 │
│ - WINDOW_UPDATE : 흐름 제어 │
│ - PUSH_PROMISE : 서버 푸시 예약 │
│ - RST_STREAM : 스트림 취소 │
│ - PING : 연결 유지 확인 │
│ - GOAWAY : 연결 종료 알림 │
└───────────────────────────────────────────────────────┘
Multiplexing (멀티플렉싱)
하나의 TCP 연결에서 여러 스트림이 독립적으로 동작한다. HTTP/1.1에서 4~8개 필요했던 병렬 연결이 1개로 축소된다.
┌───────────────────────────────────────────────────────┐
│ HTTP/2 Multiplexing 동작 원리 │
├───────────────────────────────────────────────────────┤
│ │
│ 하나의 TCP 연결: │
│ ┌─────────────────────────────────────────────┐ │
│ │ Stream 1 [HEADERS]──[DATA]──[DATA]──[END] │ │
│ │ Stream 3 [HEADERS]──[DATA]──[END] │ │
│ │ Stream 5 [HEADERS]──[DATA]──[DATA]──[END] │ │
│ │ Stream 7 [HEADERS]──[END] │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ 프레임 인터리빙 (실제 전송 순서): │
│ [S1:H][S3:H][S1:D][S5:H][S3:D][S5:D][S7:H]... │
│ │
│ 각 스트림은 독립적 → 하나가 느려도 다른 것에 영향 X │
└───────────────────────────────────────────────────────┘
HPACK 헤더 압축 (RFC 7541)
HTTP/2 전용 헤더 압축 알고리즘이다.
- 정적 사전: 61개 사전 정의 항목 (
:method GET,:status 200등) - 동적 사전: 연결 내에서 새로운 헤더를 학습하여 인덱스로 참조
- Huffman 인코딩: 자주 사용되는 문자에 짧은 코드 할당
Cloudflare 측정 결과: 평균 69% 압축률 달성.
Server Push
PUSH_PROMISE 프레임으로 클라이언트가 요청하기 전에 리소스를 미리 전송한다. 브라우저에서는 Chrome이 2022년에 지원을 제거했으나, 서버-서버 통신(gRPC Server Streaming 등)에서는 여전히 유용하다.
Stream 우선순위
스트림에 의존성과 가중치를 설정하여 중요한 요청을 우선 처리할 수 있다.
2.4 h2 vs h2c (TLS 유무)
| 항목 | h2 (HTTP/2 over TLS) | h2c (HTTP/2 Cleartext) |
|---|---|---|
| TLS | 필수 (ALPN으로 협상) | 불필요 (평문) |
| 포트 | 443 (일반적) | 80 또는 임의 |
| 보안 | 암호화 + 인증 | 없음 |
| 성능 | TLS 핸드셰이크 오버헤드 | 오버헤드 없음 |
| K8s 내부 | Service Mesh mTLS 사용 시 | Pod 간 직접 통신 시 |
| 프로토콜 협상 | TLS ALPN | HTTP Upgrade 또는 Prior Knowledge |
┌───────────────────────────────────────────────────────┐
│ h2 vs h2c 프로토콜 협상 │
├───────────────────────────────────────────────────────┤
│ │
│ h2 (TLS 있음): │
│ Client ──TLS ClientHello (ALPN: h2)──► Server │
│ Client ◄──TLS ServerHello (ALPN: h2)── Server │
│ → TLS 핸드셰이크에서 HTTP/2 합의 │
│ │
│ h2c (TLS 없음 - HTTP Upgrade): │
│ Client ──GET / HTTP/1.1 │
│ Connection: Upgrade │
│ Upgrade: h2c ──────────────► Server │
│ Client ◄──101 Switching Protocols──── Server │
│ → HTTP/1.1에서 HTTP/2로 업그레이드 │
│ │
│ h2c (TLS 없음 - Prior Knowledge): │
│ Client ──HTTP/2 Connection Preface──► Server │
│ → 서버가 h2c 지원을 미리 알고 있으면 바로 HTTP/2 │
│ → K8s Service Mesh에서 주로 사용 │
└───────────────────────────────────────────────────────┘
K8s에서의 적용:
- Service Mesh 사용 시: Pod 간 통신은 h2c, mTLS는 Sidecar/ztunnel이 처리
- Service Mesh 미사용 시: 보안이 필요하면 h2 (애플리케이션 레벨 TLS)
- K8s Service 설정:
appProtocol: kubernetes.io/h2c또는 포트명http2-*
2.5 Kubernetes에서의 과제: kube-proxy L4 로드밸런싱
K8s 환경에서 HTTP/2를 사용할 때 가장 심각한 문제는 로드밸런싱 불균형이다.
┌───────────────────────────────────────────────────────┐
│ kube-proxy의 L4 로드밸런싱 한계 │
├───────────────────────────────────────────────────────┤
│ │
│ kube-proxy = L4 (TCP 연결 단위) 로드밸런싱 │
│ HTTP/2 = 하나의 TCP 연결에 수백 개 요청 │
│ │
│ 결과: 모든 요청이 최초 연결된 Pod 하나에 집중 │
│ │
│ order-service (클라이언트) │
│ │ │
│ │ TCP 연결 1개 (HTTP/2 멀티플렉싱) │
│ │ → 100개의 gRPC 호출이 모두 이 연결 사용 │
│ │ │
│ ▼ │
│ kube-proxy (iptables/IPVS) │
│ │ │
│ │ TCP 연결 수립 시 1번만 Pod 선택 │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Pod A │ │ Pod B │ │ Pod C │ │
│ │ 100 요청 │ │ 0 요청 │ │ 0 요청 │ │
│ │ CPU 90% │ │ CPU 5% │ │ CPU 5% │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Pod A만 과부하, Pod B/C는 유휴 상태 → HPA 비정상 │
└───────────────────────────────────────────────────────┘
영향범위:
- gRPC 서비스 (HTTP/2 필수)
- HTTP/2를 명시적으로 설정한 REST 서비스
- WebSocket 등 long-lived 연결 서비스
2.6 해결 방법
방법 1: Istio DestinationRule (L7 로드밸런싱)
# Istio가 HTTP/2 프레임 단위로 로드밸런싱
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: order-service-lb
namespace: production
spec:
host: order-service
trafficPolicy:
connectionPool:
http:
h2UpgradePolicy: UPGRADE # HTTP/2 업그레이드 강제
http2MaxRequests: 1000 # 동시 요청 제한
maxRequestsPerConnection: 100 # 연결당 100 요청 후 재연결 → 재분배
loadBalancer:
simple: ROUND_ROBIN # L7 라운드 로빈
방법 2: gRPC Client-side 로드밸런싱
# Headless Service (ClusterIP: None)
apiVersion: v1
kind: Service
metadata:
name: order-service-headless
spec:
clusterIP: None # DNS가 모든 Pod IP 반환
selector:
app: order-service
ports:
- name: grpc
port: 50051
appProtocol: kubernetes.io/h2c
// gRPC 클라이언트 설정 (Go)
// DNS resolver + round_robin 로드밸런싱
conn, err := grpc.Dial(
"dns:///order-service-headless.production.svc.cluster.local:50051",
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
방법 3: MaxConnectionAge (서버측)
// gRPC 서버에서 연결 수명 제한
// 주기적으로 연결이 끊기면 kube-proxy가 새 Pod에 재연결
server := grpc.NewServer(
grpc.KeepaliveParams(keepalive.ServerParameters{
MaxConnectionAge: 5 * time.Minute, // 5분마다 연결 갱신
MaxConnectionAgeGrace: 30 * time.Second, // 진행 중 요청 완료 유예
}),
)
방법 4: Linkerd L7 로드밸런싱
Linkerd는 자동으로 HTTP/2 요청 단위 로드밸런싱을 수행한다. 별도 설정 없이 Linkerd Sidecar가 주입되면 HTTP/2 멀티플렉싱 문제가 해결된다.
2.7 서비스 메시별 HTTP/2 벤치마크 (arXiv 2411.02267)
실제 벤치마크 연구에서 측정한 서비스 메시별 성능 오버헤드이다.
┌───────────────────────────────────────────────────────────────┐
│ 서비스 메시 성능 벤치마크 (arXiv 2411.02267) │
├───────────────────────────────────────────────────────────────┤
│ │
│ P99 지연시간 증가율 (베이스라인 대비): │
│ │
│ Istio Sidecar ████████████████████████████████ +166% │
│ Cilium ██████████████████████ +99% │
│ Linkerd ████████████████ +33% (*) │
│ Istio Ambient ██ +8% │
│ │
│ (*) Linkerd: P99 +33%이지만 P50에서는 가장 낮은 오버헤드 │
│ │
│ 핵심 인사이트: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Istio Ambient(ztunnel L4)는 L7 파싱을 하지 않아 │ │
│ │ 오버헤드가 가장 낮다 (+8%). │ │
│ │ L7 기능(Waypoint)을 추가하면 오버헤드가 증가하지만, │ │
│ │ 필요한 서비스에만 선택적으로 적용 가능하다. │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 메모리 사용량 (Pod당): │
│ Istio Sidecar ~60-100MB (Envoy per Pod) │
│ Linkerd ~20-30MB (Linkerd-proxy per Pod) │
│ Istio Ambient ~10-15MB (ztunnel per Node, 공유) │
│ Cilium ~0MB (eBPF, 커널 내 처리) │
└───────────────────────────────────────────────────────────────┘
2.8 HTTP/3 (QUIC) 미래 전망
HTTP/2의 TCP-level HOL Blocking을 해결하기 위해 QUIC(UDP) 위에 구축된 HTTP/3가 등장했다.
HTTP/2의 남은 문제:
HTTP/2는 애플리케이션 레벨 HOL Blocking은 해결했지만, TCP 레벨의 HOL Blocking은 여전히 존재한다. TCP 패킷 하나가 유실되면 그 위의 모든 HTTP/2 스트림이 블로킹된다.
현재 채택 현황 (Cloudflare Radar 2025):
| 프로토콜 | 글로벌 트래픽 비율 |
|---|---|
| HTTP/1.x | 8% |
| HTTP/2 | 67% |
| HTTP/3 | 25% |
K8s 생태계 지원 현황:
| 구성요소 | HTTP/3 지원 수준 |
|---|---|
| Envoy (다운스트림) | GA |
| Envoy (업스트림) | Alpha |
| Istio Gateway | Alpha/Experimental |
| Istio 내부 통신 | 미지원 |
| NGINX Ingress | 실험적 |
권장 사항 (2026년 현재):
- 외부 에지(CDN, API Gateway): HTTP/3 적용 검토 가능
- 내부 서비스 간 통신: 아직 HTTP/2가 안정적. HTTP/3 미채택 권장
- 모바일 클라이언트: HTTP/3의 연결 마이그레이션이 유리 (네트워크 전환 시)
3. mTLS – 제로 트러스트 보안의 핵심
3.1 왜 등장했는가: 경계 기반 보안의 한계
기존 보안 모델은 경계(perimeter) 를 기준으로 내부/외부를 구분했다. K8s 클러스터 내부는 “신뢰할 수 있는 영역”으로 간주하고, 서비스 간 통신은 평문(HTTP)이었다.
┌───────────────────────────────────────────────────────────────┐
│ 경계 기반 보안 vs Zero Trust │
├───────────────────────────────────────────────────────────────┤
│ │
│ [경계 기반 보안 - 기존 모델] │
│ │
│ ┌─── 방화벽 ──────────────────────────────────────┐ │
│ │ "클러스터 내부 = 신뢰" │ │
│ │ │ │
│ │ order-svc ──HTTP(평문)──► payment-svc │ │
│ │ │ │ │
│ │ └──HTTP(평문)──► user-svc │ │
│ │ │ │
│ │ 위험: 내부 침입자가 트래픽 도청/변조 가능 │ │
│ │ 위험: Pod 간 네트워크는 기본적으로 암호화 없음 │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ [Zero Trust 모델 - mTLS 적용] │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ "아무것도 신뢰하지 않는다" │ │
│ │ │ │
│ │ order-svc ──mTLS──► payment-svc │ │
│ │ (SPIFFE ID) (상호 인증 + 암호화) (SPIFFE ID) │ │
│ │ │ │ │
│ │ └──mTLS──► user-svc │ │
│ │ (SPIFFE ID) │ │
│ │ │ │
│ │ 모든 통신: 인증 + 암호화 + 인가 │ │
│ └──────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
K8s 기본 네트워킹의 위험:
| 위협 | K8s 기본 상태 | mTLS 적용 후 |
|---|---|---|
| 도청 (Eavesdropping) | 평문 트래픽 노출 | AES-GCM 암호화로 불가 |
| 스푸핑 (Spoofing) | IP 위변조 가능 | X.509 인증서로 신원 검증 |
| 중간자 공격 (MITM) | 방어 없음 | 상호 인증서 검증으로 차단 |
| 리플레이 (Replay) | 방어 없음 | TLS 세션 키로 무효화 |
| 비인가 접근 | NetworkPolicy만 | SPIFFE ID 기반 인가 정책 |
3.2 단방향 TLS vs 양방향 mTLS 비교
┌───────────────────────────────────────────────────────────────┐
│ TLS vs mTLS 핸드셰이크 비교 │
├───────────────────────────────────────────────────────────────┤
│ │
│ [단방향 TLS - 일반 HTTPS] │
│ │
│ 클라이언트 서버 │
│ │──ClientHello────────────────►│ │
│ │◄──ServerHello + 서버 인증서──│ │
│ │ (서버 인증서 검증) │ │
│ │──Finished──────────────────►│ │
│ │ │ │
│ └─ 클라이언트 → 서버 인증: O │
│ └─ 서버 → 클라이언트 인증: X ← 서버는 클라이언트 모름 │
│ │
│ [양방향 mTLS - 서비스 메시] │
│ │
│ 클라이언트(order-svc) 서버(payment-svc) │
│ │──ClientHello────────────────►│ │
│ │◄──ServerHello + 서버 인증서──│ │
│ │ (서버 인증서 검증) │ │
│ │◄──CertificateRequest────────│ ← 클라이언트 인증서 요구│
│ │──클라이언트 인증서──────────►│ │
│ │ (클라이언트 인증서 검증) │
│ │──Finished──────────────────►│ │
│ │ │ │
│ └─ 클라이언트 → 서버 인증: O │
│ └─ 서버 → 클라이언트 인증: O ← 양쪽 모두 신원 확인 │
└───────────────────────────────────────────────────────────────┘
| 항목 | 단방향 TLS | 양방향 mTLS |
|---|---|---|
| 서버 인증 | O | O |
| 클라이언트 인증 | X | O |
| 인증서 관리 | 서버만 | 양쪽 모두 |
| K8s에서 사용 | Ingress (외부→클러스터) | Pod 간 내부 통신 |
| 주요 용도 | 브라우저-서버 HTTPS | Zero Trust 서비스 메시 |
3.3 SPIFFE/SPIRE 워크로드 아이덴티티
SPIFFE (Secure Production Identity Framework For Everyone)는 워크로드에 표준화된 아이덴티티를 부여하는 프레임워크이다.
┌───────────────────────────────────────────────────────────────┐
│ SPIFFE 아이덴티티 체계 │
├───────────────────────────────────────────────────────────────┤
│ │
│ SPIFFE ID 형식: │
│ spiffe://<trust-domain>/<workload-path> │
│ │
│ 예시: │
│ spiffe://cluster.local/ns/production/sa/order-service │
│ ├─ trust-domain : cluster.local │
│ ├─ namespace : production │
│ └─ service-acct : order-service │
│ │
│ SVID (SPIFFE Verifiable Identity Document): │
│ ┌──────────────────────────────────────────┐ │
│ │ X.509 인증서 내용: │ │
│ │ - Subject Alternative Name (SAN): │ │
│ │ URI: spiffe://cluster.local/ns/ │ │
│ │ production/sa/order-service │ │
│ │ - Issuer: Istio CA (istiod) │ │
│ │ - Not After: 24h (자동 갱신) │ │
│ │ - Key Algorithm: ECDSA P-256 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ PKI 계층: │
│ ┌─ Root CA (Istio 자체 CA 또는 외부 CA) │
│ ├─── Intermediate CA (istiod) │
│ │ ├─── Workload Cert (order-service) │
│ │ ├─── Workload Cert (payment-service) │
│ │ └─── Workload Cert (user-service) │
│ └─ Root CA는 10년, Workload Cert는 24시간 수명 │
└───────────────────────────────────────────────────────────────┘
SPIRE (SPIFFE Runtime Environment)는 SPIFFE를 구현한 런타임이다. Istio는 자체 SPIFFE 구현을 내장하고 있어 SPIRE 없이도 동작하지만, 멀티 클러스터에서는 SPIRE를 별도 사용하기도 한다.
| 구성요소 | 역할 | Istio에서의 대응 |
|---|---|---|
| SPIFFE ID | 워크로드 아이덴티티 표준 | SAN URI에 자동 포함 |
| SVID | 검증 가능한 인증서 | X.509 인증서 (24시간) |
| SPIRE Server | 인증서 발급 서버 | istiod (Citadel 통합) |
| SPIRE Agent | 노드별 인증서 배포 | istio-agent (Sidecar 내) / ztunnel (Ambient) |
3.4 Istio PeerAuthentication (STRICT / PERMISSIVE / DISABLE)
# 메시 전체 STRICT mTLS (가장 안전)
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: mesh-wide-strict
namespace: istio-system # istio-system = 메시 전체 적용
spec:
mtls:
mode: STRICT # 평문 요청 거부
| 모드 | 동작 | 사용 시점 |
|---|---|---|
| STRICT | mTLS만 허용. 평문 거부 | 프로덕션 안정화 후 |
| PERMISSIVE | mTLS + 평문 모두 허용 | 마이그레이션 중 |
| DISABLE | mTLS 비활성화 (평문만) | 특수한 경우만 |
| UNSET | 상위 정책 상속 | 기본값 |
적용 우선순위 (높은 순):
- 워크로드별 (selector 지정)
- 네임스페이스별 (namespace 지정, selector 없음)
- 메시 전체 (istio-system 네임스페이스)
# 프로덕션 네임스페이스: STRICT, 단 헬스체크 포트는 PERMISSIVE
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: production-strict
namespace: production
spec:
mtls:
mode: STRICT
portLevelMtls:
8080:
mode: PERMISSIVE # kubelet 헬스체크용 (mTLS 불가)
3.5 cert-manager 연동
외부 CA를 사용하거나 인증서 관리를 세밀하게 제어할 때 cert-manager를 Istio와 연동한다.
# cert-manager Issuer (Istio CA 대체)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: istio-ca
spec:
ca:
secretName: istio-ca-secret # Root CA 키 쌍
---
# Istio가 cert-manager를 CA로 사용하도록 설정
# istio-operator 또는 Helm values:
# pilot:
# env:
# EXTERNAL_CA: ISTIOD_RA_KUBERNETES_API
# K8S_RA_ISSUER_NAME: istio-ca
# K8S_RA_ISSUER_KIND: ClusterIssuer
# K8S_RA_ISSUER_GROUP: cert-manager.io
cert-manager 연동 장점:
| 항목 | Istio 기본 CA | cert-manager 연동 |
|---|---|---|
| Root CA 관리 | Istio 자동 생성 | 외부 CA (Vault, AWS ACM PCA 등) |
| 인증서 수명 | 24시간 (고정) | 커스텀 가능 |
| 갱신 방식 | istio-agent 자동 | cert-manager 자동 |
| 감사 추적 | 제한적 | cert-manager 이벤트/로그 |
| 멀티 클러스터 | 클러스터별 Root CA | 공유 Root CA 가능 |
3.6 Istio Ambient: ztunnel에서의 L4 mTLS
Ambient Mesh에서는 ztunnel(DaemonSet)이 노드 레벨에서 L4 mTLS를 처리한다.
┌───────────────────────────────────────────────────────────────┐
│ Ambient Mesh: ztunnel L4 mTLS │
├───────────────────────────────────────────────────────────────┤
│ │
│ Node A Node B │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │
│ │ │ order-svc │ │ │ │ payment-svc │ │ │
│ │ │ (Sidecar 없음)│ │ │ │ (Sidecar 없음)│ │ │
│ │ └──────┬───────┘ │ │ └──────▲───────┘ │ │
│ │ │ 평문 │ │ │ 평문 │ │
│ │ ▼ │ │ │ │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │
│ │ │ ztunnel │ │ │ │ ztunnel │ │ │
│ │ │ (DaemonSet) │───┼─mTLS──┼──│ (DaemonSet) │ │ │
│ │ │ HBONE:15008 │ │ │ │ HBONE:15008 │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ 장점: │
│ - Pod에 Sidecar 주입 불필요 │
│ - Pod 재시작 없이 mTLS 즉시 활성화 │
│ - 노드당 1개 ztunnel → 메모리 대폭 절감 │
│ - L4 only → P99 오버헤드 +8% (arXiv 2411.02267) │
└───────────────────────────────────────────────────────────────┘
3.7 성능 영향
mTLS 자체의 오버헤드는 미미하다.
| 항목 | 측정값 | 비고 |
|---|---|---|
| TLS 1.3 핸드셰이크 | 1-RTT (~1ms LAN) | 연결 수립 시 1회만 |
| AES-256-GCM 암호화 | ~1GB/s (CPU HW 가속) | 현대 CPU에서 무시할 수준 |
| P99 지연시간 증가 | +1~3% (L4 mTLS) | ztunnel 기준 |
| 메모리 (Sidecar 모드) | ~60-100MB/Pod | Envoy Sidecar 비용 |
| 메모리 (Ambient 모드) | ~10-15MB/Node | ztunnel 공유 |
실제 성능 병목은 mTLS 암호화가 아니라 L7 HTTP 파싱이다. Ambient ztunnel이 낮은 오버헤드를 보이는 이유는 L4에서만 동작하기 때문이다.
3.8 마이그레이션 전략: PERMISSIVE에서 STRICT로
┌───────────────────────────────────────────────────────────────┐
│ mTLS 마이그레이션 단계 (안전한 전환 절차) │
├───────────────────────────────────────────────────────────────┤
│ │
│ 1단계: 현황 파악 │
│ ├─ 비메시 클라이언트 식별 (모니터링, CI/CD, 외부 시스템) │
│ ├─ 헬스체크 포트 확인 (kubelet은 mTLS 불가) │
│ └─ 트래픽 메트릭 수집 (mTLS vs 평문 비율) │
│ │
│ 2단계: PERMISSIVE 적용 (메시 전체) │
│ ├─ mTLS + 평문 모두 허용 │
│ ├─ connection_security_policy 메트릭 모니터링 │
│ └─ 2주간 안정성 확인 │
│ │
│ 3단계: 네임스페이스별 STRICT 전환 │
│ ├─ 비핵심 네임스페이스부터 STRICT │
│ ├─ portLevelMtls로 헬스체크 포트 예외 처리 │
│ ├─ 에러 로그 모니터링 (connection reset, TLS handshake fail)│
│ └─ 문제 발생 시 즉시 PERMISSIVE로 롤백 │
│ │
│ 4단계: 메시 전체 STRICT │
│ ├─ istio-system에 STRICT PeerAuthentication 적용 │
│ ├─ 평문 트래픽 비율 0% 확인 │
│ └─ 완료 후 PERMISSIVE 정책 제거 (정리) │
└───────────────────────────────────────────────────────────────┘
# mTLS 적용 비율 모니터링 (Prometheus 쿼리)
# mTLS 연결 비율 확인
sum(istio_requests_total{connection_security_policy="mutual_tls"}) /
sum(istio_requests_total) * 100
# 평문 연결 추적 (STRICT 전환 전 0%여야 함)
sum(istio_requests_total{connection_security_policy!="mutual_tls"}) by (source_workload, destination_workload)
4. Waypoint Proxy – Ambient Mesh의 L7 처리기
4.1 왜 등장했는가: Sidecar 모델의 리소스 오버헤드
기존 Istio Sidecar 모델에서는 모든 Pod에 Envoy Proxy가 주입된다. Pod가 1,000개면 Envoy도 1,000개가 실행되며, 이는 상당한 리소스 낭비이다.
┌───────────────────────────────────────────────────────────────┐
│ Sidecar 모델의 문제점 │
├───────────────────────────────────────────────────────────────┤
│ │
│ [Sidecar 모델 - 기존] │
│ │
│ Pod 1 Pod 2 Pod 3 │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ App (50MB) │ │ App (80MB) │ │ App (30MB) │ │
│ │ Envoy(70MB)│ │ Envoy(70MB)│ │ Envoy(70MB)│ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ 문제점: │
│ - Pod 1000개 × Envoy 70MB = 약 70GB 메모리 소비 │
│ - Envoy 업그레이드 = 모든 Pod 재시작 (rolling restart) │
│ - L7 파싱이 불필요한 TCP-only 서비스에도 Envoy 주입 │
│ - 사이드카 주입 실패 시 서비스 장애 가능 │
│ - istio-init 컨테이너의 iptables 규칙으로 네트워크 복잡도 증가│
│ │
│ 벤치마크 (arXiv 2411.02267): │
│ Sidecar 모델 P99 지연시간: +166% (베이스라인 대비) │
└───────────────────────────────────────────────────────────────┘
4.2 Istio Ambient Mesh 2단계 아키텍처
Ambient Mesh는 프록시를 Pod에서 분리하여 2단계로 나눈다.
┌───────────────────────────────────────────────────────────────┐
│ Ambient Mesh 2단계 아키텍처 │
├───────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1단계: ztunnel (Zero Trust Tunnel) - L4 처리 │ │
│ │ │ │
│ │ - DaemonSet (노드당 1개) │ │
│ │ - L4 TCP 프록시 │ │
│ │ - mTLS 암호화/복호화 (SPIFFE ID) │ │
│ │ - L4 AuthorizationPolicy (IP/포트 기반) │ │
│ │ - L4 Telemetry (TCP 메트릭) │ │
│ │ - HBONE 터널링 (포트 15008) │ │
│ │ - Pod 재시작 불필요, 네임스페이스 레이블만으로 활성화 │ │
│ │ │ │
│ │ 성능: P99 +8% (매우 낮은 오버헤드) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 2단계: Waypoint Proxy - L7 처리 (선택적) │ │
│ │ │ │
│ │ - Deployment (네임스페이스당 또는 서비스당) │ │
│ │ - L7 HTTP/gRPC 파싱 │ │
│ │ - VirtualService (라우팅, Canary, A/B) │ │
│ │ - L7 AuthorizationPolicy (HTTP 메서드/경로 기반) │ │
│ │ - Circuit Breaker (outlierDetection) │ │
│ │ - Retry / Timeout │ │
│ │ - RequestAuthentication (JWT 검증) │ │
│ │ - L7 Telemetry (HTTP 메트릭, 트레이싱) │ │
│ │ │ │
│ │ L7이 필요한 서비스에만 선택적으로 배포 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 핵심 원리: "필요한 곳에만 L7 비용을 지불한다" │
└───────────────────────────────────────────────────────────────┘
4.3 HBONE 프로토콜 (HTTP CONNECT 기반 터널링)
HBONE (HTTP-Based Overlay Network Environment)은 ztunnel 간 통신에 사용되는 터널링 프로토콜이다.
┌───────────────────────────────────────────────────────────────┐
│ HBONE 프로토콜 동작 │
├───────────────────────────────────────────────────────────────┤
│ │
│ HBONE = HTTP/2 CONNECT 메서드 기반 터널 │
│ 포트: 15008 (ztunnel 전용) │
│ │
│ 1. ztunnel A가 ztunnel B에 HTTP/2 CONNECT 요청: │
│ CONNECT 10.0.1.5:8080 HTTP/2 │
│ Host: 10.0.1.5:8080 │
│ x-]envoy-peer-metadata: (원본 Pod 메타데이터) │
│ │
│ 2. ztunnel B가 200 OK 응답: │
│ HTTP/2 200 OK │
│ │
│ 3. 터널 수립 후 원본 TCP 데이터 투명 전달 │
│ │
│ 데이터 흐름: │
│ ┌────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐│
│ │ App A │─TCP─►│ztunnel A │─HBONE│ztunnel B │─TCP│ App B ││
│ │ │ │ mTLS암호화│:15008│ mTLS복호화│─► │ ││
│ └────────┘ └──────────┘ └──────────┘ └────────┘│
│ │
│ 장점: │
│ - 표준 HTTP/2 사용 → 기존 인프라(로드밸런서, 방화벽) 호환 │
│ - mTLS가 터널 레벨에서 적용 → 애플리케이션 무관 │
│ - HTTP/2 멀티플렉싱 → 다수 연결을 하나의 HBONE 터널로 공유 │
└───────────────────────────────────────────────────────────────┘
4.4 Gateway API 연동 (gateway.networking.k8s.io/Gateway)
Waypoint Proxy는 Kubernetes Gateway API 리소스로 선언한다.
# payment 네임스페이스에 Waypoint Proxy 배포
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
labels:
istio.io/waypoint-for: service # 서비스 레벨 Waypoint
name: payment-waypoint
namespace: payment
spec:
gatewayClassName: istio-waypoint # Istio Waypoint 클래스
listeners:
- name: mesh
port: 15008 # HBONE 포트
protocol: HBONE # HBONE 프로토콜
# istioctl로 Waypoint 배포 (간편 명령)
istioctl waypoint apply --namespace payment --name payment-waypoint
# 특정 서비스에 Waypoint 연결
kubectl label service payment-service \
istio.io/use-waypoint=payment-waypoint \
-n payment
Waypoint 적용 범위 제어:
| 레이블 | 위치 | 효과 |
|---|---|---|
istio.io/waypoint-for: service |
Gateway | 서비스 트래픽에 적용 |
istio.io/waypoint-for: workload |
Gateway | 워크로드(Pod) 트래픽에 적용 |
istio.io/waypoint-for: all |
Gateway | 모든 트래픽에 적용 |
istio.io/use-waypoint: <name> |
Service/Namespace | 특정 Waypoint 지정 |
4.5 Sidecar vs Ambient 비교
| 항목 | Sidecar 모델 | Ambient 모델 |
|---|---|---|
| 프록시 위치 | Pod 내부 (컨테이너) | 노드(ztunnel) + 네임스페이스(Waypoint) |
| L4 mTLS | Sidecar Envoy | ztunnel (DaemonSet) |
| L7 처리 | Sidecar Envoy | Waypoint Proxy (선택적) |
| 메모리 (1000 Pod) | ~70GB (70MB x 1000) | ~1.5GB (ztunnel 공유 + Waypoint 일부) |
| P99 오버헤드 | +166% (arXiv) | +8% (L4 only) |
| Pod 재시작 | Sidecar 주입/업그레이드 시 필요 | 불필요 |
| 활성화 방법 | Namespace 레이블 + Pod 재시작 | Namespace 레이블만 |
| EnvoyFilter | 지원 | 미지원 (WASM 대체) |
| 성숙도 | 프로덕션 검증 (2017~) | GA (Istio v1.24, Nov 2024) |
| 혼합 사용 | - | 같은 메시에서 Sidecar와 혼용 가능 |
4.6 리소스 절감 효과
┌───────────────────────────────────────────────────────────────┐
│ 리소스 절감 효과 (Sidecar → Ambient 전환) │
├───────────────────────────────────────────────────────────────┤
│ │
│ 사례: 500 Pod 클러스터 (10 노드, 50 Pod/노드) │
│ │
│ [Sidecar 모델] │
│ - Envoy: 500 x 70MB = 35,000 MB (35 GB) │
│ - Istio-init: 500 x 10MB = 5,000 MB (시작 시) │
│ - 총 메모리: ~35 GB (상시) │
│ │
│ [Ambient 모델 - L4 only] │
│ - ztunnel: 10 x 40MB = 400 MB │
│ - 총 메모리: ~400 MB (상시) │
│ - 절감: 약 98.9% │
│ │
│ [Ambient 모델 - L4 + Waypoint (30% 서비스)] │
│ - ztunnel: 10 x 40MB = 400 MB │
│ - Waypoint: 5 x 100MB = 500 MB │
│ - 총 메모리: ~900 MB (상시) │
│ - 절감: 약 97.4% │
│ │
│ 메모리 비교 (막대 그래프): │
│ Sidecar ████████████████████████████████████ 35,000 MB │
│ Ambient L4 █ 400 MB │
│ Ambient+WP ██ 900 MB │
│ │
│ 최대 90% 이상 메모리 절감 달성 │
└───────────────────────────────────────────────────────────────┘
4.7 Istio v1.24 GA 이후 프로덕션 전환 가이드
Istio v1.24 (2024년 11월)에서 Ambient Mesh가 GA(General Availability)로 승격되었다.
프로덕션 전환 단계:
┌───────────────────────────────────────────────────────────────┐
│ Sidecar → Ambient 프로덕션 전환 가이드 │
├───────────────────────────────────────────────────────────────┤
│ │
│ 사전 조건: │
│ ├─ Istio v1.24 이상 │
│ ├─ CNI 플러그인 호환성 확인 (Cilium, Calico 등) │
│ └─ HBONE 포트(15008) 방화벽/SecurityGroup 허용 │
│ │
│ 1단계: 비프로덕션 환경 테스트 (2주) │
│ ├─ dev/staging 네임스페이스에 ambient 레이블 적용 │
│ ├─ kubectl label ns dev istio.io/dataplane-mode=ambient │
│ ├─ 기존 사이드카 Pod과 Ambient Pod 간 통신 테스트 │
│ └─ L4 mTLS 메트릭 확인 │
│ │
│ 2단계: 비핵심 프로덕션 서비스 전환 (2주) │
│ ├─ 모니터링/로깅 등 비핵심 네임스페이스 전환 │
│ ├─ 사이드카 injection 비활성화 │
│ │ kubectl label ns monitoring istio-injection- │
│ ├─ Ambient 활성화 │
│ │ kubectl label ns monitoring istio.io/dataplane-mode=ambient│
│ └─ Pod 재시작으로 사이드카 제거 │
│ │
│ 3단계: L7 서비스에 Waypoint 배포 (1주) │
│ ├─ L7 정책이 필요한 서비스에만 Waypoint 추가 │
│ ├─ VirtualService, AuthorizationPolicy 동작 확인 │
│ └─ Waypoint HPA/리소스 설정 │
│ │
│ 4단계: 핵심 프로덕션 서비스 전환 (2주) │
│ ├─ 핵심 서비스 네임스페이스 순차 전환 │
│ ├─ 카나리 방식: 일부 Pod만 먼저 전환 │
│ └─ 모든 메트릭 안정 확인 후 전체 전환 │
│ │
│ 5단계: 정리 │
│ ├─ 모든 네임스페이스 ambient 확인 │
│ ├─ 불필요한 Sidecar 관련 리소스 정리 │
│ └─ istio-injection 관련 레이블/웹훅 제거 │
└───────────────────────────────────────────────────────────────┘
5. Circuit Breaker – 연쇄 장애 방지
5.1 왜 등장했는가: 마이크로서비스 연쇄 장애
마이크로서비스 아키텍처에서는 서비스 간 의존성이 복잡하다. 하나의 서비스 장애가 호출 체인을 따라 전파되어 전체 시스템 장애로 이어질 수 있다.
┌───────────────────────────────────────────────────────────────┐
│ 연쇄 장애 (Cascading Failure) 시나리오 │
├───────────────────────────────────────────────────────────────┤
│ │
│ 정상 상태: │
│ order-svc ──► payment-svc ──► bank-api (외부) │
│ 200 OK 200 OK 200 OK │
│ 응답: 50ms 응답: 100ms 응답: 200ms │
│ │
│ bank-api 장애 발생: │
│ order-svc ──► payment-svc ──► bank-api (외부) │
│ ??? (대기) ??? (대기) ✕ Timeout (30s) │
│ │
│ 연쇄 장애 전파: │
│ 1. bank-api 응답 없음 → payment-svc 스레드 고갈 │
│ 2. payment-svc 응답 없음 → order-svc 스레드 고갈 │
│ 3. order-svc 응답 없음 → frontend 장애 │
│ 4. frontend 장애 → 전체 서비스 중단 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ frontend │ │ order │ │ payment │ ┌──────────┐ │
│ │ ✕ │◄──│ ✕ │◄──│ ✕ │◄──│ bank-api │ │
│ │ 스레드 │ │ 스레드 │ │ 스레드 │ │ ✕ │ │
│ │ 풀 고갈 │ │ 풀 고갈 │ │ 풀 고갈 │ │ 원인 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 핵심 문제: 장애 서비스에 계속 요청을 보내서 리소스 낭비 │
└───────────────────────────────────────────────────────────────┘
5.2 Retry/Timeout만으로는 부족한 이유
| 패턴 | 대상 | 한계 |
|---|---|---|
| Timeout | 단일 요청의 대기 시간 제한 | 장애 서비스에 계속 요청 전송. 부하 가중 |
| Retry | 일시적(Transient) 장애 복구 | 지속적 장애 시 Retry Storm 발생. 부하 N배 증가 |
| Circuit Breaker | 지속적 장애 격리 | 장애 감지 시 요청 자체를 차단 (Fail-Fast). 복구 시간 확보 |
Timeout과 Retry는 일시적 장애에 효과적이지만, 지속적 장애에서는 오히려 상황을 악화시킨다. Circuit Breaker는 장애가 지속될 때 빠르게 실패하여 리소스를 보호한다.
5.3 상태 머신: Closed -> Open -> Half-Open
Circuit Breaker는 3가지 상태를 순환하는 상태 머신이다.
┌───────────────────────────────────────────────────────────────┐
│ Circuit Breaker 상태 머신 │
├───────────────────────────────────────────────────────────────┤
│ │
│ 실패율 < 임계값 │
│ ┌──────────────┐ │
│ │ │ │
│ ▼ │ │
│ ┌──────────┐ │ │
│ ──────►│ CLOSED │────────┘ │
│ │ │ (정상) │ │
│ │ └────┬─────┘ │
│ │ │ │
│ │ │ 실패율 >= 임계값 │
│ │ │ (예: 50% 이상 또는 연속 5회 에러) │
│ │ ▼ │
│ │ ┌──────────┐ │
│ │ │ OPEN │ ← 모든 요청 즉시 실패 (503) │
│ │ │ (차단) │ ← 장애 서비스 보호 │
│ │ └────┬─────┘ │
│ │ │ │
│ │ │ 대기 시간 경과 (baseEjectionTime) │
│ │ │ (예: 30초) │
│ │ ▼ │
│ │ ┌──────────┐ │
│ └──────│HALF-OPEN │ ← 제한된 프로브 요청만 허용 │
│ 성공 │ (시험) │ ← 성공하면 CLOSED로 복귀 │
│ └──────────┘ ← 실패하면 다시 OPEN │
│ │
│ CLOSED : 정상 상태. 모든 요청 통과. 실패율 모니터링 │
│ OPEN : 차단 상태. 즉시 실패 반환 (Fail-Fast) │
│ HALF-OPEN : 시험 상태. 제한된 요청만 통과시켜 복구 확인 │
└───────────────────────────────────────────────────────────────┘
5.4 Netflix Hystrix -> Resilience4j -> Istio/Envoy 진화 역사
┌───────────────────────────────────────────────────────────────┐
│ Circuit Breaker 진화 역사 │
├───────────────────────────────────────────────────────────────┤
│ │
│ 2007 Michael Nygard "Release It!" 출간 │
│ └─ 소프트웨어에서 Circuit Breaker 패턴 최초 정의 │
│ │
│ 2012 Netflix Hystrix 오픈소스 공개 │
│ └─ 마이크로서비스에서 대중화 │
│ └─ Netflix 내부 수천 서비스에 적용 │
│ └─ 애플리케이션 코드에 직접 구현 (Java 라이브러리) │
│ │
│ 2017 Istio/Envoy 출시 │
│ └─ 인프라 레벨 Circuit Breaking 도입 │
│ └─ 애플리케이션 코드 변경 없이 적용 │
│ └─ YAML 선언만으로 Circuit Breaker 설정 │
│ │
│ 2018.11 Netflix Hystrix maintenance 모드 선언 │
│ └─ Resilience4j가 공식 후속 라이브러리 │
│ └─ Hystrix 대비 가볍고 함수형 프로그래밍 지원 │
│ │
│ 2024 Istio Ambient Mesh GA │
│ └─ Sidecarless Circuit Breaking 가능 │
│ └─ Waypoint Proxy에서 L7 Circuit Breaker 실행 │
│ │
│ 진화 방향: │
│ 애플리케이션 레벨(코드) → 인프라 레벨(YAML) → 선택적 L7 │
└───────────────────────────────────────────────────────────────┘
5.5 outlierDetection (수동적/패시브 감지)
실제 트래픽의 응답을 모니터링하여 비정상 엔드포인트를 자동으로 제거한다.
# payment-service에 대한 Outlier Detection 설정
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-service
namespace: production
spec:
host: payment-service
trafficPolicy:
outlierDetection:
# 감지 조건
consecutive5xxErrors: 3 # 3회 연속 5xx → 즉시 제거
consecutiveGatewayErrors: 3 # 3회 연속 502/503/504 → 제거
interval: 5s # 5초 간격으로 분석
# 제거 정책
baseEjectionTime: 30s # 최소 30초 제거 (이후 점진 증가)
maxEjectionPercent: 50 # 최대 50%만 제거 (가용성 보장)
# Panic Threshold
minHealthPercent: 30 # 건강한 호스트 30% 미만이면 제거 중지
동작 원리:
┌───────────────────────────────────────────────────────────────┐
│ Outlier Detection 동작 원리 │
├───────────────────────────────────────────────────────────────┤
│ │
│ order-svc ──요청──► Envoy/Waypoint (로드밸런서) │
│ │ │
│ ├──► Pod A: 200, 200, 200 (정상) │
│ ├──► Pod B: 200, 503, 503 (경고) │
│ └──► Pod C: 503, 503, 503 (3연속!) │
│ │
│ interval(5s) 후 분석: │
│ - Pod A: 정상 → 유지 │
│ - Pod B: 연속 에러 2회 → 아직 임계값(3) 미달 → 유지 │
│ - Pod C: 연속 에러 3회 → 임계값 도달 → 제거! │
│ │
│ Pod C 제거 후: │
│ order-svc ──요청──► Envoy/Waypoint │
│ ├──► Pod A: 정상 │
│ └──► Pod B: 정상 │
│ (Pod C: 30초간 제거 = ejected) │
│ │
│ 30초 후 (baseEjectionTime): │
│ Pod C를 다시 풀에 추가하여 프로브 요청 전송 │
│ - 성공 → 풀에 복귀 │
│ - 실패 → 다시 제거 (제거 시간 2배 증가: 60초) │
└───────────────────────────────────────────────────────────────┘
5.6 connectionPool (능동적/프로액티브 보호, Bulkhead 패턴)
connectionPool은 장애가 발생하기 전에 리소스 사용량을 제한한다. 이는 Bulkhead(격벽) 패턴의 인프라 구현이다.
# payment-service에 대한 Connection Pool 설정 (Bulkhead)
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-bulkhead
namespace: production
spec:
host: payment-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100 # 최대 TCP 연결 100개
connectTimeout: 5s # TCP 연결 타임아웃 5초
http:
http1MaxPendingRequests: 50 # HTTP/1.1 대기 큐 50개
http2MaxRequests: 200 # HTTP/2 동시 요청 200개
maxRequestsPerConnection: 50 # 연결당 50 요청 후 재연결
maxRetries: 3 # 동시 재시도 3개 제한
connectionPool vs outlierDetection 비교:
| 항목 | connectionPool (Bulkhead) | outlierDetection (CB) |
|---|---|---|
| 타이밍 | 사전 예방 (Proactive) | 사후 대응 (Reactive) |
| 감지 방식 | 리소스 임계값 초과 | 에러 응답 패턴 |
| 차단 대상 | 초과 요청 전체 | 비정상 엔드포인트만 |
| 응답 | 503 (overflow) | 라우팅 풀에서 제거 |
| 비유 | 선박 격벽 (침수 격리) | 전기 차단기 (과부하 차단) |
5.7 Panic Threshold (최소 건강한 호스트 비율)
outlierDetection의 minHealthPercent 설정이다.
건강한 호스트 비율이 이 값 아래로 내려가면 모든 호스트에 트래픽을 분배한다 (Panic Mode).
┌───────────────────────────────────────────────────────────────┐
│ Panic Threshold 동작 │
├───────────────────────────────────────────────────────────────┤
│ │
│ 설정: minHealthPercent: 50 (건강한 호스트 50% 유지) │
│ Pod: 4개 (A, B, C, D) │
│ │
│ 상황 1: Pod C 장애 (건강한 호스트 75%) │
│ → 75% > 50% → 정상 동작: Pod C만 제거 │
│ → 트래픽: A, B, D에 분배 │
│ │
│ 상황 2: Pod B, C, D 장애 (건강한 호스트 25%) │
│ → 25% < 50% → Panic Mode 진입! │
│ → 모든 Pod(A, B, C, D)에 트래픽 분배 │
│ → 이유: 장애 Pod에서라도 일부 요청이 성공할 수 있음 │
│ Pod A 하나에 모든 트래픽 집중 → A도 장애 위험 │
│ │
│ Panic Mode 목적: "모두 장애보다 일부 성공이 낫다" │
└───────────────────────────────────────────────────────────────┘
5.8 인프라 수준 vs 애플리케이션 수준 비교
| 항목 | Istio/Envoy (인프라) | Resilience4j (애플리케이션) |
|---|---|---|
| 설정 방식 | YAML (DestinationRule) | Java/Kotlin 코드 또는 설정 파일 |
| 적용 범위 | 클러스터 전체 일괄 적용 | 서비스별 개별 적용 |
| 코드 변경 | 불필요 | 필요 (애노테이션 또는 래퍼) |
| Fallback | 불가 (503 반환만) | 커스텀 Fallback 로직 가능 |
| 언어 무관 | O (모든 언어) | Java/Kotlin 전용 |
| 상태 머신 | 간접적 (ejection 기반) | 명시적 (Closed/Open/Half-Open) |
| 메트릭 | Envoy 메트릭 자동 수집 | Micrometer 연동 필요 |
| 관측성 | Kiali, Grafana 통합 | Actuator 엔드포인트 |
| 권장 | 기본 보호 (모든 서비스) | 핵심 서비스 추가 보호 |
함께 사용하는 것이 권장된다. Istio가 인프라 레벨에서 비정상 Pod를 제거하고, Resilience4j가 애플리케이션 레벨에서 커스텀 Fallback을 실행한다.
6. 4가지 기술 통합 아키텍처
HTTP/2, mTLS, Waypoint Proxy, Circuit Breaker가 하나의 요청 흐름에서 어떻게 협력하는지 보여준다.
┌──────────────────────────────────────────────────────────────────────┐
│ Istio Ambient Mesh 통합 아키텍처 (요청 흐름) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ [order-service Pod] [payment-service Pod] │
│ (1) HTTP/2 gRPC 요청 생성 (7) HTTP/2 gRPC 수신 │
│ │ ▲ │
│ │ 평문 (Pod 내부) │ 평문 │
│ ▼ │ │
│ [ztunnel - Node A] [ztunnel - Node B] │
│ (2) SPIFFE ID로 mTLS 핸드셰이크 (6) mTLS 복호화 │
│ (3) HBONE 터널 캡슐화 (포트 15008) (5) HBONE 디캡슐화 │
│ │ ▲ │
│ │ mTLS 암호화된 HBONE 터널 │ │
│ ▼ │ │
│ [Waypoint Proxy]─────────────────────────────────┘ │
│ (4) L7 처리: │
│ ├─ HTTP/2 바이너리 프레임 파싱 │
│ ├─ L7 AuthorizationPolicy 인가 검사 │
│ ├─ Circuit Breaker 검사 (outlierDetection) │
│ │ └─ 대상 Pod 건강 여부 확인 │
│ │ └─ 비정상이면 503 즉시 반환 (Fail-Fast) │
│ ├─ connectionPool 검사 (Bulkhead) │
│ │ └─ 동시 요청 수 확인 │
│ │ └─ 초과 시 503 overflow 반환 │
│ ├─ 로드밸런싱 (HTTP/2 요청 단위 ROUND_ROBIN) │
│ ├─ Retry/Timeout 정책 적용 │
│ └─ L7 Telemetry 수집 (HTTP 메트릭, 분산 트레이싱) │
│ │
│ 각 기술의 역할: │
│ ┌────────────────┬───────────────────────────────────────────┐ │
│ │ HTTP/2 │ 바이너리 프레이밍, 멀티플렉싱, HPACK 압축 │ │
│ │ mTLS │ ztunnel 간 상호 인증 + AES-GCM 암호화 │ │
│ │ Waypoint Proxy │ L7 트래픽 관리 엔진 (라우팅, 인가, CB) │ │
│ │ Circuit Breaker │ 비정상 Pod 격리, Bulkhead 리소스 보호 │ │
│ └────────────────┴───────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
데이터 흐름 상세:
| 단계 | 위치 | 동작 | 관련 기술 |
|---|---|---|---|
| 1 | order-service Pod | HTTP/2(gRPC) 요청 생성 | HTTP/2 |
| 2 | ztunnel (Node A) | SPIFFE ID로 mTLS 핸드셰이크, AES-GCM 암호화 | mTLS |
| 3 | ztunnel (Node A) | HBONE 터널로 캡슐화, 포트 15008 전송 | HBONE |
| 4 | Waypoint Proxy | HTTP/2 프레임 파싱, Circuit Breaker 검사, 라우팅 결정 | Waypoint + CB |
| 5 | ztunnel (Node B) | HBONE 디캡슐화 | HBONE |
| 6 | ztunnel (Node B) | mTLS 복호화 | mTLS |
| 7 | payment-service Pod | HTTP/2(gRPC) 요청 수신 및 처리 | HTTP/2 |
7. 실전 시나리오별 적용 가이드
7.1 시나리오 1: 결제 서비스 보호 (Circuit Breaker + mTLS)
결제 서비스는 가장 높은 수준의 보호가 필요하다. Circuit Breaker + Bulkhead + mTLS STRICT를 조합한다.
# 1. payment 네임스페이스 mTLS STRICT 적용
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: payment-strict
namespace: payment
spec:
mtls:
mode: STRICT # 평문 요청 거부 (결제 데이터 보호)
portLevelMtls:
8081:
mode: PERMISSIVE # 헬스체크 포트 예외
---
# 2. payment-service Circuit Breaker + Bulkhead
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-protection
namespace: payment
spec:
host: payment-service
trafficPolicy:
# Bulkhead: 연결 풀 제한
connectionPool:
tcp:
maxConnections: 50 # 결제 서비스 최대 연결 50개
connectTimeout: 3s # 빠른 실패
http:
http2MaxRequests: 200 # 동시 요청 200개 제한
http1MaxPendingRequests: 20 # 대기 큐 20개 제한
maxRetries: 2 # 재시도 최대 2회 (결제는 보수적)
# Circuit Breaker: 장애 엔드포인트 제거
outlierDetection:
consecutive5xxErrors: 3 # 3회 연속 5xx → 즉시 제거
interval: 5s # 5초 간격 분석 (빠른 감지)
baseEjectionTime: 60s # 60초 제거 (결제는 보수적)
maxEjectionPercent: 30 # 최대 30%만 제거 (가용성 보장)
minHealthPercent: 50 # 50% 미만이면 Panic Mode
---
# 3. 결제 요청 Timeout + Retry 정책
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payment-routing
namespace: payment
spec:
hosts:
- payment-service
http:
- route:
- destination:
host: payment-service
weight: 100
timeout: 5s # 결제 요청 타임아웃 5초
retries:
attempts: 2 # 최대 2회 재시도
perTryTimeout: 3s # 재시도당 3초 타임아웃
retryOn: "5xx,reset,connect-failure"
7.2 시나리오 2: gRPC 서비스 최적화 (HTTP/2 + Load Balancing)
gRPC는 HTTP/2를 필수로 사용하므로, K8s에서의 로드밸런싱 문제를 반드시 해결해야 한다.
# gRPC 서비스를 위한 통합 설정
# HTTP/2 로드밸런싱 + mTLS + Circuit Breaker
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: order-grpc-config
namespace: production
spec:
host: order-service
trafficPolicy:
# mTLS 설정
tls:
mode: ISTIO_MUTUAL
# HTTP/2 연결 관리 (로드밸런싱 문제 해결)
connectionPool:
http:
h2UpgradePolicy: UPGRADE # HTTP/2 업그레이드 강제
http2MaxRequests: 1000 # gRPC 동시 요청 허용량
maxRequestsPerConnection: 100 # 연결당 100 요청 후 재연결 → 재분배
# gRPC 장애 감지
outlierDetection:
consecutiveGatewayErrors: 3 # gRPC 게이트웨이 에러 감지
consecutive5xxErrors: 5
interval: 10s
baseEjectionTime: 30s
maxEjectionPercent: 50
# L7 로드밸런싱
loadBalancer:
simple: ROUND_ROBIN
// order-service gRPC 서버 설정 (Go)
// MaxConnectionAge로 연결 재분배 강제
server := grpc.NewServer(
grpc.KeepaliveParams(keepalive.ServerParameters{
MaxConnectionAge: 5 * time.Minute, // 5분마다 연결 갱신
MaxConnectionAgeGrace: 30 * time.Second, // 진행 중 요청 완료 유예
Time: 30 * time.Second, // Keepalive 핑 간격
Timeout: 10 * time.Second, // 핑 응답 타임아웃
}),
)
# gRPC Service 정의 (appProtocol 명시)
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: production
spec:
selector:
app: order-service
ports:
- name: grpc-order
port: 50051
targetPort: 50051
appProtocol: kubernetes.io/h2c # gRPC(h2c) 명시
7.3 시나리오 3: 멀티 클러스터 통신 (mTLS + Waypoint)
서로 다른 K8s 클러스터에 있는 서비스 간 안전한 통신을 구성한다.
┌───────────────────────────────────────────────────────────────┐
│ 멀티 클러스터 통신 아키텍처 │
├───────────────────────────────────────────────────────────────┤
│ │
│ Cluster A (ap-northeast-2a) Cluster B (ap-northeast-2c) │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ order-service │ │ payment-service │ │
│ │ │ │ │ ▲ │ │
│ │ ▼ │ │ │ │ │
│ │ ztunnel ──mTLS──────────────────► ztunnel │ │
│ │ │ │ │ │ │ │
│ │ ▼ │ │ ▼ │ │
│ │ East-West Gateway │ │ East-West Gateway │ │
│ │ (Istio Gateway) │ │ (Istio Gateway) │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ 핵심 요구사항: │
│ - 공유 Root CA (두 클러스터가 같은 신뢰 도메인) │
│ - East-West Gateway로 클러스터 간 mTLS 트래픽 터널링 │
│ - DNS 또는 Istio ServiceEntry로 원격 서비스 검색 │
└───────────────────────────────────────────────────────────────┘
# Cluster A: 원격 payment-service 검색을 위한 ServiceEntry
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: payment-service-cluster-b
namespace: production
spec:
hosts:
- payment-service.payment.svc.cluster.local
location: MESH_INTERNAL
ports:
- number: 50051
name: grpc
protocol: GRPC
resolution: DNS
endpoints:
- address: cluster-b-eastwest-gw.example.com # Cluster B East-West Gateway
ports:
grpc: 15443 # mTLS 포트
---
# Cluster A: 원격 서비스에 대한 mTLS + Circuit Breaker
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-service-cross-cluster
namespace: production
spec:
host: payment-service.payment.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL # 클러스터 간 mTLS
connectionPool:
tcp:
connectTimeout: 10s # 클러스터 간 네트워크 지연 고려
outlierDetection:
consecutive5xxErrors: 5
interval: 10s
baseEjectionTime: 60s # 원격 클러스터 복구 시간 여유
멀티 클러스터 mTLS 사전 조건:
| 항목 | 설정 방법 |
|---|---|
| 공유 Root CA | 두 클러스터에 같은 Root CA 인증서 배포 (cert-manager 또는 Istio 외부 CA) |
| 신뢰 도메인 | meshConfig.trustDomain: cluster.local (동일) |
| East-West Gateway | 각 클러스터에 Istio IngressGateway 배포 (포트 15443) |
| 서비스 검색 | ServiceEntry 또는 Istio Multi-Primary 모드 |
| 방화벽 | 클러스터 간 15443(mTLS), 15012(istiod) 포트 허용 |
7.4 시나리오 4: 레거시에서 서비스메시 마이그레이션 (PERMISSIVE mTLS + Sidecar -> Ambient)
기존 레거시 시스템을 단계적으로 서비스 메시에 통합하는 전략이다.
┌───────────────────────────────────────────────────────────────┐
│ 레거시 → 서비스메시 마이그레이션 단계 │
├───────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: PERMISSIVE mTLS (2주) │
│ ├─ Ambient 모드 활성화 (레이블만 추가, 재시작 불필요) │
│ ├─ 레거시 서비스: 평문 통신 유지 │
│ ├─ 메시 서비스: mTLS 자동 활성화 │
│ ├─ PERMISSIVE → 평문 + mTLS 공존 │
│ └─ 메트릭 수집: mTLS 비율 모니터링 │
│ │
│ Phase 2: 레거시 서비스 Ambient 편입 (2주) │
│ ├─ 레거시 서비스 네임스페이스에 ambient 레이블 추가 │
│ ├─ ztunnel이 자동으로 L4 mTLS 적용 │
│ ├─ 애플리케이션 코드 변경 없음 │
│ └─ mTLS 비율 100% 목표 │
│ │
│ Phase 3: STRICT mTLS 전환 (1주) │
│ ├─ 비핵심 네임스페이스부터 STRICT │
│ ├─ 평문 트래픽 0% 확인 │
│ └─ 핵심 네임스페이스 STRICT │
│ │
│ Phase 4: L7 정책 활성화 (1주) │
│ ├─ 필요한 서비스에 Waypoint 배포 │
│ ├─ Circuit Breaker, Retry, Timeout 설정 │
│ └─ L7 AuthorizationPolicy 적용 │
│ │
│ Phase 5: (선택) Sidecar → Ambient 전환 │
│ ├─ 기존 Sidecar 서비스가 있으면 Ambient로 마이그레이션 │
│ ├─ 혼합 모드에서 점진적 전환 │
│ └─ Sidecar injection 비활성화 + Pod 재시작 │
└───────────────────────────────────────────────────────────────┘
# Phase 1: 네임스페이스 Ambient 모드 활성화
# Pod 재시작 불필요!
kubectl label namespace legacy-app istio.io/dataplane-mode=ambient
# Phase 1: PERMISSIVE mTLS (레거시 평문 허용)
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: legacy-permissive
namespace: legacy-app
spec:
mtls:
mode: PERMISSIVE # 평문 + mTLS 모두 허용
---
# Phase 3: STRICT mTLS 전환 (평문 0% 확인 후)
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: legacy-strict
namespace: legacy-app
spec:
mtls:
mode: STRICT # 평문 거부, mTLS만 허용
---
# Phase 4: 레거시 서비스에 Waypoint 배포 (L7 정책 필요 시)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
labels:
istio.io/waypoint-for: service
name: legacy-waypoint
namespace: legacy-app
spec:
gatewayClassName: istio-waypoint
listeners:
- name: mesh
port: 15008
protocol: HBONE
8. YAML 설정 레퍼런스
8.1 PeerAuthentication YAML
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: example # 정책 이름
namespace: production # 적용 범위 (istio-system = mesh-wide)
spec:
selector: # 선택적: 특정 워크로드만 대상
matchLabels:
app: order-service # 이 레이블의 Pod에만 적용
mtls:
mode: STRICT # STRICT | PERMISSIVE | DISABLE | UNSET
# STRICT : mTLS만 허용, 평문 거부
# PERMISSIVE: mTLS + 평문 모두 허용 (마이그레이션 중)
# DISABLE : mTLS 비활성화 (특수 케이스)
# UNSET : 상위 정책 상속
portLevelMtls: # 선택적: 포트별 오버라이드
8080:
mode: PERMISSIVE # 이 포트만 평문 허용 (헬스체크 등)
9090:
mode: DISABLE # 이 포트는 mTLS 비활성화
적용 우선순위 (높은 순):
- 워크로드별 (selector 지정)
- 네임스페이스별 (namespace 지정, selector 없음)
- 메시 전체 (istio-system 네임스페이스)
8.2 DestinationRule (outlierDetection + connectionPool) YAML
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: order-service-resilience # 규칙 이름
namespace: production
spec:
host: order-service # 대상 서비스
trafficPolicy:
# ── outlierDetection: 비정상 엔드포인트 패시브 감지 ──
outlierDetection:
consecutive5xxErrors: 5 # 기본값: 5. 연속 5xx 에러 횟수
consecutiveGatewayErrors: 0 # 기본값: 0 (비활성). 502/503/504 에러 횟수
consecutiveLocalOriginFailures: 5 # 기본값: 5. 로컬 원인 실패 횟수
interval: 10s # 기본값: 10s. 분석 주기
baseEjectionTime: 30s # 기본값: 30s. 최소 제거 시간 (이후 2배씩 증가)
maxEjectionPercent: 10 # 기본값: 10. 최대 제거 비율 (%)
minHealthPercent: 0 # 기본값: 0. Panic Threshold (%)
splitExternalLocalOriginErrors: false # 기본값: false. 로컬/원격 에러 분리
# ── connectionPool: 프로액티브 리소스 보호 (Bulkhead) ──
connectionPool:
tcp:
maxConnections: 1024 # 기본값: 2^32-1. 최대 TCP 연결
connectTimeout: 10s # 기본값: 10s. TCP 연결 타임아웃
tcpKeepalive:
time: 7200s # TCP Keepalive 시작 시간
interval: 75s # Keepalive 프로브 간격
probes: 10 # 최대 프로브 횟수
maxConnectionDuration: 0s # 기본값: 0 (무제한). 연결 최대 수명
http:
http1MaxPendingRequests: 1024 # 기본값: 1024. HTTP/1.1 대기 큐
http2MaxRequests: 1024 # 기본값: 1024. HTTP/2 동시 요청
maxRequestsPerConnection: 0 # 기본값: 0 (무제한). 연결당 요청 수
maxRetries: 3 # 기본값: 2^32-1. 동시 재시도 수
idleTimeout: 3600s # 기본값: 1h. 유휴 연결 타임아웃
h2UpgradePolicy: DEFAULT # DEFAULT | UPGRADE | DO_NOT_UPGRADE
useClientProtocol: false # 클라이언트 프로토콜 유지 여부
outlierDetection 필드별 권장값:
| 필드 | 기본값 | 권장값 | 설명 |
|---|---|---|---|
consecutive5xxErrors |
5 | 3-5 | 값이 작으면 민감, 크면 둔감 |
consecutiveGatewayErrors |
0 (비활성) | 3 | gRPC 서비스에 권장. 502/503/504만 감지 |
interval |
10s | 5-10s | 짧으면 빠른 감지, CPU 소비 증가 |
baseEjectionTime |
30s | 30-60s | 너무 짧으면 불안정, 너무 길면 복구 지연 |
maxEjectionPercent |
10 | 30-50 | 프로덕션에서는 50% 이하 권장 |
minHealthPercent |
0 | 30-50 | 0이면 Panic Mode 비활성화 |
8.3 Gateway + Waypoint YAML
# Waypoint Proxy 배포 (네임스페이스 레벨)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
labels:
istio.io/waypoint-for: service # 서비스 트래픽에 적용
name: production-waypoint # Waypoint 이름
namespace: production # 배포할 네임스페이스
spec:
gatewayClassName: istio-waypoint # Istio Waypoint 전용 클래스
listeners:
- name: mesh # 리스너 이름
port: 15008 # HBONE 포트 (고정)
protocol: HBONE # HBONE 프로토콜 (고정)
# allowedRoutes: # 선택적: 라우트 제한
# namespaces:
# from: Same # 같은 네임스페이스 라우트만 허용
# 서비스에 Waypoint 연결 (레이블)
kubectl label service order-service \
istio.io/use-waypoint=production-waypoint \
-n production
# 또는 네임스페이스 전체에 Waypoint 연결
kubectl label namespace production \
istio.io/use-waypoint=production-waypoint
Waypoint 리소스 설정 (HPA 포함):
# Waypoint Pod 리소스 및 오토스케일링
# istioctl waypoint apply 시 자동 생성되지만, 수동 설정 권장
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: production-waypoint
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: production-waypoint-istio-waypoint # Waypoint Deployment 이름
minReplicas: 2 # 최소 2개 (고가용성)
maxReplicas: 10 # 최대 10개
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 70% 기준 오토스케일링
8.4 VirtualService (retry + timeout) YAML
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: order-service-routing # VirtualService 이름
namespace: production
spec:
hosts:
- order-service # 대상 서비스
http:
# 라우트 1: 카나리 배포 (v2에 10% 트래픽)
- match:
- headers:
x-canary:
exact: "true" # 카나리 헤더가 있으면 v2로
route:
- destination:
host: order-service
subset: v2 # v2 서브셋
weight: 100
timeout: 3s # 카나리 요청 타임아웃 3초
retries:
attempts: 1 # 카나리는 재시도 1회만
perTryTimeout: 2s
retryOn: "5xx"
# 라우트 2: 기본 트래픽 (v1)
- route:
- destination:
host: order-service
subset: v1 # v1 서브셋 (안정 버전)
weight: 100
timeout: 10s # 기본 요청 타임아웃 10초
retries:
attempts: 3 # 최대 3회 재시도
perTryTimeout: 5s # 재시도당 5초 타임아웃
retryOn: "5xx,reset,connect-failure,retriable-status-codes"
retryRemoteLocalities: true # 원격 로컬리티에도 재시도
fault: # 선택적: 장애 주입 (테스트용)
delay:
percentage:
value: 0.1 # 0.1% 요청에 지연 주입
fixedDelay: 5s
retryOn 옵션 상세:
| 값 | 의미 |
|---|---|
5xx |
서버 5xx 에러 시 재시도 |
reset |
연결 리셋 시 재시도 |
connect-failure |
연결 실패 시 재시도 |
retriable-status-codes |
x-envoy-retriable-status-codes 헤더의 코드 |
gateway-error |
502, 503, 504 에러 시 재시도 |
retriable-4xx |
409 에러 시 재시도 |
refused-stream |
REFUSED_STREAM 에러 시 재시도 |
9. 프로덕션 체크리스트
4가지 핵심 기술을 프로덕션에 배포할 때 확인해야 할 항목이다.
HTTP/2 체크리스트
- 1. Service 포트에
appProtocol: http2또는name: grpc-*설정 - 2. gRPC 서비스:
MaxConnectionAge설정 (권장 3-5분) - 3. DestinationRule에
maxRequestsPerConnection설정으로 연결 재분배 - 4.
http2MaxRequests값을 서비스 용량에 맞게 조정 - 5. h2c 사용 시 Service Mesh mTLS 또는 NetworkPolicy로 보호
- 6. HPA 트리거 메트릭이 Pod별 요청 수 기준인지 확인
- 7. HTTP/2 WINDOW_UPDATE 흐름 제어 설정 검토
mTLS 체크리스트
- 1. PERMISSIVE 모드에서 시작하여 mTLS 연결 비율 모니터링
- 2. 비메시 클라이언트(모니터링, CI/CD 등) 식별 및 예외 처리
- 3. 헬스체크 포트
portLevelMtls설정 확인 - 4. 네임스페이스별 순차적으로 STRICT 전환
- 5.
connection_security_policy="mutual_tls"메트릭 100% 확인 - 6. 인증서 자동 갱신 동작 확인 (Istio 기본 24시간)
- 7. Root CA 만료일 모니터링 알림 설정
- 8. SPIFFE ID 기반 AuthorizationPolicy 설정 확인
Waypoint 체크리스트
- 1. 네임스페이스에
istio.io/dataplane-mode: ambient레이블 확인 - 2. L7 정책이 필요한 서비스에만 Waypoint 배포 (불필요한 곳은 L4 only)
- 3. Waypoint HPA 설정 (CPU 70% 기준 오토스케일링)
- 4. Waypoint Pod의 리소스 requests/limits 설정
- 5. 사이드카에서 Ambient 마이그레이션 시 혼합 모드 테스트 완료
- 6. HBONE 포트(15008) 방화벽/SecurityGroup 허용 확인
- 7. Waypoint 장애 시 L4 fallback 동작 확인
Circuit Breaker 체크리스트
- 1. outlierDetection 설정 (최소
consecutive5xxErrors,interval,baseEjectionTime) - 2.
maxEjectionPercent50% 이하로 설정 (가용성 보장) - 3.
minHealthPercent30% 이상으로 설정 (Panic Threshold) - 4. connectionPool 설정 (
maxConnections,http2MaxRequests) - 5. 핵심 서비스에 Resilience4j Fallback 로직 구현
- 6. Grafana 대시보드에 ejection 이벤트 알림 설정
- 7. Chaos Engineering 테스트로 Circuit Breaker 동작 검증
- 8. VirtualService에 적절한 timeout/retries 설정 확인
10. 기술 선택 가이드
의사결정 플로우차트
┌───────────────────────────────────────────────────────────────────────┐
│ 서비스 메시 기술 선택 플로우차트 │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ 시작: K8s 서비스 메시 도입 검토 │
│ │ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ 서비스 간 암호화/인증 필요? │ │
│ └─────────┬──────────┬────────┘ │
│ Yes │ │ No │
│ ▼ └──────► NetworkPolicy만으로 충분 (비권장) │
│ ┌─────────────────────────┐ │
│ │ 리소스 제약이 있는가? │ │
│ └────┬──────────┬─────────┘ │
│ Yes │ │ No │
│ ▼ ▼ │
│ Ambient 모드 Sidecar도 가능 │
│ (ztunnel L4) (선택의 여지 있음) │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ L7 기능 필요? (라우팅, JWT, │ │
│ │ Circuit Breaker, 카나리 등) │ │
│ └─────────┬──────────┬────────────┘ │
│ Yes │ │ No │
│ ▼ └──────► L4 only (ztunnel)로 충분 │
│ ┌─────────────────────────┐ mTLS + L4 메트릭 확보 │
│ │ Waypoint Proxy 배포 │ │
│ │ (필요한 서비스에만) │ │
│ └─────────┬───────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ gRPC 서비스 사용? │ │
│ └─────────┬──────────┬────────────┘ │
│ Yes │ │ No │
│ ▼ └──────► 기본 HTTP/1.1 + mTLS │
│ HTTP/2 최적화 필수: │
│ ├─ MaxConnectionAge 설정 │
│ ├─ L7 로드밸런싱 또는 │
│ │ Client-side LB 설정 │
│ └─ http2MaxRequests 조정 │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ 외부 의존성이 있는 핵심 서비스? │ │
│ │ (결제, 인증, 외부 API 등) │ │
│ └─────────┬──────────┬────────────┘ │
│ Yes │ │ No │
│ ▼ └──────► 기본 outlierDetection만 설정 │
│ Circuit Breaker 강화: │
│ ├─ outlierDetection (보수적 임계값) │
│ ├─ connectionPool (Bulkhead) │
│ └─ Resilience4j Fallback 구현 │
└───────────────────────────────────────────────────────────────────────┘
비용/복잡도/효과 매트릭스
| 기술 | 도입 비용 | 운영 복잡도 | 보안 효과 | 성능 효과 | 안정성 효과 | 권장 우선순위 |
|---|---|---|---|---|---|---|
| mTLS (Ambient L4) | 낮음 (레이블 1개) | 낮음 | 매우 높음 | +8% 오버헤드 | 중간 | 1 (가장 먼저) |
| mTLS (STRICT) | 낮음 | 중간 (예외 관리) | 매우 높음 | 동일 | 중간 | 2 |
| Circuit Breaker | 중간 (YAML 설정) | 중간 (임계값 튜닝) | - | - | 매우 높음 | 3 |
| Waypoint Proxy | 중간 (배포/HPA) | 중간 | 높음 (L7 인가) | 중간 오버헤드 | 높음 | 4 (필요 시) |
| HTTP/2 최적화 | 중간 (설정 복합) | 중간 (LB 모니터링) | - | 높음 (압축, 멀티플렉싱) | - | 4 (gRPC 필수) |
| Resilience4j | 높음 (코드 변경) | 높음 (서비스별 관리) | - | - | 매우 높음 | 5 (핵심 서비스) |
상황별 필요 기술
| 상황 | HTTP/2 | mTLS | Waypoint | Circuit Breaker |
|---|---|---|---|---|
| gRPC 서비스 | 필수 | 권장 | L7 필요 시 | 권장 |
| REST API (HTTP/1.1) | 선택적 | 권장 | L7 필요 시 | 필요 시 |
| 레거시 HTTP/1.1 전용 | 불필요 | 권장 | 불필요 | 필요 시 |
| 컴플라이언스 (PCI/HIPAA) | - | 필수 | L7 인가 정책 시 | - |
| 리소스 제한 환경 | h2c 검토 | Ambient 모드 | ztunnel only (L4) | 앱 레벨(Resilience4j) |
| 대규모 클러스터 (500+ Pods) | 필수 | Ambient 모드 | 선택적 | 필수 |
| 개발/스테이징 | 선택적 | PERMISSIVE | 불필요 | 불필요 |
기술 도입 순서 권장
┌───────────────────────────────────────────────────────┐
│ 권장 도입 순서 │
├───────────────────────────────────────────────────────┤
│ │
│ 1단계: mTLS (PERMISSIVE) │
│ ├─ Ambient 모드 활성화 (레이블 하나) │
│ ├─ 즉시 L4 mTLS 획득 │
│ └─ 리스크: 매우 낮음 │
│ │
│ 2단계: mTLS (STRICT) │
│ ├─ PERMISSIVE에서 모니터링 후 전환 │
│ ├─ Zero Trust 기반 확립 │
│ └─ 리스크: 낮음 (단계적 전환) │
│ │
│ 3단계: Circuit Breaker │
│ ├─ 핵심 서비스에 outlierDetection 설정 │
│ ├─ connectionPool로 Bulkhead 적용 │
│ └─ 리스크: 낮음 (관측 후 튜닝) │
│ │
│ 4단계: Waypoint + HTTP/2 │
│ ├─ L7 정책이 필요한 서비스에 Waypoint 배포 │
│ ├─ gRPC 서비스에 HTTP/2 최적화 적용 │
│ └─ 리스크: 중간 (L7 파싱 오버헤드 모니터링 필요) │
└───────────────────────────────────────────────────────┘
11. 자주 묻는 질문 (FAQ)
Q1. mTLS를 적용하면 성능이 크게 떨어지나요?
A: mTLS 암호화 자체의 오버헤드는 미미하다. TLS 1.3 핸드셰이크는 1-RTT이며, 대칭키 암호화(AES-GCM)는 현대 CPU에서 하드웨어 가속(AES-NI)된다. 실제 오버헤드의 주요 원인은 L7 HTTP 파싱이다. Ambient 모드의 ztunnel(L4 only)을 사용하면 P99 지연시간 증가가 +8% 수준으로 매우 낮다 (arXiv 2411.02267).
Q2. Sidecar 모델에서 Ambient로 마이그레이션하는 것이 안전한가요?
A: 같은 메시에서 Sidecar와 Ambient를 혼용할 수 있다. 권장 절차:
- 새로운 네임스페이스를 Ambient로 시작
- 비핵심 서비스부터 Sidecar에서 Ambient로 전환
- 트래픽 메트릭 비교 후 핵심 서비스 전환
- Sidecar injection 비활성화 + Pod 재시작
Istio v1.24부터 GA이므로 프로덕션 사용에 적합하다.
Q3. Circuit Breaker의 임계값을 어떻게 정해야 하나요?
A: 정답은 없으며, 서비스 특성에 따라 튜닝해야 한다. 권장 시작점:
consecutive5xxErrors: 5 (기본값, 대부분 적합)interval: 10s (기본값)baseEjectionTime: 30s (결제 서비스는 60s)maxEjectionPercent: 30-50% (레플리카 수에 따라)
프로덕션 배포 전에 Chaos Engineering 도구(Chaos Mesh, Litmus)로 장애 주입 테스트를 수행하여 적절한 임계값을 찾는다.
Q4. HTTP/2가 K8s에서 로드밸런싱 문제를 일으키면, HTTP/1.1로 돌아가야 하나요?
A: 아니다. HTTP/2의 성능 이점(멀티플렉싱, 헤더 압축)은 매우 크다. 문제는 kube-proxy의 L4 로드밸런싱 한계이며, 이는 3가지 방법으로 해결 가능하다:
MaxConnectionAge설정 (가장 간단, 서버 코드 3줄)- Service Mesh L7 로드밸런싱 (가장 포괄적)
- Client-side 로드밸런싱 (Headless Service + round_robin)
Q5. Waypoint Proxy를 모든 네임스페이스에 배포해야 하나요?
A: 아니다. Waypoint는 L7 기능이 필요한 곳에만 선택적으로 배포한다. L4 기능(mTLS, TCP 로드밸런싱)만 필요한 서비스는 ztunnel만으로 충분하다. 이것이 Ambient 모델의 핵심 장점이다 – 필요한 곳에만 L7 비용을 지불한다.
L7이 필요한 경우:
- HTTP 라우팅 (경로/헤더 기반)
- L7 AuthorizationPolicy (HTTP 메서드/경로 기반 인가)
- Circuit Breaker / Retry / Timeout
- 카나리 배포 / 트래픽 분할
- JWT 검증 (RequestAuthentication)
Q6. Resilience4j와 Istio Circuit Breaker를 함께 사용해도 되나요?
A: 오히려 함께 사용하는 것이 권장된다. 역할이 다르다:
- Istio outlierDetection: 인프라 레벨에서 비정상 엔드포인트를 자동 제거. 모든 서비스에 일괄 적용.
- Resilience4j: 애플리케이션 레벨에서 커스텀 Fallback 로직 실행. 핵심 비즈니스 서비스에 개별 적용.
예를 들어 Istio가 장애 Pod를 제거하고, 남은 Pod에서도 장애가 발생하면 Resilience4j가 Fallback(비동기 큐잉, 캐시 반환 등)을 실행한다.
Q7. HTTP/3(QUIC)는 언제 K8s 내부 통신에 도입해야 하나요?
A: 2026년 현재, K8s 내부 통신에 HTTP/3를 도입하기에는 이르다. Istio의 내부 통신 지원이 아직 없으며, Envoy 업스트림도 Alpha 수준이다. 외부 에지(CDN, API Gateway)에서 먼저 HTTP/3를 적용하고, 내부 통신은 HTTP/2 + mTLS로 유지하는 것이 안전하다. Envoy와 Istio의 HTTP/3 로드맵을 지속적으로 모니터링할 것을 권장한다.
Q8. Ambient Mesh에서 EnvoyFilter를 사용할 수 없는데, 커스텀 필터가 필요하면?
A: WASM (WebAssembly) 플러그인을 사용한다. Istio의 WasmPlugin API를 통해 Waypoint Proxy에 커스텀 필터를 배포할 수 있다. 현재 Alpha 상태이지만, EnvoyFilter의 공식 대체 방법이다. 또는 사이드카 모델을 해당 서비스에만 유지할 수 있다 (혼합 모드).
Q9. Istio Ambient와 Cilium Service Mesh 중 무엇을 선택해야 하나요?
A: 핵심 차이는 다음과 같다:
| 항목 | Istio Ambient | Cilium |
|---|---|---|
| L4 처리 | ztunnel (유저스페이스) | eBPF (커널) |
| L7 처리 | Waypoint (Envoy) | Envoy (별도 Pod) |
| P99 오버헤드 | +8% (L4), 더 높음(L7) | +99% (arXiv) |
| mTLS | SPIFFE 기반 | WireGuard 기반 |
| L7 정책 성숙도 | 매우 높음 (Istio 생태계) | 발전 중 |
| CNI 종속성 | 없음 (기존 CNI 유지) | Cilium CNI 필수 |
L7 정책 풍부함이 필요하면 Istio Ambient, eBPF 기반 네트워킹을 이미 사용 중이면 Cilium이 자연스러운 선택이다.
Q10. Pod가 100개 미만인 소규모 클러스터에서도 서비스 메시가 필요한가요?
A: 규모와 관계없이 보안 요구사항이 있다면 필요하다. 컴플라이언스(PCI DSS, HIPAA), Zero Trust 정책이 요구되면 Pod 수와 무관하게 mTLS를 적용해야 한다. Ambient 모드는 소규모 클러스터에서도 오버헤드가 매우 낮다 (노드당 ztunnel 1개, ~40MB). 순수 기능적 요구(라우팅, CB)만 필요하면 서비스 메시 없이도 가능하지만, mTLS를 위해서는 서비스 메시가 가장 효율적인 방법이다.
Q11. outlierDetection의 baseEjectionTime이 지나면 즉시 모든 트래픽을 받나요?
A: 아니다. baseEjectionTime이 경과하면 해당 엔드포인트가 로드밸런싱 풀에 다시 추가되지만, Envoy는 점진적으로 트래픽을 보낸다. 다시 에러가 발생하면 제거 시간이 baseEjectionTime * (제거 횟수)로 증가한다. 예를 들어 baseEjectionTime이 30s이고 2번째 제거이면 60s, 3번째이면 90s로 점진적으로 증가하여 반복적 장애 서비스의 영향을 최소화한다.
Q12. SPIFFE ID 기반 인가 정책은 어떻게 설정하나요?
A: Istio AuthorizationPolicy에서 source.principals로 SPIFFE ID를 사용한다:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: payment-allow-order
namespace: payment
spec:
action: ALLOW
rules:
- from:
- source:
# SPIFFE ID로 order-service만 허용
principals:
- "cluster.local/ns/production/sa/order-service"
to:
- operation:
methods: ["POST"]
paths: ["/api/v1/payments"]
이렇게 하면 order-service ServiceAccount의 SPIFFE ID를 가진 워크로드만 payment-service의 /api/v1/payments POST 엔드포인트에 접근할 수 있다.
12. 요약 및 키워드
4가지 핵심 기술 요약
| 기술 | 핵심 가치 | K8s 구현 | 도입 우선순위 |
|---|---|---|---|
| HTTP/2 | 멀티플렉싱으로 전송 효율 극대화 | appProtocol, DestinationRule h2UpgradePolicy | 4 (gRPC 시 필수) |
| mTLS | Zero Trust 네트워크 보안 | PeerAuthentication, Ambient ztunnel | 1 (가장 먼저) |
| Waypoint Proxy | Sidecar 없는 L7 트래픽 관리 | Gateway API, istio-waypoint | 4 (L7 필요 시) |
| Circuit Breaker | 연쇄 장애 방지, Fail-Fast | outlierDetection, connectionPool | 3 (핵심 서비스) |
기술 간 관계 요약
┌───────────────────────────────────────────────────────────────┐
│ │
│ HTTP/2 ───전송 기반 제공───► mTLS │
│ │ (바이너리 프레이밍) │ │
│ │ │ │
│ │ │ 터널 보호 │
│ │ 프레임 파싱 │ (HBONE/SPIFFE) │
│ │ │ │
│ ▼ ▼ │
│ Waypoint Proxy ◄──실행 환경── ztunnel │
│ │ (L4 mTLS) │
│ │ │
│ │ Circuit Breaker 실행 │
│ │ (outlierDetection + connectionPool) │
│ ▼ │
│ 건강한 Pod에만 트래픽 전달 │
│ │
└───────────────────────────────────────────────────────────────┘
핵심 수치 요약
| 항목 | 수치 | 출처 |
|---|---|---|
| Istio Sidecar P99 오버헤드 | +166% | arXiv 2411.02267 |
| Istio Ambient P99 오버헤드 | +8% | arXiv 2411.02267 |
| Linkerd P99 오버헤드 | +33% | arXiv 2411.02267 |
| Cilium P99 오버헤드 | +99% | arXiv 2411.02267 |
| HPACK 헤더 압축률 | 평균 69% | Cloudflare |
| HTTP/3 글로벌 트래픽 비율 | 25% | Cloudflare Radar 2025 |
| Ambient 메모리 절감 | 최대 90%+ | Sidecar 대비 |
| Istio 인증서 기본 수명 | 24시간 | Istio 기본 설정 |
| mTLS 지연시간 오버헤드 | +1~3% | L4 ztunnel 기준 |
키워드 목록
HTTP/2, HTTP/3, QUIC, HPACK, Multiplexing, Binary Framing,
h2, h2c, ALPN, MaxConnectionAge, gRPC, Head-of-Line Blocking,
mTLS, Mutual TLS, Zero Trust, PeerAuthentication, STRICT, PERMISSIVE,
SPIFFE, SPIRE, SVID, X.509, cert-manager, Certificate Rotation,
Waypoint Proxy, Ambient Mesh, ztunnel, HBONE, Sidecar, DaemonSet,
Gateway API, istio-waypoint, istio.io/use-waypoint,
Circuit Breaker, Outlier Detection, Connection Pool, Bulkhead,
Resilience4j, Netflix Hystrix, Cascading Failure, Panic Threshold,
Closed, Open, Half-Open, Fail-Fast, Retry Storm,
Envoy, Istio, Linkerd, Cilium, Service Mesh, Kubernetes,
arXiv 2411.02267, WASM, WasmPlugin, East-West Gateway