쿠버네티스 Istio(envoy) 분석하기

온프레미스 K8s 클러스터 구축하기 - 6
이민석's avatar
Apr 16, 2025
쿠버네티스 Istio(envoy) 분석하기

직전에 쿠버네티스 Istio(envoy) 설치 및 실습하기 [1]를 했는데,
여전히 Istiod, Envoy 등의 작동 원리가 이해가 되지 않아 심화 문서를 작성합니다.

A. 분석하기

A.1. 사전 준비

Istio 설치하기 [A.1-1], Istio Sample 앱 배포하기 [A.1-2]를 진행해주세요.

A.2. istio-proxy 분석하기

istio-proxy의 설정파일은 크게 3가지로 구분됩니다.

  1. xDS (소켓 파일)

  2. envoy-rev.json Envoy (리비전 파일)

  3. grpc-bootstrap.json (gRPC 부트스트램 파일)

[명령어 1] Envoy 설정파일 리스트업

1. 파드 리스트업

kubectl get pods -n istio-sample -o=custom-columns="KIND:.kind,NS:.metadata.namespace,NAME:.metadata.name"
KIND NS NAME Pod istio-sample bookinfo-gateway-istio-854cd9bd69-v4q68 Pod istio-sample details-v1-79dfbd6fff-slm95 Pod istio-sample productpage-v1-dffc47f64-5v8l6 Pod istio-sample ratings-v1-65f797b499-hf42z Pod istio-sample reviews-v1-5c4d6d447c-w74pp Pod istio-sample reviews-v2-65cb66b45c-vjmpv Pod istio-sample reviews-v3-f68f94645-bp6v2

2. 파드 컨테이너 명확인하기

kubectl get pods -n istio-sample -o jsonpath="{range .items[*]}{.metadata.namespace}{'\t'}{.metadata.name}{'\t'}{range .spec.initContainers[*]}[init]{.name}{'\t'}{end}{range .spec.containers[*]}{.name}{'\t'}{end}{'\n'}{end}"
istio-sample bookinfo-gateway-istio-854cd9bd69-v4q68 istio-proxy istio-sample details-v1-79dfbd6fff-slm95 [init]istio-init details istio-proxy istio-sample productpage-v1-dffc47f64-5v8l6 [init]istio-init productpage istio-proxy istio-sample ratings-v1-65f797b499-hf42z [init]istio-init ratings istio-proxy istio-sample reviews-v1-5c4d6d447c-w74pp [init]istio-init reviews istio-proxy istio-sample reviews-v2-65cb66b45c-vjmpv [init]istio-init reviews istio-proxy istio-sample reviews-v3-f68f94645-bp6v2 [init]istio-init reviews istio-proxy

3. 파드 접속하기

kubectl exec productpage-v1-dffc47f64-5v8l6 -n istio-sample -it -c istio-proxy -- /bin/sh
$

4. 파드 주요 메타데이터 확인하기

whoami # istio-proxy pwd # / cd ~ pwd # /home/istio-proxy cd /

5. istio-proxy 설정확인하기

cd /etc/istio/proxy ls -l
total 20 srw-rw-rw- 1 istio-proxy istio-proxy 0 Apr 15 12:22 XDS -rw-r--r-- 1 istio-proxy istio-proxy 14236 Apr 15 12:22 envoy-rev.json -rw-r--r-- 1 istio-proxy istio-proxy 2929 Apr 15 12:22 grpc-bootstrap.json

grpc-bootstrap.json 파일에는 몇가지 중요한 설정이 있습니다.

  1. .node (노드 설정)

    1. id → sidecar~10.244.0.211~productpage-v1-dffc47f64-5v8l6.istio-sample~istio-sample.svc.cluster.local

    2. cluster → productpage.istio-sample

  2. xds_servers (xDS 설정)

    1. server_uri → “unix:///etc/istio/proxy/XDS”

    2. channel_creds → [{ type: insecure” }]

    3. server_features: [ “xds_v3” ]

  3. listeners (리스너 설정)

    1. name: “0.0.0.0_15090” → 15090 포트에서 트래픽을 수신

    2. filter_chanins: [… ] → /stats/prometheus 경로로 오는 요청을 promehteus_stats 클러스터로 라우팅

[명령어 2] Envoy 설정파일 조회하기

1. .node (노드 설정)

cat grpc-bootstrap.json | grep node -A 60
"node": { "id": "sidecar~10.244.0.211~productpage-v1-dffc47f64-5v8l6.istio-sample~istio-sample.svc.cluster.local", "metadata": { "ANNOTATIONS": { "istio.io/rev": "default", "kubectl.kubernetes.io/default-container": "productpage", "kubectl.kubernetes.io/default-logs-container": "productpage", "kubernetes.io/config.seen": "2025-04-15T21:22:43.081122129+09:00", "kubernetes.io/config.source": "api", "prometheus.io/path": "/stats/prometheus", "prometheus.io/port": "15020", "prometheus.io/scrape": "true", "sidecar.istio.io/status": "{\"initContainers\":[\"istio-init\"],\"containers\":[\"istio-proxy\"],\"volumes\":[\"workload-socket\",\"credential-socket\",\"workload-certs\",\"istio-envoy\",\"istio-data\",\"istio-podinfo\",\"istio-token\",\"istiod-ca-cert\"],\"imagePullSecrets\":null,\"revision\":\"default\"}" }, "APP_CONTAINERS": "productpage", "CLUSTER_ID": "Kubernetes", "ENVOY_PROMETHEUS_PORT": 15090, "ENVOY_SKIP_DEPRECATED_LOGS": "true", "ENVOY_STATUS_PORT": 15021, "GENERATOR": "grpc", "INSTANCE_IPS": "10.244.0.211", "INTERCEPTION_MODE": "REDIRECT", "ISTIO_PROXY_SHA": "d1333136f077ed86411257320fe37d4b5f8b8ddd", "ISTIO_VERSION": "1.25.1", "LABELS": { "app": "productpage", "security.istio.io/tlsMode": "istio", "service.istio.io/canonical-name": "productpage", "service.istio.io/canonical-revision": "v1", "version": "v1" }, "MESH_ID": "cluster.local", "METADATA_DISCOVERY": "false", "NAME": "productpage-v1-dffc47f64-5v8l6", "NAMESPACE": "istio-sample", "NODE_NAME": "cp-k8s", "OWNER": "kubernetes://apis/apps/v1/namespaces/istio-sample/deployments/productpage-v1", "PILOT_SAN": [ "istiod.istio-system.svc" ], "POD_PORTS": "[{\"containerPort\":9080,\"protocol\":\"TCP\"}]", "PROXY_CONFIG": { "binaryPath": "/usr/local/bin/envoy", "concurrency": 2, "configPath": "./etc/istio/proxy", "controlPlaneAuthPolicy": "MUTUAL_TLS", "discoveryAddress": "istiod.istio-system.svc:15012", "drainDuration": "45s", "proxyAdminPort": 15000, "serviceCluster": "istio-proxy", "statNameLength": 189, "statusPort": 15020, "terminationDrainDuration": "5s" }, "SERVICE_ACCOUNT": "bookinfo-productpage", "WORKLOAD_IDENTITY_SOCKET_FILE": "socket", "WORKLOAD_NAME": "productpage-v1" }, "locality": {}, "UserAgentVersionType": null },

2. xds_servers (XDS 설정)

cat grpc-bootstrap.json | grep xds_servers -A 12
"xds_servers": [ { "server_uri": "unix:///etc/istio/proxy/XDS", "channel_creds": [ { "type": "insecure" } ], "server_features": [ "xds_v3" ] } ],

3. listeners (리스너 설정)

cat envoy-rev.json | grep listeners -A 100

즉,
초기 설정(grpc-bootstrap.json), 이후 설정(envoy-rev.json)에는
노드, xDS, 리스너 등의 다양한 설정들이 주입되어 있음을 알 수 있었습니다.

자연스럽게 “주입되는 경로가 어디인가?”라는 의문과 연결되고
그 경로가 되는 친구가 xDS(LDS, CDS, RDS, EDS)입니다.

A.3. Istiod가 동적 구성을 하는 방식 (Delta xDS API)

xDS*는 서비스 검색 및 동적구성을 하는데 사용되는 프로토콜인데,
LDS, RDS, CDS, EDS 등의 다양한 Discovery Service들을 묶어놓은 API입니다.

💡

xDS(Extensible Discovery Service)의 세부 구성의 일부는 다음과 같습니다. 1. CDS : Cluster Discovery Service 2. LDS : Listener Discovery Service 3. EDS : Endpoint Discovery Service 4. SDS : Secret Discovery Service

확장된 xDS들도 몇가지가 있긴한데, 실제로 쓸 일이 있을까 싶습니다.

  1. SotW(State of the World) : ~ @1.22 이전 버전 기본값, 중앙에서 전체값 전송, 각 sidecar istio-proxy(envoy)에서 값 관리

  2. Delta xDS(Incremental xDS) : @1.22 이후 버전 기본값, 중앙에서 변경값 전송, 각 sidecar istio-proxy(envoy)에서 값 관리

  3. ADS(Aggregated Discovery Service) : 중앙의 gRPC 스트림에서 전체값 저장

  4. Delta ADS(Incremetnal ADS) : 중앙의 gRPC 스트림에서 변경값 저장

(다른 방식도 같은 구조인지는 확인해봐야 하지만…)
기본값인 Delta xDS의 경우 istiod 내부에 있는 xDS API을 의미합니다.

Istio와 Envoy의 구성 변경 전파 방식
[그림 1] Istio와 Envoy의 구성 변경 전파 방식

Istiod와 istio-proxy(envoy)는 크게 두 가지 통신을 하게 됩니다.

  1. 초기 설정 전송

  2. 변경 사항 구독 및 반영

Istio와 Envoy의 구성 변경 흐름
[그림 2] Istio와 Envoy의 구성 변경 흐름

A.4. Istio Sidecar Injection 작동 원리

Istio 설치 및 실습 [A.4-1]에서 istio-sample을 위해 라벨을 붙였습니다.

kubectl label namespace istio-sample istio-injection=enabled

이후 istio-sample에서 생성된 파드는 init-istio, istio-proxy가 생겼습니다.

  1. init-istio : istio, istio-proxy 초기화 설정

  2. istio-proxy : istio-proxy 설정 및 envoy 실행

application, init-istio, istio-proxy 구조도
[그림 3] application, init-istio, istio-proxy 구조도

Istio는 어떻게 Sidecard Injection 기능을 구현했을까요?
Istio는 Kubernetes AdmissionController을 활용하여 이를 구현했으며
구체적으로는 MutatingAdmissionWebhook이라는 기능을 사용합니다.

[그림 4] validating admission controller -> mutating admission controller

[명령어 3]을 실행해보면,
istio-sidecar-injector라는 MutatingWebhookConfiguration을 통해
istiod.istio-system/inject 요청을 보내는 것을 알 수 있습니다.

[명령어 3] Istio Injector 작동과정

1. MutatingWebhookConfiguration 리스트 조회하기

kubectl get MutatingWebhookConfiguration
NAME WEBHOOKS AGE istio-revision-tag-default 4 43h istio-sidecar-injector 4 43h

2. MutatingWebhookConfiguration istio-revision-tag-default* 확인하기

kubectl get MutatingWebhookConfiguration istio-revision-tag-default

3. MutatingWebhookConfiguration istio-sidecar-injector* 확인하기

kubectl get MutatingWebhookConfiguration istio-sidecar-injector

4. MutatingWebhookConfiguration istio-sidecar-injector* 조회하기

kubectl get MutatingWebhookConfiguration istio-sidecar-injector -o yaml | yq e '.webhooks[] | {"name": .name, "rules": .rules}' -
name: rev.namespace.sidecar-injector.istio.io rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: '*' name: rev.object.sidecar-injector.istio.io rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: '*' name: namespace.sidecar-injector.istio.io rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: '*' name: object.sidecar-injector.istio.io rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: '*'

istio @1.25.1에서는 총 4종류의 Webhook을 가지고 있는데,
모두 파드가 생길때 실행되며, istiod.istio-system/inject로 요청을 보내게 됩니다.

Webhook Rules

label target

label

rev.namespace.sidecar-injector.istio.io

namespace

istio.io/rev

rev.object.sidecar-injector.istio.io

pod

istio.io/rev

namespace.sidecar-injector.istio.io

namespace

istio-injection=enabled

object.sidecar-injector.istio.io

pod

istio-injection=enabled

지금은 namespace.sidecar-injector.istio.io를 사용하고 있어서
해당 namespace에 있는 모든 파드들에게 init-istio, istio-proxy가 주입됩니다.

A.5. Istio Envoy 작동 원리

[명령어 4]의 1-2을 통해서 Istio Gateway만 배포되어 있음을 알 수 있었습니다.

[명령어 4] Istio CRD 조회하기

1. Istio CRD 리스트 조회하기

kubectl api-resources -o="name" | grep istio
wasmplugins.extensions.istio.io destinationrules.networking.istio.io envoyfilters.networking.istio.io gateways.networking.istio.io proxyconfigs.networking.istio.io serviceentries.networking.istio.io sidecars.networking.istio.io virtualservices.networking.istio.io workloadentries.networking.istio.io workloadgroups.networking.istio.io authorizationpolicies.security.istio.io peerauthentications.security.istio.io requestauthentications.security.istio.io telemetries.telemetry.istio.io

2. Istio CRD 배포 내역 조회하기

kubectl get wasmplugins,destinationrules,envoyfilters,gateways,proxyconfigs,serviceentries,sidecars,virtualservices,workloadentries,workloadgroups,authorizationpolicies,peerauthentications,requestauthentications,telemetries -A -o=custom-columns="KIND:.kind,NS:.metadata.namespace,NAME:.metadata.name"
KIND NS NAME Gateway istio-sample bookinfo-gateway

[명령어 5]를 통해서 Istio Listener, Proxy Config을 봤지만,
여러 공식문서에서 말하고 있는 Istio Network 흐름과는 상이했습니다.
아마도 Istio Control Plane이 istiod로 변경되면서 많은 부분이 달라진 것 같습니다.

[명령어 5] Istio Listener, Proxy 확인하기

1. pod 조회하기

kubectl get pods -n istio-sample -o=custom-columns=KIND:.kind,NS:.metadata.namespace,NAME:.metadata.name
KIND NS NAME Pod istio-sample bookinfo-gateway-istio-854cd9bd69-v4q68 Pod istio-sample details-v1-79dfbd6fff-slm95 Pod istio-sample productpage-v1-dffc47f64-5v8l6 Pod istio-sample ratings-v1-65f797b499-hf42z Pod istio-sample reviews-v1-5c4d6d447c-w74pp Pod istio-sample reviews-v2-65cb66b45c-vjmpv Pod istio-sample reviews-v3-f68f94645-bp6v2

2. istio pc listener 조회하기

istioctl pc listener productpage-v1-dffc47f64-5v8l6 -n istio-sample

3. istio pc listener 세부사항 조회하기

istioctl pc listener productpage-v1-dffc47f64-5v8l6 -n istio-sample --address 0.0.0.0 --port 15001 -o yaml

4. istio proxy-config routes 조회하기

istioctl proxy-config routes productpage-v1-dffc47f64-5v8l6 -n istio-sample

CNCF Ambassador의 게시글에서는
Remote Pod → Local Pod으로 가는 트래픽을 아래와 같이 표현하고 있습니다.

  • REDROUTING, ISTIO_INBOUND, ISTIO_IN_REDIRECT, Envoy(inbound), OUTPUT → ISTIOU_OUTPUT(RULE 1) → POSTROUTING → Local Pod

[그림 5] Remote Pod -> Local Pod (구버전으로 추측)

Istio 설치 및 실습 [A.4-1]에서 살펴본 바,
네트워크 제어(iptables) 방식은 크게 다르지 않으며
일부 비율 분산*, 도메인 네임 등록* 등의 부분 정도의 차이만 보였습니다.

  1. 비율 분산?

    1. Service + kube-proxy(iptables)는 파드에 균등하게 분산함

    2. Sidecar istio-proxy(envoy) + Service + kube-proxy(iptables)는 여러 deploy에 대해서 비율로 분산할 수 있음

  2. 도메인 네임 등록

    1. Pod가 도메인을 파악하려면 CoreDNS + Kube-Proxy에 질의해야함

    2. Pod가 갈 수 있는 도메인이 Envoy Listener에 등록되어 있음

참고 자료

Share article

Unchaptered