homelab89 Docs Logs Legacy Files ☰ TOC 🌓
noteistio 2026-06-07istioenvoyxdsfilesystem-xdseds

파일 기반 xDS는 DiscoveryResponse 포맷·move 교체만 감지하고 EDS의 "클러스터당 CLA 1개" 제약 때문에 디버깅이 까다롭다

ABSTRACT

머릿속에 둘 한 장면: 파일 기반 xDS는 gRPC ADS의 구독 계약을 그대로 둔 채 전송(transport)만 “로컬 파일"로 바꾼 것이다. 그래서 세 가지 좁은 제약은 따로 생긴 규칙이 아니라 모두 그 계약에서 흘러나온다 — ① 파일은 인라인 조각이 아니라 루트에 resources: 배열을 둔 DiscoveryResponse 응답이어야 하고, ② 파일 watcher가 신뢰하는 변경 신호는 move(rename) 이벤트 하나뿐이며, ③ EDS만은 “응답 1개 = 클러스터 1개"라 클러스터당 ClusterLoadAssignment 1개만 허용된다. 결론: LDS/RDS 학습용으로는 훌륭하지만 파일 EDS는 함정이고, xDS를 진짜로 보려면 gRPC ADS(Istio면 istioctl proxy-config)로 우회하는 편이 빠르다. 깊은 실습 절차는 정적/동적 xDS 실습에 위임하고, 여기서는 왜 그런 제약이 생기고 어떻게 판단할지의 멘탈모델만 다룬다.


1. 배경 — 왜 파일 기반 xDS를 손으로 만져보는가

xDS는 한 문장으로 “설정을 누가, 어떤 전송으로 Envoy에 주입하는가“의 문제다. Envoy는 Listener(LDS)·Route(RDS)·Cluster(CDS)·Endpoint(EDS)를 부팅 시 한 번 읽고 끝내는 게 아니라, 런타임에 구독해서 받아온다. 이 구독을 누가 채워주느냐가 전송(transport)이고, 같은 LDS/RDS/CDS/EDS 리소스라도 전송은 세 가지로 나뉜다:

전송 방식 config_source 푸시 주체 용도
static (없음, 부트스트랩 인라인) 없음(고정) 최소 부팅·테스트
filesystem(파일) path: / path_config_source: 로컬 파일 watcher 단독 실습·엣지 케이스
gRPC ADS api_config_source: {api_type: GRPC} 컨트롤 플레인(istiod) 프로덕션(Istio)

프로덕션에서 Istio는 gRPC ADS 한 채널로 모든 리소스를 단일 스트림에 실어 보낸다. 그런데 그 ADS 스트림 안을 직접 들여다보긴 어렵다 — istiod가 KRM(VirtualService·DestinationRule 등)을 번역해 푸시하는 결과만 보일 뿐, “Envoy가 한 개의 RouteConfiguration을 받으면 무슨 일이 벌어지는가"를 손으로 한 줄씩 바꿔보긴 힘들다. 파일 기반 xDS는 그 ADS 스트림을 로컬 파일로 “외재화(externalize)“한 것이다. 컨트롤 플레인 없이 lds.yaml·rds.yaml을 직접 쓰고, 파일 한 줄 바꾸면 Envoy가 재시작 없이 반영한다. 그래서 “동적 라우팅이 실제로 어떻게 갱신되는가"를 컨트롤 플레인의 추상화를 걷어내고 맨손으로 체득하는 최고의 실습 도구다.

선행 개념: 정적/동적의 경계와 어떤 계층을 동적화할지는 정적 vs 동적 설정, 계층 분할(LDS→RDS, CDS→EDS의 의존 사슬)의 전체 그림은 xDS API 계층에 있다. 이 글은 그 위에서 “파일로 바꾸면 어떤 함정이 새로 생기나” 만 다룬다.


2. 핵심 멘탈모델 — “transport만 바꾼 것"에서 세 제약이 따라 나온다

붙잡을 단 하나의 그림:

파일 기반 xDS는 gRPC ADS와 동일한 구독 계약을 쓰되, 메시지를 운반하는 채널만 gRPC 스트림 → 로컬 파일로 바꾼다. Envoy 입장에선 “응답(DiscoveryResponse)을 어디서 받느냐"만 다르고, 받은 응답을 어떻게 검증·적용하느냐는 똑같다.

이 한 줄을 쥐면 뒤의 세 제약이 전부 연역된다. 각 제약은 새로 만든 규칙이 아니라, 동일한 구독 계약의 어느 부분이 파일이라는 전송에서 드러나는가의 차이일 뿐이다:

flowchart TD
  contract["동일한 xDS 구독 계약<br/>(gRPC ADS와 공유)"]
  contract -->|"응답은 DiscoveryResponse 타입이다"| c1["제약 ① 포맷<br/>루트 resources[] + @type"]
  contract -->|"새 응답 = 새 파일 도착 이벤트"| c2["제약 ② 갱신 신호<br/>move(rename)만 안정"]
  contract -->|"EDS 응답 단위 = 클러스터 1개"| c3["제약 ③ EDS<br/>클러스터당 CLA 1개"]
  c1 -.같은 인터페이스, 구현은 분리.-> mux["Subscription 인터페이스(추상)<br/>구현·거부 로그는 전송별로 분리 — 파일은 FilesystemSubscriptionImpl"]
  c3 -.length 검사(파일 전용 구현·로그).-> mux

세 제약을 하나씩 계약에서 끌어내며 보면:

2-1. 제약 ① — 파일은 DiscoveryResponse여야 한다 (포맷)

ADS 스트림에서 오는 메시지는 DiscoveryResponse다. 전송만 바꿨으니 파일의 모양도 정확히 DiscoveryResponse여야 한다. 즉 루트에 resources: 배열이 있고, 각 원소는 "@type"으로 구체 리소스 타입을 명시한다:

# rds.yaml — 루트 resources[] + @type 이 계약
version_info: "0"                  # 선택, 디버깅·관찰용
resources:
  - "@type": type.googleapis.com/envoy.config.route.v3.RouteConfiguration
    name: local_route
    virtual_hosts: [ ... ]

여기서 오는 혼동:

  • 부분 설정 YAML이 아니다. “Listener 한 조각"을 그냥 쓰면 안 되고, Listenerresources[]로 감싼 응답 형태여야 한다. static 부트스트랩에서 쓰던 인라인 형식과 구조가 다르다는 점이 첫 번째 혼동 지점이다 — 같은 리소스라도 인라인은 필드 값, 파일 xDS는 응답 페이로드라는 위상 차이다.
  • 경로는 부트스트랩 시점에 이미 존재해야 한다. watcher는 초기 로드에서 파일을 읽으므로, 없으면 빈 구독 상태로 시작해 이후 생성에 반응이 어긋난다.
  • @type이 틀리면 조용히 무시되거나 reject된다. 타입 FQDN(envoy.config.route.v3.RouteConfiguration 등)은 v3 API 기준으로 정확히 적어야 한다.

2-2. 제약 ② — 갱신은 move(rename)로만 안정 감지된다 (이벤트)

ADS에선 “새 응답이 왔다"가 명시적 메시지다. 파일 전송엔 그런 메시지가 없으니, “파일이 바뀌었다"는 OS 파일시스템 이벤트로 대신한다 — inotify(Linux)/kqueue(macOS). 문제는 에디터/스크립트의 in-place 저장이 발생시키는 이벤트가 플랫폼마다 다르고 불안정하다는 것이다. Envoy가 안정적으로 신뢰하는 트리거는 rename(move) = MOVED_TO 한 가지다.

# 잘못: in-place 수정 — inotify가 일관되게 안 잡음(IN_MODIFY/CLOSE_WRITE 누락 가능)
vi xds/rds.yaml

# 옳음: 새 파일에 쓰고 atomic move 로 교체 — 항상 MOVED_TO 발생
cat > xds/rds.new <<'EOF'
... 새 DiscoveryResponse ...
EOF
mv xds/rds.new xds/rds.yaml        # rename = 원자적 교체, watcher 확실히 감지

왜 move인가: rename은 디렉터리 엔트리를 원자적으로 바꾸므로 “반쯤 쓰인 파일을 읽는” race가 없고, 단일 MOVED_TO 이벤트로 환원된다. in-place write는 truncate→write 사이의 중간 상태와 다중 이벤트(IN_MODIFY 여러 번, CLOSE_WRITE)를 만들어 watcher 구현이 빠뜨리기 쉽다. 그래서 ConfigMap을 마운트하는 Kubernetes도 내부적으로 symlink swap(=rename) 으로 갱신하며, 그 패턴을 안정 감지하라고 Envoy가 path_config_source.watched_directory를 추가했다. 즉 “rename으로만 갱신하라"는 임의의 규칙이 아니라 원자적 교체만이 일관된 단일 이벤트를 보장한다는 파일시스템 물리에서 나온다.

sequenceDiagram
  participant Op as Operator/script
  participant FS as filesystem
  participant W as Envoy file watcher
  participant E as Envoy config
  Op->>FS: write rds.new (full DiscoveryResponse)
  Op->>FS: mv rds.new rds.yaml (rename)
  FS-->>W: MOVED_TO 이벤트(원자적)
  W->>FS: re-read rds.yaml
  W->>E: route_config 갱신(재시작 없음)
  Note over W,E: in-place write 면 이 화살표가 누락될 수 있음

2-3. 제약 ③ — EDS는 클러스터당 CLA 1개 (구독 단위 비대칭, 핵심 함정)

세 제약 중 가장 비자명하고 가장 자주 터지는 것. 이건 파일 전송의 한계가 아니라 EDS 구독 단위의 본질이 파일에서 노출되는 것이다. EDS 리소스의 단위는 “클러스터 1개의 ClusterLoadAssignment(CLA) 1개"다. CDS/LDS/RDS는 한 파일(=한 DiscoveryResponse)에 여러 리소스를 넣어도 되지만 — CDS는 애초에 “클러스터 목록“을 받는 게 정상이니까 — EDS는 한 구독 응답이 정확히 그 클러스터의 CLA 하나여야 한다. “특정 클러스터에 대한 답"이라 1개여야 한다는 의미가, “리소스 목록"인 CDS와 충돌하는 게 함정의 본질이다.

# eds.yaml — 두 클러스터의 CLA를 한 파일에 욱여넣으면 거부
resources:
  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
    cluster_name: httpbin_a            # CLA #1
    endpoints: [ ... ]
  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
    cluster_name: httpbin_b            # CLA #2  ← 이게 문제

이 경우 Envoy 로그에 다음이 뜬다(2026-07-05 실측, Envoy 1.30 — 아래 참고):

[warning][config] filesystem_subscription_impl.cc:63] Filesystem config update rejected:
Unexpected EDS resource length: 2

여기서 두 가지를 동시에 이해해야 한다:

  • “로그 접두어가 실제로는 뭘까?” — (2026-07-05 실측 정정) 로그 머리는 gRPC config아니라 Filesystem config update rejected: ...이고, 소스 위치도 filesystem_subscription_impl.cc다. filesystem 구독은 gRPC/ADS mux 코드 경로를 타지 않고, 자기 자신만의 FilesystemSubscriptionImpl 경로에서 검증·거부 로그를 남긴다 — “구독 계약(Subscription 인터페이스)은 gRPC와 공유하지만, 그 구현체와 로그 문구는 전송별로 분리돼 있다"는 뜻이다. 홈랩 클러스터에서 두 클러스터의 CLA를 한 eds.yaml에 넣고 원자적 rename으로 교체해 재현한 결과, 전체 로그 어디에도 gRPC config 문자열은 한 번도 나타나지 않았다(grep 0건). “filesystem도 결국 공통 grpc-mux 경로를 타서 gRPC config가 찍힌다"는 서술은 이 실측으로 반증됐다.
  • “왜 length 2?” — 파일 EDS 구독은 클러스터별로 별도 응답을 기대하는데, 한 파일에 둘을 넣으면 “이 클러스터에 대한 CLA가 2개 왔다"로 해석돼 length 2로 reject된다.

회피책 — STRICT_DNS로 EDS 자체를 제거: 학습/실습이라면 CDS에서 클러스터 타입을 STRICT_DNS(또는 LOGICAL_DNS)로 두고 엔드포인트를 인라인 load_assignment로 적으면 EDS 구독이 필요 없어진다. Envoy가 DNS로 IP를 직접 해석하므로 파일 EDS의 length 함정을 통째로 건너뛴다.

# cds.yaml — STRICT_DNS 면 EDS 불필요(엔드포인트 인라인)
resources:
  - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
    name: httpbin_a
    type: STRICT_DNS                   # EDS 대신 DNS 해석
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: httpbin_a
      endpoints:
        - lb_endpoints:
            - endpoint: { address: { socket_address: { address: httpbin-a, port_value: 8080 } } }

부트스트랩 배선은 이 계약을 그대로 반영한다 — lds_config: { path: ... }, cds_config: { path: ... }로 가리키고, HCM 안에서 RDS를 rds.config_source.path로 건다. 즉 파일 하나마다 그게 채우는 구독이 1:1로 묶인다.

flowchart LR
  subgraph FS["filesystem xDS"]
    boot["bootstrap.yaml"]
    lds["lds.yaml<br/>(Listener)"]
    rds["rds.yaml<br/>(Route)"]
    cds["cds.yaml<br/>(Cluster)"]
    eds["eds.yaml<br/>(CLA) — 함정"]
  end
  boot -->|lds_config path| lds
  boot -->|cds_config path| cds
  lds -->|rds.config_source path| rds
  cds -->|eds_config path| eds
  watcher["file watcher<br/>(inotify/kqueue)"] -.move 이벤트.-> lds & rds & cds & eds

3. 예시 — move로 가중치 전환을 관찰하고, 거부를 재현한다

세 제약이 실제로 어떻게 드러나는지 한 사이클로 묶어 본다. 전체 동작 실습(가중치 스위치·Admin API 덤프 전 과정)은 중복하지 않고 정적/동적 xDS 실습 §3–4로 위임하고, 여기서는 핵심 동작과 기대 출력만 확인한다.

(a) move로 RDS 가중치 전환 — 제약 ②가 살아 있음을 확인. A→B 트래픽을 100% B로 옮기는 새 RouteConfiguration을 atomic move로 교체한 뒤, Admin API에서 갱신을 확인한다:

# 주의: admin 의 ?resource= 는 type-URL 필터지 'routes' 같은 약어가 아니다.
# 전체 config_dump 를 받아 jq 로 추출해야 한다(정본 lab과 일치).
curl -s http://127.0.0.1:15000/config_dump \
  | jq '.. | .weighted_clusters? // empty'
# 기대: httpbin_a weight 0, httpbin_b weight 100 으로 갱신

mv로 교체하면 위 출력이 재시작 없이 바뀌고, vi로 in-place 저장하면 (플랫폼에 따라) 바뀌지 않는다 — 그 차이가 곧 제약 ②의 증명이다.

(b) 거부를 일부러 재현 — 제약 ③의 시그니처. §2-3의 두-CLA eds.yaml을 그대로 넣어 보면 Envoy 로그에 Unexpected EDS resource length: 2가 뜬다. 이 줄을 보면 “한 파일에 CLA를 여러 개 넣었다"로 즉시 환원하고, 클러스터별 분리 또는 STRICT_DNS 회피로 간다.

(c) Istio 실환경에서 EDS를 제대로 보는 법(파일이 아니라 ADS 경로). 파일 EDS의 함정을 우회해 “진짜 EDS가 런타임에 갱신되는 것"을 보려면 ADS로 간다:

istioctl proxy-config clusters deploy/sleep -n default -o short
istioctl proxy-config endpoints deploy/sleep -n default \
  --cluster "outbound|8000||httpbin.default.svc.cluster.local" -o json
# kubectl scale deploy/httpbin --replicas=2 후 endpoints 가 증가하면 EDS 동적 반영 확인

cluster 이름은 direction|port|subset|fqdn 규칙(예: outbound|8000||httpbin.default.svc.cluster.local)을 따른다. 이 좌표로 어떤 클러스터의 EDS를 보는지 특정한다. 데이터플레인 동기화 상태(SYNCED/STALE)는 데이터플레인 동기화 상태에서, 진단 도구 사용은 Envoy admin API 진단에서 다룬다.


4. 정리 — 무엇으로 우회할지의 의사결정

멘탈모델 한 줄로 되돌아가면: 파일 xDS는 “transport만 파일로 바꾼 ADS” 이고, 그래서 LDS/RDS는 손으로 체득하기 훌륭하지만 EDS는 구독 단위 비대칭 때문에 함정이다. 그러니 보고 싶은 것에 따라 전송을 고른다:

목적 권장 경로 이유
LDS/RDS 동적성(라우팅 가중치·timeout·retry) “확인만” 파일 LDS/RDS + CDS는 STRICT_DNS EDS 함정 회피, move 한 번으로 관찰
엔드포인트가 런타임에 바뀌는 EDS 동작 자체 gRPC ADS (go-control-plane 미니 CP 1~2h) 파일 EDS length·이벤트 삽질보다 빠름
Istio 이해가 최종 목적 Istio on kind + istioctl proxy-config 진짜 ADS/gRPC xDS를 그대로 관찰
flowchart TD
  q{무엇을 보고 싶나?}
  q -->|"LDS/RDS 동적 라우팅"| a["파일 LDS/RDS<br/>CDS=STRICT_DNS"]
  q -->|"EDS 엔드포인트 변화"| b["gRPC ADS<br/>(go-control-plane)"]
  q -->|"Istio 동작 자체"| c["kind + istioctl<br/>proxy-config"]
  b -.파일 EDS 회피.-> a
  c -.프로덕션 경로.-> b

핵심 정리

  • 한 문장 앵커: 파일 기반 xDS = gRPC ADS와 같은 구독 계약, 전송만 로컬 파일. 세 제약은 이 한 문장의 연역이다.
  • 파일 xDS의 계약 3가지: (1) 루트 resources: + @type의 DiscoveryResponse 포맷, (2) move(rename) 이벤트만 안정 감지, (3) EDS는 클러스터당 CLA 1개.
  • Unexpected EDS resource length: N 은 한 파일에 CLA를 여러 개 넣었다는 신호 → 클러스터별로 분리하거나 STRICT_DNS로 EDS 자체를 제거. 로그 접두어는 gRPC config가 아니라 **Filesystem config update rejected**다(2026-07-05 Envoy 1.30 실측) — filesystem 구독은 gRPC/ADS mux와 별개인 자신만의 검증·로그 경로(FilesystemSubscriptionImpl)를 타기 때문이다.
  • 파일은 부트스트랩 시점에 존재해야 하고, 갱신은 mv(atomic rename) 로. in-place 저장은 watcher가 놓칠 수 있다. ConfigMap이 symlink swap을 쓰는 이유, watched_directory 옵션이 생긴 이유가 모두 여기에 있다.
  • 학습 경로: 동적 라우팅 확인은 파일 LDS/RDS(CDS=STRICT_DNS), 진짜 EDS/ADS는 gRPC(go-control-plane 또는 Istio istioctl proxy-config).

What you might be missing

  • path vs path_config_source는 다르다. 단순 path:는 레거시 단일 파일 watcher라 위 이벤트 함정에 그대로 노출된다. 최신 Envoy는 path_config_source: { path, watched_directory }를 제공해 디렉터리를 watch하고 symlink swap(ConfigMap·Secret 마운트 패턴)을 안정적으로 감지한다. 파일 EDS를 굳이 써야 하면 이 쪽을 쓴다.
  • macOS Docker Desktop의 파일 이벤트는 신뢰도가 더 낮다. 가상 파일시스템(gRPC-FUSE/virtiofs) 경유라 inotify 전파가 누락되곤 한다. 같은 manifest가 Linux에선 되고 Mac에선 “왜 안 바뀌지"가 되는 흔한 원인 — Envoy 버그가 아니라 호스트 FS 이벤트 전달 문제다(이 홈랩은 Linux 워커 노드로만 구성돼 직접 재현·검증은 못 했다).
  • Istio는 사이드카에 파일 xDS를 쓰지 않는다. istiod가 gRPC ADS 단일 스트림으로 LDS/RDS/CDS/EDS를 푸시한다. (2026-07-05 정정) 이 단일 스트림에 SDS는 포함되지 않는다 — SDS는 파드 안의 istio-agent가 로컬 유닉스 도메인 소켓으로 별도 서빙하는 채널이라, istiod와의 gRPC ADS 스트림과는 분리돼 있다. 파일 기반은 어디까지나 Envoy 단독 학습/특수 임베디드 용도다. 따라서 이 note의 함정들은 “Istio 운영 중 만날 버그"가 아니라 “xDS 멘탈모델을 손으로 체득할 때의 함정"으로 분리해 이해해야 한다.
  • version_info는 의미적 버전이 아니라 관찰용 라벨이다. 파일 갱신 자체(=move)가 reload를 트리거하고, version_info를 안 바꿔도 새 내용이 반영된다. config_dump에서 변경 추적을 쉽게 하려고 올려 두는 것일 뿐, “버전을 올려야 반영된다"는 오해를 하기 쉽다.
  • EDS length 거부는 “잘못된 설정"이 아니라 “구독 단위 오해” 다. CDS의 다중 리소스 습관을 EDS에 그대로 옮기면 터진다. EDS만 “응답 1개 = 클러스터 1개"라는 비대칭을 기억하면 대부분의 파일 EDS 삽질이 사라진다.

검증 기록 (2026-07-05 · Istio 1.30.0 / k8s 1.30.6)

검증 방법: Envoy/Istio 공식 문서(xds.md, config_source.proto, xds_protocol 등) 대조 + homelab k8s 클러스터(istio-verify 네임스페이스, 메시 밖 순수 Envoy 파드)에서의 실측을 병행했다. 15개 주장 중 12개는 문헌·실측으로 그대로 확인됐고, 1개(SDS가 istiod ADS 스트림에 같이 실린다는 서술)는 공식 아키텍처 문서와 배치돼 오류로 정정했으며, 1개(거부 로그의 gRPC config 접두어 서술)는 실측으로 반증돼 정정했다. macOS 파일 이벤트 신뢰도 주장은 이 홈랩(Linux 워커 전용)에서는 재현 대상이 없어 실측 불가로 남겼다.

주장 판정 근거
C1. 파일 기반 xDS는 gRPC ADS와 동일한 Subscription 인터페이스를 쓰고 전송만 로컬 파일로 바뀐 것이다 ✅ 문헌 확인 github.com/envoyproxy/envoy/…/xds.md
C2. 파일은 부분 리소스가 아니라 루트 resources: + @type의 완전한 DiscoveryResponse여야 한다 ✅ 문헌 확인 envoyproxy.io/…/configuration-dynamic-filesystem
C3. 파일 경로는 부트스트랩(config load) 시점에 이미 존재해야 한다 ✅ 문헌 확인 envoyproxy.io/…/config_source.proto
C4. 파일 watcher는 move(MOVED_TO)만 신뢰하고, in-place 저장(IN_MODIFY/CLOSE_WRITE)은 감지가 누락될 수 있다 ✅ 실측 확인 envoyproxy.io/…/configuration-dynamic-filesystem · T66 실측 — in-place(cat>)는 update_attempt 불변으로 고착, rename(mv)만 반영
C5. rename은 원자적 단일 이벤트를 만들고, K8s ConfigMap도 symlink swap을 쓰며 이를 위해 watched_directory가 생겼다 ✅ 문헌 확인 envoyproxy.io/…/config_source.proto
C6. EDS 구독 단위는 “클러스터 1개 = CLA 1개"라 한 응답에 CLA가 2개 이상이면 거부된다 ✅ 실측 확인 github.com/envoyproxy/envoy/issues/23581 · T23 실측 — 2-CLA eds.yaml 교체 시 Unexpected EDS resource length: 2로 즉시 거부, last-good 유지
C7. 거부 로그는 gRPC config for ... rejected: ... 접두어이며, filesystem 구독도 공통 grpc-mux 검증 경로를 타기 때문이다 🔬 실측 반증 — 본문 교정 github.com/envoyproxy/envoy/issues/23581 · T23 실측 — 실제 접두어는 Filesystem config update rejected: ...(filesystem_subscription_impl.cc), 전체 로그에 gRPC config 문자열 0건. filesystem은 gRPC mux와 분리된 자체 구현 경로를 탐
C8. CDS를 STRICT_DNS/LOGICAL_DNS + 인라인 load_assignment로 두면 EDS 구독 자체가 필요 없다 ✅ 문헌 확인 envoyproxy.io/…/service_discovery
C9. Istio 사이드카 클러스터 이름은 direction|port|subset|fqdn 규칙을 따른다 ✅ 문헌 확인 istio.io/…/proxy-cmd
C10. 레거시 path:는 단일 파일 watcher이고, 최신 path_config_source: {path, watched_directory}는 디렉터리를 watch해 symlink swap을 감지한다 ✅ 문헌 확인 envoyproxy.io/…/config_source.proto
C11. Istio 사이드카는 파일 기반 xDS를 쓰지 않고 istiod와의 단일 gRPC ADS로만 LDS/RDS/CDS/EDS를 받는다 ✅ 실측 확인 envoyproxy.io/…/xds_protocol · T22 실측 — bootstrap 전체에 path_config_source 0건, ads:{} + DELTA_GRPC만 존재
C12. (원문) istiod의 gRPC ADS 단일 스트림이 SDS까지 포함해 LDS/RDS/CDS/EDS/SDS 전부를 푸시한다 ❌ 오류 — 본문 교정 github.com/istio/istio/…/istio-agent.md — SDS는 istiod ADS 스트림이 아니라 파드 내 istio-agent가 로컬 소켓으로 별도 서빙
C13. version_info는 갱신을 게이팅하는 값이 아니라 관찰용 라벨이며, move 자체가 reload를 트리거한다 ✅ 실측 확인 envoyproxy.io/…/xds_protocol · T66 실측 — 3개 파일 모두 version_info 동일하게 유지해도 rename 시점에만 갱신됨
C14. istioctl proxy-config endpoints --cluster ...는 EDS가 런타임에 실제 갱신되는 것을 보여준다 ✅ 문헌 확인 istio.io/…/proxy-cmd
C15. macOS Docker Desktop의 가상 FS(gRPC-FUSE/virtiofs)는 inotify 전파가 덜 신뢰할 만해 Linux와 다르게 동작할 수 있다 실측 불가 github.com/docker/for-mac/issues/4999 — 홈랩은 Linux 워커 노드만 존재해 macOS 환경 재현 대상 없음

Files