Kyunghoon Kim
Notes

Networking / Jul 01, 2026 / 9 min

Istio: How a Service Mesh Works

Kubernetes Service와 Ingress의 차이부터 istiod, Envoy, Sidecar와 Ambient, 트래픽 관리, mTLS, 관측성까지 정리한다.

IstioKubernetesService MeshEnvoy

Summary

Istio는 애플리케이션 코드를 크게 바꾸지 않고 서비스 간 통신에 라우팅, 보안, 복원력, 관측 정책을 적용하는 Service Mesh다. Kubernetes Service를 대체하는 것이 아니라 Service가 제공하는 주소와 endpoint 정보 위에 더 세밀한 트래픽 제어 계층을 추가한다.

구성 요소주로 다루는 트래픽핵심 역할
Kubernetes Service클러스터 내부Pod 집합에 안정적인 주소와 service discovery를 제공한다.
Ingress / GatewayNorth-South외부 요청을 받아 host, path, TLS 조건에 따라 내부 Service로 전달한다.
Service Mesh주로 East-West서비스 간 통신에 라우팅, mTLS, 인가, retry, timeout, telemetry를 적용한다.
Istio Ingress GatewayNorth-Southmesh 경계의 Envoy가 외부 요청을 받아 Istio의 route와 연결한다.

핵심 차이는 Ingress는 외부에서 클러스터로 들어오는 입구에 집중하고, Service Mesh는 주로 내부 서비스 간 통신 전체를 다룬다는 것이다. Istio도 ingress gateway를 제공하므로 일부 기능은 겹치지만, Ingress를 사용한다고 내부 통신까지 자동으로 mesh가 되는 것은 아니다.

Istio의 구조는 두 영역으로 나뉜다.

영역핵심 구성 요소역할
Control planeistiod서비스와 정책을 발견하고 proxy 설정과 인증서를 배포한다.
Data planeEnvoy, ztunnel, waypoint실제 요청을 전달하고 L4/L7 정책을 실행한다.

istiod가 모든 요청을 중계하는 중앙 proxy는 아니다. 요청은 data plane을 통과하고, istiod는 data plane이 사용할 설정과 인증 정보를 관리한다.

Context

마이크로서비스가 늘어나면 단순히 다른 서비스의 주소를 호출하는 것 이상의 문제가 생긴다.

  • 새 버전을 일부 요청에만 보내고 안전하게 배포하려면 어떻게 해야 하는가?
  • 일시적인 오류에 재시도하되 장애를 증폭시키지 않으려면 어떻게 해야 하는가?
  • 서비스 간 요청을 암호화하고 호출자의 identity로 접근을 제한하려면 어떻게 해야 하는가?
  • 어느 서비스 구간에서 지연과 오류가 발생했는지 어떻게 확인할 수 있는가?

각 애플리케이션에 client library와 보안 코드를 넣을 수도 있지만, 언어와 framework가 다르면 구현과 운영 수준이 달라진다. Service Mesh는 이런 네트워크 공통 기능을 workload 주변의 data plane으로 옮겨 일관된 정책으로 관리한다.

Service, Ingress, and Service Mesh

Kubernetes Service

Pod는 생성과 삭제에 따라 IP가 바뀔 수 있다. Kubernetes Service는 label selector로 Pod 집합을 선택하고 그 앞에 안정적인 DNS 이름과 가상 IP를 제공한다.

model-service.ai-serving.svc.cluster.local
                         │
                         ├── model-v1 Pod
                         ├── model-v1 Pod
                         └── model-v2 Pod

Service는 클라이언트가 개별 Pod IP를 추적하지 않게 해준다. 기본 endpoint 선택과 연결성은 제공하지만 다음과 같은 정책은 중심 역할이 아니다.

  • HTTP header를 기준으로 v2에만 라우팅
  • v1과 v2에 90:10 비율로 트래픽 분배
  • 서비스 identity를 기준으로 요청 허용 또는 거부
  • 요청별 retry, timeout, fault injection

Istio는 Kubernetes의 Service와 EndpointSlice를 service discovery 정보로 활용하면서 그 위에 이 정책들을 추가한다.

Ingress and Gateway

Kubernetes Ingress는 클러스터 외부의 HTTP와 HTTPS 요청을 내부 Service에 연결하는 API다. hostpath 규칙을 선언하면 Ingress controller가 실제 proxy나 load balancer를 설정한다.

Internet
   │
External Load Balancer
   │
Ingress Controller
   ├── api.example.com → api-service
   └── app.example.com → frontend-service

Ingress object는 설정이며, 실제 트래픽은 NGINX, Kong, Envoy 같은 Ingress controller의 data plane이 처리한다. Kubernetes는 새로운 구축에서 Gateway API 사용을 권장한다. 기존 Ingress API는 유지되지만 기능 추가는 중단된 상태다.

Istio에서는 Kubernetes Gateway API 또는 Istio의 Gateway resource로 mesh 진입점을 설정할 수 있다. Gateway는 받을 port, protocol, host를 정하고, VirtualService 또는 HTTPRoute는 요청을 어느 서비스로 보낼지 정한다.

Service Mesh

Service Mesh는 주로 서비스에서 다른 서비스로 이동하는 East-West 트래픽을 다룬다.

frontend → AI gateway → model service → Redis
                      └──────────────→ Kafka

이 경로에서 mesh의 data plane은 트래픽 분할, retry, timeout, mTLS, authorization, metric과 access log 같은 기능을 수행한다. 외부 요청이 ingress를 통과한 뒤 frontend에서 API로, API에서 model server로 이동하는 내부 구간도 계속 관리한다.

실제 환경에서는 세 계층을 다음과 같이 함께 사용한다.

External Client
      │
Cloud Load Balancer
      │
Istio Ingress Gateway
      │
Kubernetes Service
      │
frontend → AI gateway → model service
             East-West traffic in the mesh

OpenStack이라면 앞단 load balancer가 Octavia일 수 있다. Octavia는 외부 VIP와 클러스터 진입 연결을, Istio ingress gateway는 HTTP route와 mesh 연결을, 내부 mesh는 mTLS와 canary routing을 담당한다. Kong이나 NGINX를 ingress로 유지하고 내부에만 Istio를 사용하는 구성도 가능하다.

Architecture and Request Flow

Control Plane: istiod

istiod는 Kubernetes API와 service registry에서 Service와 workload를 발견하고, Istio 정책을 Envoy가 이해할 수 있는 설정으로 바꿔 data plane에 배포한다. 또한 workload가 mTLS에 사용할 인증서의 발급과 순환에도 관여한다.

Kubernetes API / Istio Resources
              │
              ▼
           istiod
      ┌───────┼────────┐
      ▼       ▼        ▼
   Proxy A  Proxy B  Gateway

정책 변경은 istiod를 통해 전달되지만 정상적인 요청 경로는 client → istiod → server가 아니다. endpoint 선택과 실제 전송은 설정을 받은 data plane이 수행한다.

Sidecar Mode

Sidecar mode에서는 애플리케이션 container와 Envoy container가 같은 Pod에 존재한다. 네트워크 redirect 규칙이 애플리케이션의 inbound와 outbound 트래픽을 Envoy로 전달한다.

Pod A                              Pod B
┌───────────────┐                 ┌───────────────┐
│ Application A │                 │ Application B │
│       ↕       │                 │       ↕       │
│ Envoy Sidecar │ ──────────────→ │ Envoy Sidecar │
└───────────────┘                 └───────────────┘

frontend가 model Service를 호출하는 흐름은 다음과 같다.

  1. 애플리케이션이 Service DNS 이름으로 요청한다.
  2. outbound 연결이 local Envoy로 redirect된다.
  3. Envoy는 istiod에서 미리 받은 route와 endpoint 설정을 조회한다.
  4. VirtualService 조건에 따라 v1 또는 v2를 고른다.
  5. DestinationRule의 연결 정책을 적용해 endpoint를 선택한다.
  6. mesh 정책에 따라 목적지 proxy와 mTLS 연결을 맺는다.
  7. 목적지 Envoy가 요청을 application container에 전달한다.

Ambient Mode

Ambient mode는 모든 application Pod에 sidecar를 주입하지 않고 기능을 두 계층으로 나눈다.

계층구성 요소담당 기능
Secure L4 overlayztunnelnode 단위로 mTLS, identity, L4 authorization과 telemetry를 처리한다.
Optional L7 layerwaypoint proxynamespace 또는 workload 단위로 HTTP routing, L7 authorization과 telemetry를 처리한다.

ztunnel로 기본 보안 계층을 만들고 L7 정책이 필요한 위치에만 Envoy 기반 waypoint를 추가할 수 있다. Sidecar resource와 Pod lifecycle의 결합은 줄지만, 필요한 기능과 topology가 적용하려는 Istio 버전에서 지원되는지는 확인해야 한다.

비교 항목Sidecar modeAmbient mode
Proxy 배치workload Pod마다 Envoynode마다 ztunnel, 필요할 때 waypoint
L4/L7 처리각 Envoy가 모두 처리ztunnel은 L4, waypoint는 L7
Pod 변경sidecar 주입이 필요함application Pod에 sidecar를 넣지 않음
Resource 모델workload 수에 따라 proxy 증가node와 waypoint 단위로 공유

기존 운영 경험, 필요한 L7 기능, multi-cluster 요구사항, resource 비용과 장애 격리 방식을 기준으로 mode를 선택해야 한다.

Traffic Management

VirtualService and DestinationRule

VirtualService어떤 요청을 어디로 보낼지 정한다. DestinationRule은 route가 도착할 subset과 연결 정책을 정의한다.

다음 예시는 model Service 요청의 90%를 v1, 10%를 v2로 보낸다.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: model-service
  namespace: ai-serving
spec:
  hosts:
    - model-service.ai-serving.svc.cluster.local
  http:
    - route:
        - destination:
            host: model-service.ai-serving.svc.cluster.local
            subset: v1
          weight: 90
        - destination:
            host: model-service.ai-serving.svc.cluster.local
            subset: v2
          weight: 10
      timeout: 30s
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: model-service
  namespace: ai-serving
spec:
  host: model-service.ai-serving.svc.cluster.local
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2

Kubernetes Service가 app: model인 Pod 전체를 선택하고, DestinationRule이 그 안을 version label로 다시 나누는 구조다. weight는 매 10개 요청 중 정확히 1개가 v2로 간다는 뜻이 아니라, 요청 수가 많을 때 설정 비율에 가까워지는 분배다.

Header나 cookie로 내부 tester만 v2에 보낼 수도 있다.

http:
  - match:
      - headers:
          x-test-version:
            exact: v2
    route:
      - destination:
          host: model-service.ai-serving.svc.cluster.local
          subset: v2
  - route:
      - destination:
          host: model-service.ai-serving.svc.cluster.local
          subset: v1

조건부 route는 catch-all route보다 앞에 둬야 한다. 위에서부터 평가되는 규칙에서 catch-all이 먼저 나오면 아래 조건은 실행되지 않는다.

Reliability Policies

Istio는 retry, timeout, connection pool, outlier detection과 fault injection을 제공한다. 하지만 정책을 추가한다고 항상 더 안전해지는 것은 아니다.

  • Retry: 일시적 오류를 복구하지만 non-idempotent 요청이나 비싼 inference를 중복 실행할 수 있다.
  • Timeout: 무한 대기를 막지만 model loading과 streaming response에는 충분한 budget이 필요하다.
  • Circuit breaking: pending request와 connection을 제한하고 반복 오류 endpoint를 일시 제외한다.
  • Fault injection: 의도적인 지연과 오류로 timeout, fallback, alert를 검증한다.

특히 LLM serving에서는 이미 GPU에서 긴 요청이 실행 중인데 client가 timeout 후 재시도하면 같은 연산이 중복될 수 있다. Client, gateway, proxy, application의 timeout을 하나의 전체 request budget으로 설계해야 한다.

Envoy의 circuit breaking은 주로 connection pool 제한과 outlier detection으로 구성된다. application library의 CLOSED → OPEN → HALF_OPEN 상태 머신과 완전히 같지는 않으며, 장애 확산을 제한할 뿐 workload 자체를 복구하지는 않는다.

Security and Observability

Istio는 workload identity와 인증서를 이용해 서비스 간 mTLS를 구성할 수 있다. Kubernetes에서는 ServiceAccount가 identity의 중요한 기반이 된다.

정책역할
PeerAuthenticationworkload의 inbound mTLS mode를 설정한다.
RequestAuthenticationJWT 같은 end-user credential을 검증한다.
AuthorizationPolicysource identity, method, path 등으로 요청을 허용하거나 거부한다.

mTLS는 연결을 암호화하고 상대 identity를 인증하지만, 인증된 호출자가 모든 API를 호출해도 된다는 뜻은 아니다. 접근 범위는 AuthorizationPolicy로 별도 제한해야 한다.

Data plane은 서비스 통신에서 request rate, error, duration, access log와 trace span을 만들 수 있다. AI serving에서는 다음 지표를 함께 보는 것이 좋다.

  • 요청 수, p95와 p99 latency, 5xx와 timeout 비율
  • queue time, time to first token, tokens per second
  • GPU utilization과 memory usage

Istio는 네트워크 구간을 보여주지만 model 내부의 batch scheduling이나 CUDA 병목까지 자동으로 설명하지는 않는다. 또한 Envoy가 span을 생성해도 여러 서비스의 span을 하나로 연결하려면 애플리케이션이 trace context header를 다음 요청에 전달해야 한다.

Istio and Cilium

Cilium과 Istio는 모두 Kubernetes networking에 관여하지만 중심 역할이 다르다.

관점CiliumIstio
기본 역할CNI, Pod 연결, network policy, service load balancingService Mesh, traffic policy, workload identity, L7 telemetry
중심 계층L3/L4와 eBPF datapathL4/L7 proxy와 mesh control plane
대표 정책IP, port, endpoint 기반 정책HTTP route, mTLS, retry, timeout

경계가 절대적인 것은 아니다. Cilium도 L7 policy와 service mesh 기능을 제공할 수 있다. 함께 사용한다면 CNI, kube-proxy replacement, L7 policy, mTLS와 ingress를 어느 구성 요소가 맡는지 명확히 정해야 한다.

AI Serving Experiment

학습 환경에서는 model server 두 버전으로 canary experiment를 구성할 수 있다.

Client → Istio Ingress Gateway → AI Gateway
                                      ├── 90% → model-v1
                                      └── 10% → model-v2
  1. 같은 Service 아래 version: v1, version: v2 label의 Deployment를 배포한다.
  2. DestinationRule로 subset을 만들고 VirtualService로 90:10 분배를 적용한다.
  3. 버전별 request rate, p95/p99 latency, 5xx와 timeout을 수집한다.
  4. v2에 지연이나 오류를 넣어 outlier detection과 alert를 검증한다.
  5. v2가 기준을 넘으면 weight를 0으로 바꿔 rollback한다.

Canary 성공 기준은 배포 전에 정해야 한다. Pod가 Ready라는 사실만으로 inference latency, 품질, GPU memory pressure와 오류율이 안전하다고 판단할 수는 없다.

Trade-offs

  • Proxy와 control plane의 CPU, memory, latency 비용을 capacity에 포함해야 한다.
  • Kubernetes Service, Istio route, proxy, application route를 함께 디버깅해야 한다.
  • 잘못된 retry와 timeout은 장애를 줄이기보다 증폭할 수 있다.
  • Metric label과 access log를 과도하게 수집하면 비용과 cardinality가 증가한다.
  • Sidecar와 Ambient는 배치 구조와 지원 기능이 다르므로 실제 workload로 검증해야 한다.

Service Mesh는 application의 모든 복원력 코드를 대체하지 않는다. Idempotency, transaction, queue backpressure, model fallback처럼 application 의미를 알아야 하는 정책은 애플리케이션과 플랫폼이 함께 설계해야 한다.

Key Takeaways

  • Service는 안정적인 주소를, Ingress와 Gateway는 외부 진입 경로를, Service Mesh는 서비스 간 통신 정책을 제공한다.
  • Istio ingress gateway와 일반 Ingress controller는 일부 역할이 겹치지만 내부 mesh의 범위는 더 넓다.
  • istiod는 설정과 인증서를 관리하고, Envoy·ztunnel·waypoint가 실제 요청을 처리한다.
  • Sidecar mode는 workload마다 Envoy를 배치하고, Ambient mode는 ztunnel과 선택적인 waypoint로 L4와 L7을 나눈다.
  • VirtualService는 route를, DestinationRule은 subset과 destination policy를 정의한다.
  • mTLS 인증과 authorization은 별개이며, retry와 timeout은 workload 특성에 맞춰야 한다.

Review Questions

  1. Kubernetes Service, Ingress, Service Mesh는 각각 어떤 문제를 해결하는가?
  2. istiod가 요청의 load balancing을 직접 수행하지 않는 이유는 무엇인가?
  3. Sidecar mode와 Ambient mode의 data plane 배치는 어떻게 다른가?
  4. VirtualService와 DestinationRule을 함께 사용하는 이유는 무엇인가?
  5. LLM inference에 일반적인 retry 정책을 적용하면 어떤 문제가 생길 수 있는가?
  6. mTLS를 활성화한 뒤에도 AuthorizationPolicy가 필요한 이유는 무엇인가?

References