istio를 다루다보면 envoy proxy에 대한 내용도 이해해야 하고, EnvoyFilter를 사용하여 라우팅룰을 조금 더 자유롭게 구성하기 위해서 envoy proxy에 대한 내용을 잘 알아야 한다. 특히 EnvoyFilter의 필드는 envoy proxy에 대한 스펙을 다루기 때문이다.
그래서 이번 시간에는 istio와 envoy proxy와의 관계와 istio를 다루기 위해 필요한 envoy proxy의 기초 지식에 대해 알아보는 시간을 가지도록 하겠다.
envoy proxy란?
envoy는 대규모 현대 서비스 지향 아키텍처를 위해 설계된 L7 proxy 및 통신 버스이다. Envoy는 다음과 같은 철학을 가지고 개발하였다.
네트워크는 애플리케이션에 투명해야 하며, 네트워크 또는 애플리케이션에서 문제가 발생하면 문제의 근원을 쉽게 파악할 수 있어야 한다.
Envoy는 다음과 같이 여러가지 고급 기능을 제공하여 네트워크와 애플리케이션을 투명하게 하려고 한다. istio에서 제공한다고 하는 기능들은 모두 envoy proxy에서 왔다고 보면 된다.
- L3/L4 네트워크 프록시
- HTTP 기반 L7 프록시
- HTTP/1.1 ~ HTTP/2 (HTTP/3) 및 gRPC 지원
- 서비스 디스커버리 및 로드밸런싱
- 헬스체크
- observability
- Circuit breaking
- Rate limit
- 동적 구성 (xDS)
Terminology
Envoy 에서 사용하는 용어는 다음과 같으며 envoy proxy의 구성에서도 마찬가지로 해당 용어를 사용한다.
- Cluster: Envoy가 요청을 포워딩하는 엔드포인트 집합을 갖춘 논리적 서비스
- Endpoints: 논리적 서비스를 구현하는 네트워크 노드, 클러스터로 그룹화 되어있다
- Downstream: Envoy에 연결하는 엔티티이며 로컬 애플리케이션 도는 네트워크 노드가 될 수 있다. 사이드카가 아닌 모델에서 이는 외부 클라이언트이다.
- Upstream: Envoy가 서비스에 대한 요청을 전달할 때 연결하는 엔드포인트이다. 이는 로컬 애플리케이션 또는 네트워크 노드가 될 수 있으며 사이드카가 아닌 모델에서 이는 외부 백엔드에 해당한다.
- Filter: 요청 처리의 일부 측면을 제공하는 연결 또는 요청 처리 파이프라인 모듈
- Filter chain: 체이닝된 일련의 필터
- Listener: IP/Port를 바인딩하는 책임이 있는 envoy 모듈, 새로운 TCP 연결을 수락하고 요청 처리의 다운스트림 측면을 조율하는 역할을 한다.
Request flow
Envoy는 이벤트 기반 쓰레드 모델이다. 메인 스레드는 서버 라이프사이클, 구성 처리, 통계 등을 담당하고 일부의 워커 쓰레드는 요청을 처리한다. 모든 쓰레드는 이벤트 루프를 중심으로 작동하며 모든 다운스트림 TCP 연결은 해당 연결의 수명 동안 정확히 하나의 워커 쓰레드에 의해 처리된다. 각 워커 쓰레드는 업스트림 엔드포인트에 대한 자체 TCP 연결 풀을 유지한다.
워커 쓰레드는 상태를 거의 공유하지 않으며 병렬적인 방식으로 작동힌다. 이 쓰레드 모델을 사용하면 매우 많은 코어 수가 있는 CPU로 확장할 수 있다.
만약 envoy의 구성이 다음과 같다고 하자.
static_resources:
listeners:
# 443 포트에 바인딩 되어있는 하나의 Listener
- name: listener_https
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 443
# listener filter에 TLS inspector만 존재한다.
listener_filters:
- name: "envoy.filters.listener.tls_inspector"
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
# 해당 리스너에 acme.com의 SNI와 일치하는 filter chain이 하나 있다.
filter_chains:
- filter_chain_match:
# TLS Inspector filter에 의해 추출되는 SNI와 일치함.
server_names: ["acme.com"]
# TLS 처리 (TLS transport socket)
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: {filename: "certs/servercert.pem"}
private_key: {filename: "certs/serverkey.pem"}
# Network Filter가 들어갈 자리
filters:
# 여기에는 HTTP connection manager 만 존재.
- 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
use_remote_address: true
http2_protocol_options:
max_concurrent_streams: 100
# Access log 구성
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/var/log/envoy/access.log"
# Route 구성
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["acme.com"]
routes:
- match:
path: "/foo"
route:
cluster: some_service
# HTTP filter chain (지금은 Router filter만 존재).
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: some_service
# Upstream TLS configuration.
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
load_assignment:
cluster_name: some_service
# Static endpoint assignment.
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.1.2.10
port_value: 10002
- endpoint:
address:
socket_address:
address: 10.1.2.11
port_value: 10002
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:
max_concurrent_streams: 100
- name: some_statsd_sink
# The rest of the configuration for statsd sink cluster.
# statsd sink.
stats_sinks:
- name: envoy.stat_sinks.statsd
typed_config:
"@type": type.googleapis.com/envoy.config.metrics.v3.StatsdSink
tcp_cluster_name: some_statsd_sink
위의 구성을 envoy proxy에 적용했을 때 HTTP를 처리하는 envoy proxy로 들어오는 하나의 요청에 대해 워커 쓰레드에서 어떤 과정으로 요청이 흐르는지에 대해 보여준다.

- 워커 쓰레드에서 구동 중인 envoy listener에 의해 다운스트림의 TCP 연결이 수락된다.
- Listener filter chain이 생성되고 구동한다. 여기서는 SNI 및 기타 TLS 이전 정보를 제공할 수 있다. 성공하면 listener는 network filter chain을 일치시킨다. 각 리스너는 목적지 IP CIDR, SNI, ALPN, source port 등의 조합과 일치하는 여러 개의 필터 체인을 가질 수 있다. TLS transport socket이 이 필터 체인과 연결되어 있다.
- 네트워크를 읽으면 TLS transport socket은 데이터를 복호화하여 추가 처리를 위해 복호화된 데이터 스트림으로 변환한다.
- network filter chain이 생성되고 실행된다. HTTP에 가장 중요한 필터는 HTTP connection filter로 체인의 마지막 네트워크 필터이다.
- HTTP connection manager의 HTTP/2 codec은 TLS 연결에서 복호화된 데이터 스트림을 여러 개의 독립적인 스트림으로 프레임 해제하고 디멀티플렉싱 한다. 각 스트림은 단일 요청과 응답을 처리한다.
- 각 HTTP 스트림에 대해 다운스트림 HTTP filter chain이 생성되고 구동된다. 요청은 처음에 CustomFilter를 통해 통과하는데 여기서 요청을 읽고 수정할 수 있다. 가장 중요한 HTTP filter는 router filter이며, 여기서는 HTTP filter chain 끝에 위치한다. router filter에서
decodeHeader
가 호출되면 라우트가 선택되고 클러스터가 선택된다. 스트림에서 요청 헤더는 클러스터의 업스트림 엔드포인트로 전달된다. router filter는 이를 위해 일치하는 클러스터에 대한 cluster manager로부터 HTTP connection pool을 얻는다. - 엔드포인트를 찾기 위해 클러스터 특정 로드밸런싱이 수행된다. 새로운 스트림을 허용할지 판단하기 위해 클러스터의 서킷 브레이커를 확인한다. 엔드포인트의 커넥션 풀이 비어있거나 용량이 부족한 경우 엔드포인트에 대한 새로운 연결이 생성된다.
- 각 스트림에 대해 업스트림 HTTP filter chain이 생성되고 실행된다. 기본적으로 여기에는 적절한 코덱으로 데이터를 보내는
CodecFilter
만이 포함된다. 하지만 클러스터가 Upstream HTTP filter chain을 구성하면 filter chain이 생성되고 실행된다. 여기에는 재시도 및 쉐도잉된 요청에 대한 별도의 filter chain을 만들고 실행하는 것이 포함된다. - 업스트림 엔드포인트 연결의 HTTP/2 코덱은 단일 TCP 연결을 통해 해당 업스트림으로 전송되는 다른 스트림과 요청 스트림을 멀티플렉싱하고 프레임화 한다.
- 업스트림 엔드포인트 연결의 TLS transport socket은 바이트를 암호화하여 업스트림 연결을 위한 TCP 소켓에 쓴다.
- 헤더와 선택적 바디 및 트레일러를 구성하는 요청은 업스트림으로 프록시되고 응답이 다운스트림으로 프록시된다. 응답은 codec filter에서 시작하여 업스트림 HTTP filter를 통과한 다음 router filter를 통과하고 Custom filter를 통과한 후 다운스트림으로 전송되기 전에 요청과 반대 순서로 HTTP filter를 통과한다.
- 독립적인 half-close가 활성화되는 경우 요청과 응답이 모두 완료된 후 스트림이 해제된다. 그리고 응답은 성공 (2XX) 를 내려준다. 그렇지 않으면 응답이 완료되면 스트림이 해제되고 요청이 아직 완료되지 않앗떠라고 마찬가지이다. 요청 후 처리가 통계를 업데이트하고 엑세스 로그를 남기고 추적 스팬을 마무리한다.
istio는 Envoy proxy 중앙 관리
istio는 애플리케이션 부분과 네트워크 부분을 투명하게 관리하기 위해 사용되는 서비스 메쉬 오픈소스로, istio 소개 글에서 설명하였듯이 컨트롤 플레인과 데이터 플레인으로 나뉜다.

데이터 플레인은 서비스 메쉬 안에 들어있는 애플리케이션에 envoy proxy
가 사이드카로 들어있는 형태로 구성되어 있고, 그 외에는 메쉬 안으로 들어오는 트래픽을 받는 ingressgateway
와 메쉬 밖으로 나가는 트래픽을 처리하는 egressgateway
가 존재한다. ingressgateway
와 egressgateway
는 모두 envoy proxy
의 일종이다.
컨트롤 플레인은 istiod
로 존재하며 사이드카 또는 ingress/egressgateway의 envoy proxy
의 구성을 중앙 관리한다. 쿠버네티스 관리자가 Gateway
나 VirtualService
등의 istio 커스텀 리소스를 추가/변경/삭제 하면 istiod가 변경사항을 감지하여 적절한 envoy-proxy
의 구성을 변경한다.
그렇다면 istiod는 istio 커스텀 리소스의 변경사항을 감지하여 어떤 방식으로 envoy-proxy의 설정을 변경할까?
xDS
Envoy는 파일 시스템을 통하거나 관리 서버에 쿼리를 보내서 동적 리소스를 검색할 수 있다. 이러한 검색 서비스와 API를 통틀어서 xDS (eXtensible Discovery Services) 이라고 한다. 리소스는 구독을 통해 요청되고, 감시할 파일 시스템 경로를 지정하거나 gRPC 스트림을 사용하거나 REST-JSON URL을 폴링하는 형식으로 동적 리소스를 확인한다.

istio에서는 리소스 관리 서비스는 istiod
이며 istiod에서는 VirtualService
, Gateway
등의 istio 커스텀 리소스의 변경사항을 감지한 후 변경사항이 발생했다면 해당 커스텀 리소스를 envoy의 구성으로 변환한 다음 istiod를 구독한 envoy proxy 중에 구성의 타깃이 되는 envoy proxy에 xDS로 동적 구성을 PUSH한다.
그리고 envoy-proxy (사이드카 및 게이트웨이) 는 파드(컨테이너)가 뜨는 시점에 istiod를 구독하기 위해 커넥션을 맺는다. 구독이 완료되어야 istiod
에서 server-side PUSH 를 할 수 있기 때문이다.
xDS의 종류는 여러가지가 있다.
- LDS (Listener)
- RDS (Route)
- CDS (Cluster)
- EDS (Endpoint)
- SDS (Secret)
- ADS (Aggregate) 등
로그 뜯어보기
로그를 통해 istio 커스텀 리소스를 추가/변경/삭제하면 어떤 일이 발생하는지 확인해보자.
istiod
먼저 모든 커스텀 리소스를 삭제하고 모든 istio 컴포넌트를 재구동한 상태에서 istiod의 로그를 확인해보자.
2025-02-18T14:54:44.322674Z info FLAG: --caCertFile=""
2025-02-18T14:54:44.322860Z info FLAG: --clusterAliases="[]"
...
2025-02-18T14:54:44.352388Z info Loaded MeshNetworks config from Kubernetes API server.
2025-02-18T14:54:44.352404Z info mesh networks configuration updated to: {
}
2025-02-18T14:54:44.353703Z info Loaded MeshConfig config from Kubernetes API server.
2025-02-18T14:54:44.354199Z info mesh configuration updated to: {
"proxyListenPort": 15001,
"proxyInboundListenPort": 15006,
...
}
2025-02-18T14:54:44.361014Z info initializing mesh networks from mesh config watcher
2025-02-18T14:54:44.361095Z info mesh configuration: {
"proxyListenPort": 15001,
"proxyInboundListenPort": 15006,
...
}
...
2025-02-18T14:54:44.363408Z info initializing mesh handlers
2025-02-18T14:54:44.363688Z info model reloading network gateways
2025-02-18T14:54:44.363973Z info creating CA and initializing public key
2025-02-18T14:54:44.364084Z info Using istiod file format for signing ca files
2025-02-18T14:54:44.364140Z info Use self-signed certificate as the CA certificate
2025-02-18T14:54:44.366090Z info pkica Load signing key and cert from existing secret istio-system/istio-ca-secret
2025-02-18T14:54:44.366560Z info pkica Using existing public key: -----BEGIN CERTIFICATE-----
MIIC/TCCAeWgAwIBAgIRALvmlLV2nf4b7lBT0y1XoY0wDQYJKoZIhvcNAQELBQAw
...
-----END CERTIFICATE-----
2025-02-18T14:54:44.366697Z info pkica Set secret name for self-signed CA cert rotator to istio-ca-secret
2025-02-18T14:54:44.366791Z info rootcertrotator Set up back off time 32m3s to start rotator.
2025-02-18T14:54:44.366848Z info initializing controllers
2025-02-18T14:54:44.366891Z info rootcertrotator Jitter is enabled, wait 32m3s before starting root cert rotator.
2025-02-18T14:54:44.367562Z info Adding Kubernetes registry adapter
2025-02-18T14:54:44.367709Z info Discover server subject alt names: [istio-pilot.istio-system.svc istiod-1-23-4.istio-system.svc istiod-remote.istio-system.svc istiod.istio-system.svc]
2025-02-18T14:54:44.367839Z info initializing Istiod DNS certificates host: istiod-1-23-4.istio-system.svc, custom host:
2025-02-18T14:54:44.603751Z info Generating istiod-signed cert for [istio-pilot.istio-system.svc istiod-1-23-4.istio-system.svc istiod-remote.istio-system.svc istiod.istio-system.svc]:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
2025-02-18T14:54:44.603797Z info Using istiod file format for signing ca files
2025-02-18T14:54:44.603804Z info Use roots from istio-ca-secret
2025-02-18T14:54:44.603982Z info x509 cert - Issuer: "O=cluster.local", Subject: "", SN: 315c7d66cc8771ffb550c0165b1336e9, NotBefore: "2025-02-18T14:52:44Z", NotAfter: "2035-02-16T14:54:44Z"
2025-02-18T14:54:44.603988Z info Istiod certificates are reloaded
- 첫 로그를 보면 기본으로 설정된 FLAGS를 출력하고 설정한 meshConfig를 불러와서 istiod의 구성을 설정한다.
- 그 다음에는 istiod와 mesh간 gRPC 통신을 위해 인증서를 가져온다.
istio-system/istio-ca-secret
시크릿에 인증서 정보가 있다.
2025-02-18T14:54:44.604115Z info spiffe Added 1 certs to trust domain cluster.local in peer cert verifier
2025-02-18T14:54:44.604126Z info initializing secure discovery service
2025-02-18T14:54:44.604183Z info initializing secure webhook server for istiod webhooks
2025-02-18T14:54:44.610317Z info initializing sidecar injector
2025-02-18T14:54:44.632181Z info initializing config validator
2025-02-18T14:54:44.632255Z info initializing registry event handlers
2025-02-18T14:54:44.632340Z info starting discovery service
2025-02-18T14:54:44.632416Z info initializing CA server with IstioD CA
2025-02-18T14:54:44.633692Z info Starting Istiod Server with primary cluster Kubernetes
2025-02-18T14:54:44.633869Z info ControlZ available at 127.0.0.1:9876
2025-02-18T14:54:44.634446Z info kube Initializing Kubernetes service registry "Kubernetes"
2025-02-18T14:54:44.634722Z info status Starting status manager
2025-02-18T14:54:44.634862Z info Starting validation controller
2025-02-18T14:54:44.634958Z info Starting ADS server
2025-02-18T14:54:44.635054Z info starting CA server
2025-02-18T14:54:44.635108Z info klog attempting to acquire leader lease istio-system/istio-leader...
2025-02-18T14:54:44.635272Z info Istiod CA has started
2025-02-18T14:54:44.635358Z info cluster "Kubernetes" kube client started
2025-02-18T14:54:44.634784Z info Starting multicluster remote secrets controller
2025-02-18T14:54:44.635587Z info klog attempting to acquire leader lease istio-system/istio-gateway-status-leader...
2025-02-18T14:54:44.635795Z info controllers starting controller=healthcheck
2025-02-18T14:54:44.635953Z info klog attempting to acquire leader lease istio-system/istio-gateway-deployment-1-23-4...
2025-02-18T14:54:44.636594Z info controllers starting controller=auto-register existing connections
2025-02-18T14:54:44.636718Z info controllers starting controller=unregister_workloadentry
2025-02-18T14:54:44.637213Z info kube Starting Pilot K8S CRD controller controller=crd-controller
2025-02-18T14:54:44.637246Z info kube controller "gateway.networking.k8s.io/v1/GRPCRoute" is syncing... controller=crd-controller
2025-02-18T14:54:44.639479Z info kube controller "gateway.networking.k8s.io/v1beta1/GatewayClass" is syncing... controller=crd-controller
2025-02-18T14:54:44.648217Z info kube controller "gateway.networking.k8s.io/v1beta1/ReferenceGrant" is syncing... controller=crd-controller
2025-02-18T14:54:44.654714Z info multicluster remote secrets controller cache synced in 19.92704ms
2025-02-18T14:54:44.654734Z info controllers starting controller=multicluster secret
2025-02-18T14:54:44.657167Z info controllers starting controller=validation
2025-02-18T14:54:44.657389Z info controllers starting controller=ingress
2025-02-18T14:54:44.658358Z info controllers starting controller=default revision
2025-02-18T14:54:44.658382Z info kube controller "extensions.istio.io/v1alpha1/WasmPlugin" is syncing... controller=crd-controller
2025-02-18T14:54:44.658552Z info controllers starting controller=default revision
2025-02-18T14:54:44.658572Z info controllers starting controller=default revision
2025-02-18T14:54:44.667388Z info controllers starting controller=webhook patcher
2025-02-18T14:54:44.676250Z info controllers starting controller=crd watcher
2025-02-18T14:54:44.676391Z info controllers starting controller=configmap istio-sidecar-injector-1-23-4
2025-02-18T14:54:44.676481Z info authorizationpolicies.security.istio.io is now ready, building client
2025-02-18T14:54:44.676699Z info destinationrules.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676806Z info envoyfilters.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676904Z info gateways.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676966Z info peerauthentications.security.istio.io is now ready, building client
2025-02-18T14:54:44.677026Z info proxyconfigs.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677122Z info requestauthentications.security.istio.io is now ready, building client
2025-02-18T14:54:44.677213Z info serviceentries.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677316Z info sidecars.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677412Z info telemetries.telemetry.istio.io is now ready, building client
2025-02-18T14:54:44.677487Z info virtualservices.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677607Z info wasmplugins.extensions.istio.io is now ready, building client
2025-02-18T14:54:44.677685Z info workloadentries.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677750Z info workloadgroups.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676310Z info kube controller "networking.istio.io/v1alpha3/Gateway" is syncing... controller=crd-controller
2025-02-18T14:54:44.710448Z info kube kube controller for Kubernetes synced after 73.949042ms
2025-02-18T14:54:44.710492Z info kube Pilot K8S CRD controller synced in 73.277254ms controller=crd-controller
- 이 이후에는 istiod에 필요한 컴포넌트들을 시작시킨다.
2025-02-18T14:54:44.710910Z info model Full push, new service argocd/argocd-applicationset-controller.argocd.svc.cluster.local
2025-02-18T14:54:44.710947Z info model Full push, new service argocd/argocd-dex-server.argocd.svc.cluster.local
2025-02-18T14:54:44.710998Z info model Full push, new service argocd/argocd-redis.argocd.svc.cluster.local
2025-02-18T14:54:44.711020Z info model Full push, new service argocd/argocd-repo-server.argocd.svc.cluster.local
2025-02-18T14:54:44.711088Z info model Full push, new service argocd/argocd-server.argocd.svc.cluster.local
2025-02-18T14:54:44.711166Z info model Full push, new service bookinfo/details.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711191Z info model Full push, new service bookinfo/productpage.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711275Z info model Full push, new service bookinfo/ratings.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711325Z info model Full push, new service bookinfo/reviews.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711419Z info model Full push, new service default/kubernetes.default.svc.cluster.local
2025-02-18T14:54:44.711451Z info model Full push, new service istio-system/egressgateway.istio-system.svc.cluster.local
2025-02-18T14:54:44.711549Z info model Full push, new service istio-system/ingressgateway.istio-system.svc.cluster.local
2025-02-18T14:54:44.711578Z info model Full push, new service istio-system/istiod-1-23-4.istio-system.svc.cluster.local
2025-02-18T14:54:44.711649Z info model Full push, new service kube-system/kube-dns.kube-system.svc.cluster.local
2025-02-18T14:54:44.711752Z info model Full push, new service kube-system/metrics-server.kube-system.svc.cluster.local
2025-02-18T14:54:44.711781Z info model Full push, new service metallb-system/webhook-service.metallb-system.svc.cluster.local
2025-02-18T14:54:44.711817Z info model Full push, new service middleware/mysql-hs.middleware.svc.cluster.local
2025-02-18T14:54:44.711861Z info model Full push, new service middleware/mysql.middleware.svc.cluster.local
2025-02-18T14:54:44.711912Z info model Full push, new service todo/todo-api.todo.svc.cluster.local
2025-02-18T14:54:44.779286Z info Waiting for caches to be synced
- 그 다음에 Kubernetes Service 리소스를 읽어들여서 클러스터와 같은 envoy 구성으로 변환한다.
2025-02-18T14:54:46.130502Z info ads XDS: Incremental Pushing ConnectedEndpoints:0 Version:2025-02-18T14:54:44Z/1
2025-02-18T14:54:46.202290Z info delta ADS: new delta connection for node:ingressgateway-66765874f6-jjdlg.istio-system-1
2025-02-18T14:54:46.210432Z info delta CDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:33 removed:0 size:37.4kB cached:0/32 filtered:0
2025-02-18T14:54:46.211947Z info delta EDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:32 removed:0 size:6.8kB empty:0 cached:0/32 filtered:0
2025-02-18T14:54:46.212811Z info delta LDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:0 removed:0 size:0B
2025-02-18T14:54:46.220763Z info delta SDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:1 removed:0 size:2.9kB cached:0/1 filtered:0
2025-02-18T14:54:46.221558Z warn buildGatewayRoutes: no gateways for router ingressgateway-66765874f6-jjdlg.istio-system
2025-02-18T14:54:46.222146Z warn buildGatewayRoutes: no gateways for router ingressgateway-66765874f6-jjdlg.istio-system
2025-02-18T14:54:46.222264Z info delta RDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:2 removed:0 size:53B cached:0/0 filtered:0
- 그 다음에는 envoy 구성을 타깃 envoy proxy로 보내는 작업이 이루어진다. 여기서는 xDS API를 사용한다. (server-side PUSH)
ingressgateway (envoy-proxy)
일단 아무 istio 커스텀 리소스가 반영되어있지 않다면 어떠한 라우팅룰과 관련된 설정이 없을 것이다. 초기 상태에서 ingressgateway 파드의 envoy proxy 구성을 살펴보자.
다음 명령어를 통해 파드 내 envoy proxy의 구성을 확인할 수 있다.
$ istioctl proxy-config all ingressgateway-557bff5b5f-cg2lc -o yaml > initial.yaml
proxy-config
명령어에서는 특정 구성만을 확인하는 것도 가능하고,all
로 선택한 경우 모든 구성을 확인해볼 수 있다. 구성의 종류로는bootstrap
,cluster
,ecds
,endpoint
,listener
,route
,secret
등이 있다.-o yaml
옵션을 사용하면 구성을 yaml 형태로 받을 수 있다.

파일을 보면 크게 7가지 부분으로 나뉜다. 여기서 BootstrapConfig를 제외하고 하나씩 살펴보자.
ClusterConfig
ClusterConfig를 보면 여러개의 cluster
배열이 선언되어 있는데, 최상단의 BlackHoleCluster
를 제외하고는 모두 쿠버네티스 내에 있는 서비스가 등록 되어있는 것을 확인할 수 있다. 즉 istiod는 쿠버네티스의 서비스 변경사항을 감지한 후 변경사항이 발생하면 관련된 envoy 구성으로 만든 다음 EDS
를 통해 메쉬 내 envoy-proxy
로 동적 구성을 적용시킨다.
metadata.filter_metadata.istio.services
부분에서host
,name
,namespace
는 각각 서비스 FQDN, 서비스 이름, 서비스 네임스페이스로 매핑된다.name
의 부분이 클러스터의 이름인데 클러스터 이름은outbound|${PORT}|${Service_FQDN}
으로 결정된다.type
부분을 보면EDS
라고 되어있는데 EDS에 의해 추가된 것으로 볼 수 있다.

EndpointsConfig
EndpointsConfig는 각 ClusterConfig에 등록된 Cluster의 엔드포인트가 선언되어 있다. 하나의 endpoint_config
안에는 클러스터(서비스)에서 디스커버리되는 엔드포인트 ip/port 주소들이 들어있다.

ListenerConfig
ListenerConfig에는 리스너의 정보가 들어있는데, 여기서는 envoy-proxy
에 오픈되어있는 포트별로 리스너 구성정보가 담겨있다.
- 첫 번째로 볼 것은
address
항목인데 여기서는 IP주소와 포트번호에 대한 정보가 들어있다. - 두 번째로 볼 것은
filter_chains
항목인데 여기서 처음 등장하는 체인은 NetworkFilterChain의HTTP connection filter
이다. 이전의 envoy 필터 구조 그림을 보면 NetworkFilterChain의 맨 끝에HTTP connection filter
가 있는 것을 확인할 수 있다. HTTP connection filter
부분을 보면http_filters
라는 항목이 있는데 이 부분부터는HTTPFilterChain
이며, 여기서도 마찬가지로 Router filter를 사용하고 있다.router_config
부분을 보면 알 수 있듯이 기본적으로 ingressgateway의 15090 포트는 메트릭 수집용 포트이고, 15021 포트는 헬스체크용으로 사용하고 있다. 초기에는 이 외의 listener는 없다.Gateway
,VirtualService
등의 리소스가 추가되면 생성이 될 것이다.

RoutesConfig
RoutesConfig에서는 라우팅룰에 대한 정보를 담고있는 것 같다. 아직은 ListenerConfig와 별 다른 것은 없어보인다.

SecretConfig
SecretConfig는 envoy proxy에서 사용할 인증서에 대한 정보를 담고있다.

리소스 추가
아무 istio 커스텀 리소스가 없을 때 최초로 ingressgateway를 대상으로 Gateway
와 VirtualService
를 추가하면 구성이 어떻게 달라질까? 한번 다음과 같이 Gateway
, VirtualService
를 생성한 후 ingressgateway의 proxy-config를 다시 분석해보자.
먼저 다음과 같이 Gateway
만 추가해보자. 그 후 어떤 설정이 변경되었는지 살펴보자.
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: beer1-com
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*.beer1.com"
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- bookinfo.beer1.com
tls:
mode: SIMPLE
credentialName: bookinfo # 인증서 시크릿은 별도로 준비해야 한다.
ListenerConfig
Gateway
설정에서는 80, 443 포트에 대한 규칙이 생겼기 때문에 ListenerConfig에는 80, 443 포트에 관련된 구성이 추가되었다.

RouteConfig
RouteConfig에는 다음과 같이 80, 443 포트에 대한 route_config
가 추가되었는데 여기서는 둘다 blackhole
으로 되어있다. 이렇게 되어있으면 무조건 503에러를 리턴하는 것 같다.

SecretConfig
Gateway에서 TLS 인증서 설정을 했기 때문에 ingressgateway에서는 TLS 처리를 위해 인증서 설정이 필요하다. 그래서 Gateway가 추가되면 해당하는 gateway의 파드의 SecretConfig에 인증서 정보가 추가된다.

이 이후에 다음과 같이 VirtualService
도 추가하면 어떻게 되는지 확인해보자.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo-ingress
namespace: istio-system
spec:
hosts:
- bookinfo.beer1.com
gateways:
- beer1-com
http:
- route:
- destination:
host: productpage.bookinfo.svc.cluster.local
port:
number: 9080
RouteConfig
예상했겠지만 VirtualService
는 L7 라우팅룰을 선언하는 부분이기 때문에 VirtualService
를 변경하면 RouteConfig가 변경된다.
- 여기서는
bookinfo.beer1.com
호스트로 80포트에 요청이 오는 경우/
경로 하위로 올 때productpage.booinfo.svc.cluster.local:9080
으로 포워딩 시켜준다.

마무리
이번 시간에는 Envoy proxy의 구조와 xDS에 대해 간단히 알아보았고 istiod가 istio 커스텀 리소스를 감지하여 어떤 방식으로 istio dataplane (gateway, sidecar)의 구성을 변경하는지 알아보았다. 그리고 실제로 어떻게 구성이 바뀌는지도 istioctl을 통해 두 눈으로 확인해 보았다.
istio에서 EnvoyProxy를 다루려면 envoy의 구조와 구성파일의 구조에 대해 대략적으로 알아야 제대로 사용할 수 있기 때문에 이렇게 자세하게 구성을 뜯어보는것도 어느정도 istio를 다루는 데 도움이 될 것이라고 생각한다.
'DevOps > Istio' 카테고리의 다른 글
istio 버전 업그레이드 (0) | 2025.03.03 |
---|---|
istio EnvoyFilter에 대해 알아보자. (0) | 2025.03.03 |
istio traffic 관리 (3) [Egress Gateway] (0) | 2025.01.18 |
istio traffic 관리 (2) [Gateway] (0) | 2025.01.13 |
istio traffic 관리 (1) [VirtualService & DestinationRule] (0) | 2025.01.12 |
댓글