Introduction
Istio의 dynamic configuration의 핵심인 xDS에 관한 요약으로, Istio in Action을 주로 참고한 글이다. 참고로 dynamic configuration는 Istio Envoy proxy에 동적으로 설정되는 데이터로, 여기에는 Istio Envoy proxy가 노출할 port 부터 routing 규칙 및 upstream 서비스까지 모두 포함된다.
Motivation
Istio의 Namespace isolation을 사용하지 않으면, pod가 많아질 수록 Istio sidecar가 사용하는 메모리 크기가 커진다. 이로 인해 OOMKilled나 connection drop 등 다양한 오류가 발생하는데, 알고보니 주된 범인은 xDS 데이터였다. xDS는 Istio/Envoy dynamic configuration의 핵심이다.
xDS란
xDS는 eXtensible Discovery Services의 약자로 dynamic configuration 관리 서버, 즉 istiod 가 노출하는 API 및 이들 서비스를 가리킨다. Envoy는 istiod 를 ‘구독’하여 최종적 일관성(eventual consistency)에 기반하여 configuration을 상시 동기화한다(출처). 참고로 이 동기화에는 Istio의 경우 gRPC를 사용하는데, Envoy는 이외에도 HTTP long polling과 특정 filesystem watch 기법도 제공한다고.
xDS의 x에는 대표적으로 Listener(LDS), Route(RDS), Cluster(CDS), Endpoint(EDS)가 있는데, 이들 각각은 순서대로, Envoy가 노출할 port, 인입된 트래픽을 어떤 upstream 서비스로 보낼지 지정하는 규칙, upstream 서비스, 마지막으로 upstream 서비스의 주소를 가리킨다.
또한 위 그림에는 없지만 Istio가 사용하는 xDS에는 Secret(SDS), Aggregate(ADS), Name(NDS)도 있으며, 이 중 NDS는 Istio 전용으로 Envoy와 별도로 동작하는 Istio DNS Proxy를 위한 것이다.
아래는 Envoy xDS의 전체 목록이다.
xDS 상세
istioctl proxy-config command는 Istio proxy의 Envoy xDS API에 기반한 configuration 정보를 보여준다. 아래는 command 형식.
•
istioctl proxy-config <clusters|listeners|routes|endpoints|bootstrap|log|secret> <pod-name[.namespace]> -o <short|yaml|json>
Listener discovery service (LDS)
Listener는 Istio Proxy가 downstream traffic을 위해 어떤 IP, port 등을 열어야 하는지, listener로 들어온 traffic을 어느 Route로 보내야하는지 등을 정의한다. 또한, listener/network filter chain로 연결되어 각종 전처리를 담당하기도 한다. EnvoyFilter 를 통해 custom filter를 이 chain에 넣을 수도.
아래는 앞서 설명한 command의 listener flag 기반 응답의 예로, 예컨데 첫 line은 80 port로 들어온 traffic은 이름이 http.80인 Route로 전달한다는 뜻이다(network filter chain을 보려면 -o yaml 또는 -o json 을 사용해야 한다). 응답에는 upstream의 IP(e.g. cluster IP)를 포함한다(-o yaml 사용).
# -o short flag 사용
ADDRESSES PORT MATCH DESTINATION
0.0.0.0 80 ALL Route: http.80
0.0.0.0 443 SNI: *.anyflow.net Route: https.443.default.default-gateway-istio-autogenerated-k8s-gateway-https-anyflow-net.cluster
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
Bash
복사
Route discovery service (RDS)
Route는 Listener를 통해 들어온 traffic을 어떤 Cluster로 보내야할지를 지정하며, Kubernetes Gateway API의 HttpRoute 나 Istio의 VirtualService 로 지정한 routing rule이 반영된다. 참고로 여기서 Cluster는 Deployment, Daemonset 등의 동일 pod로 구성된 집합을 의미한다.
아래는 앞서 설명한 command의 route 및 -o yaml flag 응답의 예로, 앞선 Listener의 예에서 확인한 http.80 Route의 상세이다.
해당 HttpRoute 설정은 path가 /dockebi 로 시작하고, X-Color header value가 blue 일 경우 dockebi-tick service로 보내는 내용인데, 이에 대한 내용이 그대로 담겨 있다. 또한 해당 조건에서 이름이 outbound|8080||dockebi-tick.cluster.svc.cluster.local 인 Cluster로 traffic을 보내도록 설정되어 있다.
# -o yaml flag 사용
- ignorePortInHostMatching: true
maxDirectResponseBodySizeBytes: 1048576
name: http.80
validateClusters: false
virtualHosts:
- domains:
- api.anyflow.net
includeRequestAttemptCount: true
name: api.anyflow.net:80
routes:
- decorator:
operation: dockebi-tick.cluster.svc.cluster.local:8080/*
match:
caseSensitive: true
headers:
- name: X-Color
stringMatch:
exact: blue
pathSeparatedPrefix: /dockebi
metadata:
...
name: cluster.dockebi.0
route:
cluster: outbound|8080||dockebi-tick.cluster.svc.cluster.local
...
...
YAML
복사
Cluster discovery service (CDS)
Cluster는 사실 상 Kubernetes Service 을 의미하여, 각 pod의 endpoint를 지칭하는 Endpoint를 포함한다. 아래는 cluster flag 기반 응답의 예로, 앞선 Route에서 논한 outbound|8080||dockebi-tick.cluster.svc.cluster.local Cluster가 보인다. 참고로 SUBSET과 DESTINATION RULE이 비어있는데, 이는 dockebi-tick 에 대한 DestinationRule Istio resource를 지정하지 않아서 그런 듯.
# -o short flag 사용
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
dockebi-tick.cluster.svc.cluster.local 8080 - outbound EDS ...
Bash
복사
Endpoint discovery service (EDS)
Cluster에 속하는 endpoint 정보로, pod 수준에서의 IP, port 정보를 포함한다. 아래는 앞서 설명한 command의 endpoint flag 기반 응답의 예로, outbound|8080||dockebi-tick.cluster.svc.cluster.local Cluster의 사항만 남겼다.
# -o short flag 사용
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.244.1.220:8080 HEALTHY OK outbound|8080||dockebi-tick.cluster.svc.cluster.local
...
Bash
복사
Secret discovery service (SDS)
인증서 배포에 사용. 아래는 앞서 설명한 command의 secret flag 기반 응답의 예이다.
# -o short flag 사용
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 4369fd4091de50ac891dc6f6514f271 2024-05-04T19:45:02Z 2024-05-03T19:43:02Z
ROOTCA CA ACTIVE true 4bc95c93a6ee95043734d2fa5f677fa5 2034-03-15T05:19:41Z 2024-03-17T05:19:41Z
Bash
복사
-o yaml flag 사용 시
Aggregate discovery service (ADS)
xDS configuration에 대한 변경분을 나타내는 serialized stream으로, ADS를 쓰면 타 xDS configuration의 변경을 일일이 추적할 필요 없다고.
Name discovery service (NDS)
Kubernetes service 및 Istio ServiceEntry resource에 변경이 있을 때마다 DN(Domain Name), IP(e.g. cluster IP) 등을 동기화한다. 앞선 API와는 달리 istiod 의 debug endpoint를 사용하여 command를 보낸다. 다음은 command 형식과 응답 예이다.
•
k exec -n istio-system {istiod pod name} -- curl "localhost:8080/debug/ndsz?proxyID={pod name}.{namespace}"
{
"resource": {
"@type": "type.googleapis.com/istio.networking.nds.v1.NameTable",
"table": {
"dockebi-tick.cluster.svc.cluster.local": {
"ips": [
"10.106.182.113"
],
"registry": "Kubernetes",
"shortname": "dockebi-tick",
"namespace": "cluster"
},
...
}
}
}
JSON
복사
Appendix: Istio sidecar의 memory 과다 사용 이슈에 관하여
Motivation 에서 논했듯, pod가 많아질 수록 Istio sidecar가 사용하는 메모리 크기가 커진다. 이로 인해 OOMKilled나 connection drop 등 다양한 오류가 발생하는 경우가 있다. 내가 경험한 상황과 유사한 보고가 상당수 보였는데 아래는 그 예이다.
Istio 공식 성능 테스트 결과(Istio version 1.21.2)인 1000RPS 부하에서의 0.5 core / 50M에는 상당히 반하는 결과다.
이는 Namepace isolation 적용 유무에 따른 것으로, Namepace isolation를 적용하면 각 pod는 Sidecar 에 지정된 namespace의 Cluster 및 Endpoint configuration만 memory에 유지하므로, Kubernetes cluster 전체에 대한 configuration을 갖는 이전과는 큰 차이를 보이게 되며, 타 namespace의 확장과도 무관해진다.
아래는 namespace isolation을 위한 Sidecar resource definition의 한 예이다. 이는 pod 자신의 namespace 및 istio-system namespace의 pod로만 outbound traffic을 보낸다는 의미로, 이외의 namespace에 대한 Istio Cluster, Endpoint configuration은 memory에 보유하지 않는다.
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: default
namespace: cluster # cluster namespace내 pod에 적용
spec:
egress:
- hosts:
- "./*" # 자신의 namespace내 모든 pod로 outbound traffic을 보낼 수 있음을 의미
- "istio-system/*" # istio-system namespace내 모든 pod로 outbound traffic을 보낼 수 있음을 의미
YAML
복사
이외에 ServiceEntry 및 Virtualservice 의 exportTo field를 통해서도 위와 동일 효과가 가능하다고.
여담으로, memory consumption 이슈는 상당히 큰 문제이기에 namespace isolation은 사실 상 필수 설정인데, Istio 공식 문서는 이에 대한 언급이 매우 부족해 보인다. 내 경우 한참이나 고생하다가 힌트를 Istio 공식 성능 테스트 결과(Istio version 1.21.2)에서 우연찮이 얻었다. 이 문서 조차 적용 사유 등에 대해서는 언급 없이 단순히 테스트 조건으로서의 namespace isolation 명칭과 Sidecar 로의 링크만 제공한다.