DevOps/Study

Istio Hands-on Study [1기] [2주차 1/2] Istio의 Data Plane Envoy Proxy

juyeon22 2025. 4. 19. 16:30
CloudNet@ 가시다님이 진행하는 Istio In Action 책 기반 Hands-on Study  

Chap.3 Istio의 Data Plane Envoy Proxy

학습 과제

  • 1.Istio안에서의 Envoy 동작 이해
  • 2.Envoy 기능 살펴보기
  • 3.Envoy 실습 및 디버깅 하기

1. Istio안에서의 Envoy 동작 이해

Proxy 란 ?

클라이언트와 서버 간 통신하는 과정 중 중간에 위치한 네트워크 중계요소입니다.

flowchart LR
    A["클라이언트 (사용자)"] -->|요청| B["프록시 서버"]
    B -->|요청 전달| C["목적지 서버"]
    C -->|응답| B
    B -->|응답 전달| A

Figure 1.1 Proxy 개념 설명

Proxy의 필요성

  • 클라이언트가 서버와 통신 할 때 진입점 만 알고도 통신을 하게 해줄 수 있게 해줍니다.
flowchart LR
    Client["클라이언트"] -->|요청| ReverseProxy["리버스 프록시"]
    ReverseProxy -->|요청 전달| Server1["서버1"]
    ReverseProxy -->|요청 전달| Server2["서버2"]
    Server1 -->|응답| ReverseProxy
    Server2 -->|응답| ReverseProxy
    ReverseProxy -->|응답 전달| Client

Figure 1.2 ReverseProxy 설명

  • Reverse Proxy설명을 통해 클라이언트는 리버스 프록시 의 주소만 알고 있어도 통신해야하는 서버거 어떤 서버인지 알 필요가 없습니다.

Envoy Proxy란 ?

  • 분산 시스템 구축 시 발생하는 Application Network 문제를 해결하고자 도입된 오픈소스 프로젝트 Proxy 입니다.
  • 리프트 사가 개발 했으며 C++ 으로 작성됐습니다.
  • 2가지 원칙을 기준으로 개발 됐습니다.
    • 네트워크는 투명해야 한다.
    • 문제 발생 시 원인 파악이 쉬워야 한다.
  • Envoy Proxy 는 일반적인 Proxy와 다르게 Serivce Discovery, Load Balancing, Health Check 같은 추가 기능을 지원합니다.
  •  

Envoy Proxy의 특징

  • 언어, 프레임워크와 무관하게 모든 Application이 사용할 수 있는 Proxy입니다.
  • Request TimeOut, Retry, RetryTimeout, Circuit Breaker 와 같은 Application의 복원력을 위한 기능도 사용 가능합니다.
  • Application 수준의 프로토콜도 이해할 수 있어, Application과 Envoy Proxy간의 요청/응답 정보를 수집할 수 있습니다.
  • 해당 정보를 토대로 Application의 처리량, 오류율과 같은 지표를 얻을 수 있습니다.
  • 다양한 프로토콜 을 지원합니다

Figure 1.3 Envoy가 지원하는 프로토콜 목록

Istio에서의 Envoy Prox 동작

flowchart LR
    subgraph DownStream
        Client["클라이언트"]
    end

    subgraph Cluster Edge
        EdgeProxy["Edge Proxy (IngressGateway)"]
    end

    subgraph Istio Service Mesh
        direction LR
        subgraph ServiceA["서비스 A"]
            AppA["애플리케이션 A"]
            EnvoyA["Envoy Proxy (사이드카)"]
        end
        subgraph ServiceB["서비스 B"]
            AppB["애플리케이션 B"]
            EnvoyB["Envoy Proxy (사이드카)"]
        end
    end

    subgraph Istio Control Plane
        Istiod["istiod"]
    end

    Client -->|"외부 요청(Down Stream)"| EdgeProxy
    EdgeProxy -->|Mesh 내부 트래픽| EnvoyA
    EnvoyA -->|서비스 간 통신| EnvoyB
    EnvoyA <-->|UpStream| AppA
    EnvoyB <-->|UpStream| AppB
    Istiod -.->|구성 및 정책 전달| EdgeProxy
    Istiod -.->|구성 및 정책 전달| EnvoyA
    Istiod -.->|구성 및 정책 전달| EnvoyB

Figure 1.3 Istio에서의 Envoy Proxy가 동작하는 프로세스

Envoy의 핵심 기능

Listener

  • Application 을 외부로 노출시키는 기능이며 해당 프로세스에서 Edge Proxy에 해당합니다.

Root

  • Listener 로 들어온 트래픽을 처리(라우팅)하는 기능이며 해당 프로세스에서 Mesh 내부 트래픽에 해당합니다.

Cluster

  • Root 가 라우팅을 하는 대상의 Envoy Proxy 를 뜻합니다.해당 프로세스에서 사이드 카에 해당합니다.

Service Discovery

  • 기존 Application Library 수준에서 제공하는 기능과 다르게, Envoy가 단순하게 End Point만 찾아가게 설멍 하면 간편하게 적용할 수 있습니다.
    • Service Discovery에 대한 정보는 Control Plane 이 가지고 있기 때문에 Control Plane 수준에서 적용하면 관리가 편해집니다.

Load Balancing

  • Envoy는 Application에서 활용할 수 있는 고급 Load Balancing 알고리즘을 제공합니다.

  • Figure 1.4 Envoy Proxy가 제공 하는 LB 알고리즘(Maglev(Sticky Session))*

트래픽 및 요청 기반 라우팅

  • Envoy는 다양한 Application 프로토콜(HTTP/ gRPC etc....)을 사용할 수 있어 프로토콜 기반 라우팅 도 지원합니다.
  • 기본적인 Context-Path 기반 라우팅 뿐만 아니라, 헤더 및, 가중치 기반 라우팅 , Retry, Timeout, Fault Injection 같은 고급 기능들을 지원합니다.

Shadowing 기능 제공

flowchart LR
    Client["클라이언트"] -->|실제 요청| Envoy["Envoy 프록시"]
    Envoy -->|실제 트래픽| Service["원본 서비스"]
    Envoy -. "Shadow(미러링) 요청".-> ShadowService["Shadow(테스트) 서비스"]

Figure 1.5 Shadowing 기능 설명 도표

Shadowing 기능이란 ?

  • 실제 트래픽을 테스트 서비스에 같이 배포를 하여 테스트를 할 수 있는 기능을 말합니다.

네트워크 복원력

  • Retry, Retry Timeout 과 같은 설정으로 Application의 복원력을 어느정도 해결 할 수 있지만, 해당 기능의 설정은 전반적으로 Application의 책임 입입니다.
  • UpStream Cluster 호출 시 진행 주인 Connection or Request의 갯수를 제한 할 수 있고, 임계치를 넘어가면 Fail처리하도록 지정할 수 있습니다.
  • Outlier Filter 적용하여 문제를 일으키는 EndPoint를 LB풀에서 제거할 수 있습니다.

메트릭 수집을 통한 관찰 가능성

  • Envoy는 네트워크를 이해하기 위한 다양한 메트릭을 수집합니다.

Figure 1.6 Envoy가 수집가능한 메트릭 정보

 

분산 트레이싱을 통한 관찰 가능성

  • Trace Span 정보를 OpenTracing Engine(zipkin, jaeger, tempo...) 에 전달하여 트래픽 흐름, 홉, 지연 시간과 같은 정보르를 시각화 할 수 있습니다.
  • 별도의 라이브러리가 필요하지 않으며, Header를 통해 구현할 수 있습니다.
  • 서비스 간 호출을 연관시키기 위해 x-request-id 헤더를 생성하고, Appliction이 호출을 연관 시키기위해서 자동으로 생성되는 헤더들은 다음과 같습니다.
    • x-b3-traceid: 전체 트레이스(Trace)를 식별하는 고유한 ID (64bit)
    • x-b3-spanid: 현재 작업(Span)을 식별하는 고유한 ID (64bit)
    • x-b3-parentspanid: 현재 span의 부모 span을 식별하는 ID (64bit)
    • x-b3-sampled: 이 요청을 트레이싱 시스템에 기록할지 여부를 결정 (0,1)
    • x-b3-flags: 트레이싱 옵션(예: 디버그 모드)을 지정 (64bit)

자동 TLS 종료 및 시작

  • 특정 서비스로 향하는 TLS 트래픽을 종료 할 수 있으며, Cluster Edge 뿐만 아니라, 서비스 메시 내부에서도 적용할 수 있습니다.
  • Envoy가 UpStream Cluster로 TLS 트래픽을 시작 할 수 있습니다.
  • 관리자나, 개발자가 언어별 KeyStore, 트러스트 스토어에 관여를 하지 않아도됩니다.

속도 제한

  • Envoy의 Retry설정 시 특정 장애의 영향이 과도하게 확대되는 것을 막기 위해 전역 속도 제한 기능을 사용할 수 있습니다.

Envoy와 다른 프록시 비교 시 장점
비교 시 다양한 장점이 있지만, 제가 생각했을때 가장 큰 장점은 해당 사항들입니다.

  • 유지보수 및 확장에 용이한 모듈식 코드베이스 기반
  • 다양한 프로토콜 지원
  • 심층 프로토콜 메트릭 수집
  • 동적 설정으로 hot restart가 필요없음

2.Envoy 기능 살펴보기

Envoy 설정하기

  • Envoy는 Listener, Root, Cluster 과 같은 기능 뿐만 아니라, Admin API 활성화 , 로그 경로, 트레이싱 엔진과 같은 설정을 지원합니다.

Envoy 정책 예시

static_resources:
  clusters:
  - name: xds_cluster # Control Plane에 연결하기 위한 클러스터
    type: STRICT_DNS
    connect_timeout: 5s
    # HTTP/2 사용 명시 (gRPC는 HTTP/2 기반)
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options: {} # HTTP/2 활성화
    load_assignment:
      cluster_name: xds_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: istiod.istio-system.svc.cluster.local # Control Plane 주소
                port_value: 15010

dynamic_resources:
 lds_config:
    resource_api_version: V3 # 사용할 리소스 API 버전 (v3가 현재 표준)
    api_config_source: # 어디서, 어떻게 설정을 가져올지 정의
      api_type: GRPC # API 통신 방식 (GRPC, REST, DELTA_GRPC 등) [3]
      transport_api_version: V3 # 전송 프로토콜 API 버전
      grpc_services: # gRPC 서비스 정의
        - envoy_grpc:
            cluster_name: xds_cluster
      set_node_on_first_message_only: true

  cds_config:
    resource_api_version: V3
    api_config_source: # LDS와 동일한 Control Plane 사용
      api_type: GRPC
      transport_api_version: V3
      grpc_services:
        - envoy_grpc:
            cluster_name: xds_cluster
      set_node_on_first_message_only: true
  sds_config:
    resource_api_version: V3
    api_config_source:
      api_type: GRPC
      transport_api_version: V3
      grpc_services:
        - envoy_grpc:
            cluster_name: xds_cluster # 일반적으로 다른 xDS와 같은 서버 사용
      set_node_on_first_message_only: true

Envoy 정적 구성

Listener 부는 Envoy가 수신할 포트를 지정합니다.
filter_chains 부는 Listener가 수신한 트래픽을 처리하는 부분입니다.

http_connection_manager 는 HTTP 요청에 대해서 처리하는 부분입니다.
@tpye부 는 Envoy가 Filter로 수행할 http_connection_manager 부분에 대해 명세한 내용입니다.

virtual host 부는 호스트명, 매칭할 도메인 명을 지정하여 처리를 하는 부분입니다.

route, match 부를 사용하여 라우팅 대상을 지정합니다.

cluster 부는 리스너로 전달받은 트래픽을 어느 서비스로 전달하지 지정하는 부분입니다.

최종 도착지의 IP와 LB 방식과 같은 내용이 포함되어있습니다.

 

Envoy 동적 구성

  • Envoy는 API호출을 통해, 재시작 없이 설정을 실시간으로 업데이트 할 수 있으며, 설정 시 xDS API 를 사용합니다.
  • LDS(Listener Discovery Service)
    • Envoy가 노출해야할 Listener을 알려주는 API 서비스를 말합니다.
  • RDS(Route Discovery Serivce)
    • LDS의 일부이며, 라우팅 정보를 가져오는 API 서비스 이며, 필수는 아닙니다.
  • CDS(Cluster Discovery Service)
    • Envoy가 클러스터 목록을 찾고 각 클러스터의 설정을 찾는 API 서비스 입니다.
  • EDS(Endpoint Discovery Serivce)
    • CDS의 일부이며, 클러스터에서 어떤 엔드포인트를 사용해야할지 설정하는 API 서비스 입니다.
  • SDS(Security Discovery Serivce)
    • 인증서를 적용할 때 사용하는 API 서비스 입니다.
  • ADS(Aggregate Discovert Serivce)
    • xDS API궁극적 일관성 을 기반이기 때문에 해당 기능을 구현하기 위한 API 서비스 입니다.

xds_config 항목들을 선언하여, 리스너를 설정합니다.

ads 필드 를 이용하여 리스너의 설정을 구현 합니다.

3.Envoy 실습 및 디버깅 하기

Envoy 실습 개요

sequenceDiagram
    participant Client as 클라이언트
    participant EnvoyProxy as Envoy Proxy
    participant WebServer as HTTPS 웹 서버

    Client->>+EnvoyProxy: HTTP 요청
    Note right of EnvoyProxy: 수신된 HTTP 요청, 라우팅 규칙 확인
    EnvoyProxy->>+WebServer: HTTP 요청
    Note left of WebServer: 수신된 HTTP 요청 처리
    WebServer-->>-EnvoyProxy: HTTP 응답
    Note right of EnvoyProxy: 수신된 HTTP 응답 처리
    EnvoyProxy-->>-Client: HTTP 응답

Figure 3.1 Envoy 실습 개요

Envoy 실습

# http 서비스 실행
docker run -d -e PORT=8000 --name httpbin mccutchen/go-httpbin 

docker run -it --rm --link httpbin curlimages/curl curl -X GET http://httpbin:8000/headers

# Result
{
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin:8000"
    ],
    "User-Agent": [
      "curl/8.13.0"
    ]
  }
}

# Envoy Proxy 설정 파일이 있는 경로로 이동
cd ~/istio-in-action/book-source-code-master/
cat ch3/simple.yaml

# Result Do not Copy!!!!!
admin:
  address:
    socket_address: { address: 0.0.0.0, port_value: 15000 }

static_resources:
  listeners:
  - name: httpbin-demo
    address:
      socket_address: { address: 0.0.0.0, port_value: 15001 }
    filter_chains:
    - filters:
      - name:  envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            name: httpbin_local_route
            virtual_hosts:
            - name: httpbin_local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service
  clusters:
    - name: httpbin_service
      connect_timeout: 5s
      type: LOGICAL_DNS
      dns_lookup_family: V4_ONLY
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: httpbin
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: httpbin
                  port_value: 8000 # httpbin 포트


docker run --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple.yaml)"

# Result Do not Copy!!!!! (작동확인)
[2025-04-19 05:34:13.868][1][info][config] [source/server/listener_manager_impl.cc:834] all dependencies initialized. starting workers
[2025-04-19 05:34:13.870][1][info][main] [source/server/server.cc:804] starting main dispatch loop


# 세션 복제 후 curl로 Proxy 호출
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/header

# Result Do not Copy!!!!! (작동확인)
{
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin"
    ],
    "User-Agent": [
      "curl/8.13.0"
    ],
    "X-Envoy-Expected-Rq-Timeout-Ms": [
      "15000"
    ],
    "X-Forwarded-Proto": [
      "http"
    ],
    "X-Request-Id": [
      "f95484d5-4857-4ddd-bf7a-626fc6af6be7"
    ]
  }
}

# Envoy Proxy 종료
docker rm -f proxy

X-Envoy-Expected-Rq-Timeout-Ms, X-Forwarded-Proto, X-Request-Id 헤더가 추가된 것을 확인 할 수 있습니다.

  • X-Envoy-Expected-Rq-Timeout-Ms
    • UpStream에 대한 힌트이며, 타임 아웃 시간을 나타냅니다.
  • X-Forwarded-Proto
    • 접속했던 사용했던 프로토콜을 나타냅니다.
  • X-Request-Id
    • 요쳥 간 파악을 위해 사용하는 헤더입니다.

설정파일을 수정하여 Envoy Proxy 추가 실습

# Timeout 설정을 추가한 Envoy Proxy 설정 적용
docker run --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple_change_timeout.yaml)"

# 설정 확인
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/headers


# Result Do not Copy!!!!!
# X-Envoy-Expected-Rq-Timeout-Ms 값 변경 사항 확인
{
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin"
    ],
    "User-Agent": [
      "curl/8.13.0"
    ],
    "X-Envoy-Expected-Rq-Timeout-Ms": [
      "1000"
    ],
    "X-Forwarded-Proto": [
      "http"
    ],
    "X-Request-Id": [
      "f31187f5-5cb7-4d53-9f1f-a1e79aae17aa"
    ]
  }
}

# Envoy Admin API를 통해 변경된 Timeout이 정상적으로 작동하는지 확인
# LogLevel 변경
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug
# delay 2초 적용
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/2

# Result Do not Copy!!!!!
upstream request timeout

Envoy Admin API 실습

# Envoy 통계 및 메트릭 출력 
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats

# Result Do not Copy!!!!!
cluster.httpbin_service.assignment_stale: 0
cluster.httpbin_service.assignment_timeout_received: 0
cluster.httpbin_service.bind_errors: 0
cluster.httpbin_service.circuit_breakers.default.cx_open: 0
cluster.httpbin_service.circuit_breakers.default.cx_pool_open: 0
cluster.httpbin_service.circuit_breakers.default.rq_open: 0
cluster.httpbin_service.circuit_breakers.default.rq_pending_open: 0
...

# Admin API를 이용한 다른 설정 값 출력
# 머신상의 인증서
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/certs
# 엔보이에 설정한 클러스터
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/clusters
# 엔보이 설정 덤프
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/config_dump
# 엔보이에 설정한 리스너
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/listeners
# 로깅 설정 확인 가능 
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging 
# 로깅 설정 편집 가능
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug 
# 엔보이 통계(프로메테우스 레코드 형식)
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats/prometheus 

Envoy가 Istio와 적합한 이유

  • Envoy를 최대한 활용하기 위해서 부가 기능을 구현 한 것이 Istio이기 떄문입니다.
  • istiod의 Control Plane 에서 Envoy의 xDS API를 구현 하여 관리 포인트를 줄여 줍니다.
  • Envoy에서 발생한 Metric과 Telemetry 정보 들을 통합 하기 위해 Istio를 사용합니다.
  • Serivce Mesh 내의 TLS 트래픽의 종료 및 시작 을 설정하기 위해 Istio를 사용합니다.
graph LR
    subgraph "Control Plane"
        Istiod["Istiod (Control Plane)"]
    end

    subgraph "Kubernetes API"
        K8sAPI["K8s API Server<br/>Services, Endpoints, Istio CRDs"]
    end

    subgraph "Data Plane"
        subgraph "Pod A Client"
            direction LR
            App_A["App A"] -- "Traffic" --> Envoy_A["Envoy A"]
        end

        subgraph "Pod B Server"
            direction LR
            Envoy_B["Envoy B"] -- "Traffic" --> App_B["App B"]
        end
    end

    subgraph "Observability"
        ObservabilityBackend["Observability<br/>Prometheus, Jaeger, etc."]
    end

    %% Configuration Flow - Links with simplified labels
    K8sAPI -- "WatchesResources" --> Istiod;
    Istiod -- "PushesConfig" --> Envoy_A;
    Istiod -- "PushesConfig" --> Envoy_B;

    %% Data Flow - Link with simplified label
    Envoy_A -- "ServiceTraffic_mTLS" --> Envoy_B;

    %% Telemetry Flow - Links with simplified labels
    Envoy_A -- "SendsTelemetry" --> ObservabilityBackend;
    Envoy_B -- "SendsTelemetry" --> ObservabilityBackend;

    %% Styling (Optional)
    classDef control fill:#f9f,stroke:#333,stroke-width:2px;
    classDef data fill:#ccf,stroke:#333,stroke-width:2px;
    classDef infra fill:#cfc,stroke:#333,stroke-width:2px;

    class Istiod control;
    class Envoy_A,Envoy_B data;
    class App_A,App_B data;
    class K8sAPI,ObservabilityBackend infra;

Figure 3.2 Istio와 Envoy