homelab89 Docs Logs Legacy Files ☰ TOC 🌓
guideistio 2026-07-09istioegressdnsgslbservice-entrytls-passthroughdecision-brief

[전체판·백업] egress(mTLS passthrough)×GSLB 검증 — 세션 단절은 기우였고, 그래도 STRICT를 쓰는 이유

ABSTRACT

검증 전 과정을 담은 전체판(백업). 사내 공유용 완성본은 egress ServiceEntry resolution은 DNS(STRICT)로 쓴다, 절체 순간의 운영 시나리오는 GSLB 절체 때 실제로 벌어지는 일 참조 — 이 문서는 두 문서의 원천으로 보존한다. 우리 환경 — 앱이 직접 HTTPS를 맺고, sidecar↔egress gateway 구간은 Istio mTLS로 감싸며, gateway는 앱의 TLS를 열어보지 않고 통과시키는 mTLS passthrough 구성, 사내 도메인은 GSLB가 VIP 하나를 반환하는 것이 기본 — 에서 ServiceEntry 설정을 검증한 결과다. 이번 검증 대상(gateway가 TLS를 열지 않고 나르는 L4 동작 + DNS에 따른 IP 목록 관리)은 mTLS 유무와 무관하게 동일하므로, 테스트는 단순 passthrough 구성으로 진행했다. 요약 세 줄: ① 도입 초기에 걱정했던 “GSLB가 IP를 바꾸면 기존 세션이 끊긴다"는 기우였다 (공식 문서 + 직접 실측으로 확인, 증적 첨부). resolution: DNS(STRICT)를 표준으로 쓴다 — 사내 GSLB 도메인(단일 VIP)에서는 두 설정의 차이가 거의 없지만, egress가 함께 처리하는 외부 일반 도메인은 복수 IP를 반환할 수 있고 그 IP들을 실제로 활용하는 쪽은 STRICT뿐이다. 표준은 도메인마다 갈라 쓸 수 없다. ③ 단일 VIP인 사내 GSLB 도메인에서 절체 대비의 실체는 (계획 절체) 앱 커넥션 수명 관리, (장애 절체) GSLB 감지 속도와 TTL이다.

NOTE

근거 등급 — 이 문서의 모든 주장에는 근거 등급을 붙였다: [실측] = 홈랩 재현 랩에서 직접 측정(원시 리포트 공개), [공식 문서] = Envoy 공식 문서 원문 인용, [논리 귀결] = 앞의 두 사실로부터의 직접 도출. 이 세 등급에 들지 못하는 추정성 서술은 싣지 않았다.

1. 우리 환경

flowchart LR
    APP["client app<br/>HTTPS를 직접 맺음"] --> SC["sidecar<br/>암호화된 바이트만 통과"]
    SC -->|"Istio mTLS 터널"| GW["egress gateway<br/>SNI만 보고 통과 - L4"]
    GW --> VA["VIP-A"]
    GW -.-> VB["VIP-B"]
    DNS["GSLB DNS<br/>VIP 하나만 반환이 기본<br/>+ 장애/점검 시 절체"] -.->|"IP 목록 갱신"| GW

앱이 TLS를 직접 맺으므로 sidecar와 egress gateway는 HTTP 요청/응답을 볼 수 없고 암호화된 바이트를 나르기만 한다(L4). sidecar↔gateway 구간의 Istio mTLS는 이 사실을 바꾸지 않는다 — mTLS는 나르는 통로를 한 겹 더 감쌀 뿐이고, gateway가 앱의 TLS를 열지 못하는 것은 같다. 그래서 테스트 랩은 mTLS 구간을 뺀 단순 passthrough로 구성했고, 이 문서의 실측은 그 구성에서 나온 것이다. 이 “L4"라는 사실이 문서 전체를 지배한다 — Envoy가 HTTP 요청 단위로 개입하는 기능(요청 재시도 등)은 이 경로에 없다.

이 gateway가 처리하는 외부 도메인은 DNS 응답 관점에서 두 부류다:

부류 DNS 응답
사내 GSLB 도메인 VIP 하나만 반환이 기본 — 장애·점검 때 다른 VIP로 바꿔서 반환 사내·제휴 서비스
외부 일반 도메인 복수 IP를 반환할 수 있음 파트너 API, SaaS

이 문서에서 절체란 GSLB가 도메인의 A레코드(도메인→IP 매핑)를 다른 VIP로 바꾸는 일을 말한다 — 계획된 점검 배수든, 장애 대응이든.

ServiceEntry.resolution은 “Envoy가 이 도메인의 IP 목록을 어떻게 관리하는가"를 정한다:

설정 Envoy 내부 이름 동작을 한 줄로
DNS STRICT_DNS DNS 응답을 IP 목록 그 자체로 쓴다. DNS가 갱신되면 목록도 갱신
DNS_ROUND_ROBIN LOGICAL_DNS 목록을 안 만든다. 새 연결을 만드는 순간에만 최신 DNS 응답의 첫 IP를 쓴다

2. 걱정 1 — “GSLB가 IP를 바꾸면 기존 세션이 끊긴다?” → 기우로 확인

걱정의 논리는 이랬다: “STRICT는 DNS가 갱신되면 IP 목록을 즉시 교체한다니까, 그 순간 그 IP로 통신 중이던 연결도 끊길 것이다.” 두 방향에서 검증했다.

공식 문서Envoy service discovery의 STRICT_DNS 원문은 “will drain traffic from any existing connection pools"다. drain은 “지금 하는 일은 끝내게 두고 새 일만 안 준다"는 뜻이지, 끊는다(close)가 아니다. “IP가 바뀌면 기존 연결을 즉시 정리"는 오히려 일부러 켜야 하는 별도 옵션으로 존재한다 (close_connections_on_host_set_change, 기본 false). 기본이 즉시 정리라면 이 옵션이 있을 이유가 없다.

실측 — 40초짜리 응답을 받는 도중에 절체(A레코드를 옛 VIP → 새 VIP로 변경)를 일으키고, Envoy의 상태를 4개 시점에서 찍었다:

sequenceDiagram
    participant C as client (curl)
    participant E as Envoy (L4)
    participant A as server A (기존 IP)
    participant D as GSLB DNS
    C->>E: HTTPS 요청 (40초짜리 응답)
    E->>A: TCP 연결, 스트리밍 시작
    Note over D: +5초 - A레코드를 B로 변경
    D-->>E: 백그라운드 갱신 - IP 목록은 B로
    Note over E,A: 기존 연결은 그대로 둠
    A-->>C: 스트리밍 계속
    A-->>C: +40초 - 409,610바이트 전량 수신, HTTP 200

위 그림의 각 시점에서 실제로 확인된 것을 말로 옮기면:

시점 DNS는 뭐라 답하나 Envoy의 IP 목록 진행 중이던 40초 요청은
시작 옛 VIP(A) 옛 VIP(A) 스트리밍 시작
절체 +7초 새 VIP(B) — 절체 반영됨 아직 옛 VIP (갱신 주기 전) 계속 스트리밍
절체 +25초 새 VIP(B) 새 VIP(B)로 교체 완료 목록이 바뀌었는데도 계속 스트리밍
요청 완료 새 VIP(B) 새 VIP(B) 409,610바이트 전량 수신, HTTP 200 — 연결이 닫힌 것은 이때뿐

(카운터 원값: “연결 종료” 누적 카운터는 절체 전 38 → 요청 진행 내내 38 그대로 → 요청이 끝난 뒤에야 39. 활성 연결 수는 요청 내내 1을 유지. 실제 실행 기록 전문은 아래 raw 링크.)

IP 목록이 새 VIP로 바뀐 뒤에도 기존 연결은 살아서 스트리밍을 계속했고, 연결이 닫힌 것은 요청을 마친 클라이언트가 닫은 시점이다. STRICT/LOGICAL 양쪽, 그리고 sidecar가 TLS를 대신 맺는 L7 경로까지 4가지 조합 전부에서 진행 중 요청은 완주했다(원표는 Q&A 문서의 실측 부록). 결론: “세션 끊김” 걱정으로 resolution을 고를 필요가 없다 — 어느 쪽도 안 끊는다.

원시 데이터(raw): 위 표의 수치가 나온 실제 실행 기록 전문 — 이 절의 L4 실측은 passthrough 원시 리포트, L7 4점 스냅샷은 part2 원시 리포트, 무가공 실행 트랜스크립트(.txt) 포함 전체 26파일 색인은 Q&A 문서 실측 부록의 “원시 데이터 색인”에 첨부돼 있다. 다운로드 사본: files.homelab89.com/istio-egress/dns-resolution/.

3. 그럼 왜 STRICT인가 — 세션이 아니라 “장애 때 작동하는 장치” 때문

세션에 차이가 없다면 무엇으로 고르는가. 먼저 오해 하나를 제거하자:

로드밸런싱 동작은 두 설정이 사실상 같다. Envoy는 연결을 만드는 순간에 DNS를 묻지 않는다 — “Envoy never synchronously resolves DNS in the forwarding path” [공식 문서]. 어느 설정이든 백그라운드 주기(TTL)로 갱신된 최신 결과를 쓸 뿐이므로, 한 주기 안의 새 연결은 전부 같은 응답 결과로 간다 [논리 귀결]. 즉 GSLB의 “질의당 분산"은 양쪽 모두 이 갱신 주기 단위로 반영되며, LOGICAL을 골라도 더 고운 분산을 얻는 것이 아니다.

그리고 하나 더 정직하게 깔아두자: 사내 GSLB 도메인처럼 A레코드가 항상 VIP 하나뿐인 경우에는 두 설정의 실질 동작 차이가 거의 없다. 목록이 항상 1개라서, “죽은 VIP를 골라내고 남은 멤버로 우회"하는 outlier detection도 우회할 곳이 없어 효과가 없다(자세한 메커니즘은 “outlier detection이 하는 일과 안 하는 일” 절). 그럼에도 STRICT를 표준으로 정하는 근거는 “강력한 효과"가 아니라 다음 네 가지다:

  1. 비용이 없다 [실측]. STRICT의 유일한 비용(목록이 바뀔 때 놀고 있는 연결이 정리되는 것)은 L4인 우리 환경에서 발생하지 않는다 — 기존 연결을 아예 안 건드린다(위 실측 표).
  2. 표준은 도메인마다 갈라 쓸 수 없는데, 복수 IP 도메인을 감당하는 쪽은 STRICT뿐이다 [실측]. 사내 GSLB 도메인은 단일 VIP가 기본이지만, 같은 egress가 처리하는 외부 일반 도메인(파트너 API·SaaS)은 지금도 복수 IP를 반환할 수 있다(1절의 두 부류). 같은 2-IP 상태에서 STRICT는 실제로 두 IP 모두에 트래픽을 분산했다(curl 12회 중 backend-a 7 / backend-b 5). LOGICAL은 통신 자체는 정상이지만 pilot-agent request GET clusters에 잡히는 cluster 멤버가 첫 IP 하나뿐이라 curl 15회 전부 그 IP로만 갔다 — 나머지 IP는 조용히 무시된다. “깨진다"가 아니라 DNS가 복수 IP를 준 의도(분산·페일오버 후보)를 LOGICAL은 실현하지 못한다는 뜻이다. 도메인 부류마다 SE 설정이 갈라지는 것 자체도 운영 비용이다. (정정, 2026-07-10: 이전 판에 실었던 “그 순간 설정 거부(CDS NACK)로 통신이 깨진다"는 오류였다. 2026-07-09 실측(2026-07-09_211314-dns-logical-multia.md)으로 확인된 실체는, 그 제약이 실제로 걸리는 지점은 SE.spec.endpoints에 여러 개를 명시적으로 선언할 때뿐이고 그것도 CDS NACK이 아니라 kubectl apply 시점의 admission webhook 거부라는 것이다 — The ServiceEntry ... is invalid: ... DNS_ROUND_ROBIN mode cannot have multiple endpoints. 이 문서가 다루는 시나리오, 즉 런타임에 DNS가 실제로 복수 A레코드를 응답하는 경우는 이 제약과 무관하다 — Envoy가 첫 IP만 골라 쓸 뿐 xDS 왕복 자체가 없어 NACK이 날 지점이 없다 [실측].)
  3. 절체가 기록된다 [실측]. STRICT는 GSLB 절체가 membership 이벤트로 카운터에 남아 “언제 절체됐나"를 장애 시각과 대조할 수 있다. LOGICAL은 무기록인 데다 목록 라벨이 실제 행선지와 어긋나는 함정까지 실측됐다. 단, 과장하지 않는다 — L4 장수명 연결에서는 STRICT도 “제거된 VIP에 남은 연결이 endpoint 목록에서 안 보이는” 사각지대가 있어(운영 시 주의 절 참조, 이것도 실측) 관측 우위는 제한적이다.
  4. 복수 IP 도메인에서는 죽은 IP 자동 격리(outlier detection)가 실제로 작동한다 [실측 — 복수 endpoint 조건]. 실측(실패율 51.7%→0.21%)은 목록에 살아있는 대안이 함께 있던 조건에서 나온 수치다. 외부 일반 도메인이 지금 이 조건에 해당하고, 사내 GSLB 도메인도 복수 A레코드 반환으로 바꾸면 이 장치가 살아난다. LOGICAL은 그 상태에서도 여전히 첫 IP 하나만 쓰므로(위 근거 2), 분산도 outlier도 결국 둘 다 STRICT를 전제로만 성립한다.

참고 — LOGICAL이 맞는 자리는 따로 있다: 판별 질문은 “응답에서 IP가 빠졌을 때 그 빠짐에 의미가 있는가"다. 사내 GSLB는 VIP 몇 개짜리 작은 고정 풀이고 빠짐 = 의도(장애·점검·절체)라서 그 의미를 목록에 반영하는 STRICT가 맞다. 반면 수백 IP 풀에서 매번 일부만 잘라 보여주는 대형 SaaS/CDN은 빠짐에 아무 의미가 없어서(빠진 IP도 멀쩡) 목록을 안 만드는 LOGICAL이 맞다 — “질의마다 응답이 다르다"는 사실 자체는 기준이 아니다.

4. 절체가 일어나면 실제로 벌어지는 일

절체의 이유에 따라 완전히 다른 두 상황이 된다.

계획 절체 (점검 배수 — 옛 VIP가 살아있는 상태) → 무손실 가능

sequenceDiagram
    participant APP as app
    participant E as egress Envoy (L4)
    participant A as VIP-A (계속 살아있음)
    participant B as VIP-B
    participant G as GSLB DNS
    Note over G: 절체 - A레코드를 VIP-A에서 VIP-B로 변경
    G-->>E: TTL 주기 갱신 - IP 목록 = [B]
    Note over APP,A: 1) 진행 중이던 요청 - 그대로 완료 (실측)
    APP->>E: keepalive로 쥔 기존 연결의 다음 요청
    E->>A: 2) 같은 연결 그대로 - 여전히 VIP-A로 (실측)
    APP->>E: 새 연결
    E->>B: 3) 새 연결부터 VIP-B로 (실측)
    Note over A: 옛 VIP가 조용해지는 시점 =<br/>앱 커넥션 수명이 다한 뒤

무손실이다. 갈래 2)(keepalive 연결이 계속 옛 VIP로 가는 것)까지 실측으로 확정했다 [실측, 2런 동일] — 하나의 TLS 연결을 유지한 채 순차 요청을 보내며 중간에 절체:

요청 연결 실제 접속지 응답 서버
1번 (절체 전) 새 연결 pod-A backend-a
2번 (절체 반영 확인 후, 같은 연결) 재사용 (로컬 포트 동일) pod-A 그대로 backend-a
3번 (같은 연결) 재사용 pod-A 그대로 backend-a
4번 (연결 닫고 새로 맺음) 새 연결 pod-B backend-b

연결 재사용은 Envoy 카운터로 교차 증명했다 — 요청 4개에 연결 생성 카운터는 정확히 2번만 증가(1번·4번 시점). 원시 리포트: docs/test-reports/2026-07-09_204354_dns-passthrough-keepalive-pin.md.

따라서 “옛 VIP가 조용해지는 시간"은 Istio가 아니라 앱의 커넥션 수명이 결정한다 — L4에서는 요청이 끝나도 Envoy가 연결을 회수하지 않으므로. 절체 runbook에 필요한 것:

  1. 절체 후 옛 VIP를 앱 커넥션 최대 수명만큼 살려둘 것 (바로 내리면 아래 장애 절체가 됨)
  2. 앱 커넥션 풀의 max lifetime 상한 합의 (절체 완료 목표 시간보다 짧게)
  3. 배수 완료 판단은 DNS가 아니라 옛 VIP의 연결 수 모니터링으로

장애 절체 (VIP 사망 → GSLB가 감지 후 변경) → 유손실 구간이 구조적으로 존재

sequenceDiagram
    participant APP as app
    participant E as egress Envoy (L4)
    participant A as VIP-A (사망)
    participant B as VIP-B
    participant G as GSLB DNS
    Note over A: t=0 - VIP-A 사망
    APP->>E: 요청 (진행 중 + 신규)
    E-xA: 연결/요청 실패 - 실패가 앱까지 전달
    Note over APP,G: 유손실 구간 W - 목록엔 죽은 VIP-A뿐<br/>W(단일 A레코드) = GSLB 감지 + TTL + Envoy 갱신<br/>W(복수 A레코드로 바꾸면) = outlier 격리 - 수 초
    Note over G: GSLB가 장애 감지 - A레코드를 VIP-B로 변경
    G-->>E: TTL 주기 갱신 - IP 목록 = [B]
    APP->>E: 이후 새 연결
    E->>B: 정상

주의: “세션 안 끊김” 확인은 IP 변경 때문에는 안 끊긴다는 뜻이다. 서버가 죽으면 그 위의 요청은 당연히 죽고, L4에서는 Envoy가 이 실패를 앱 대신 흡수하지 못한다(실측: 완화 없이 요청 44%가 실패로 앱 도달).

단일 A레코드인 현 구조에서 W를 줄이는 실질 레버는 Envoy가 아니라 GSLB에 있다 — 감지 주기와 TTL. 이 구간엔 목록에 죽은 VIP 하나뿐이라 Envoy 차원의 우회가 성립하지 않기 때문이다. Envoy/앱 쪽에서 유효한 것과 한계:

  • 짧은 connect timeout (1초) — 죽은 IP를 만나도 1초 만에 실패 판정 (요청이 매달리는 것 방지 — 단일 A에서도 유효)
  • 앱의 연결 실패 한정 재시도 — 단, W 안에서 즉시 재시도하면 같은 죽은 VIP를 다시 만난다. 재시도 간격(백오프)이 W를 넘어설 때만 구제가 된다 — W가 수 초대가 아니라면 재시도 횟수보다 백오프 설계가 중요
  • outlier detection — 현 구조(단일 A)에서는 우회 효과 없음. 복수 A레코드로 바꾸면 W 자체가 수 초로 줄어드는 구조가 된다 (실측 51.7%→0.21%가 그 조건)

따라서 “GSLB가 복수 A레코드를 반환하게 할 수 있는가"가 이 설계의 가장 큰 갈림길이다 — 가능하다면 장애 절체의 유손실 구간이 “GSLB 감지+TTL”(수십 초 단위 가능성)에서 “outlier 격리”(수 초)로 구조적으로 줄어든다.

5. outlier detection이 하는 일과 안 하는 일

사내 공유 때 반드시 나올 질문: “outlier가 되면 뭐가 되는데? 실패하면 DNS 질의를 다시 하나?”

아니다 — DNS와 outlier는 서로를 호출하지 않는 별개의 장치다. 둘 다 같은 IP 목록을 만지되 역할이 다르다:

장치 역할 트리거
DNS 갱신 목록에 누가 있는가 (명단) 자기 주기 (TTL) — 실패와 무관하게 돈다
outlier detection 명단 중 누구에게 새 연결을 줄 것인가 (건강 표시) 연결 실패 누적
앱 재시도 이미 실패한 그 요청의 구제 실패 그 자체

outlier가 하는 일: 어떤 VIP로의 연결 실패가 연속 3회 쌓이면, 그 VIP를 목록에서 지우는 게 아니라 “일시 제외” 표시를 한다(우리 설정 기준 30초, 반복되면 제외 시간이 늘어난다). 그동안 새 연결은 목록에 남은 다른 VIP로만 간다. 제외 시간이 지나면 다시 후보에 넣어 살아났는지 자연스럽게 확인된다.

outlier가 안 하는 일 세 가지:

  1. DNS 재질의를 유발하지 않는다. DNS 갱신은 자기 주기로만 돈다. outlier는 그 주기 사이의 공백(“GSLB는 아직 모르는 죽은 VIP”)을 메우는 장치다.
  2. 이미 실패한 요청을 살려내지 못한다. 격리는 다음 연결부터의 예방이다. 첫 1~3건의 실패는 앱에 도달한다 — 그걸 흡수하는 것이 앱 재시도의 몫이다.
  3. 목록에 대안이 없으면 우회시킬 곳도 없다. GSLB가 A레코드를 하나만 반환하는 순간의 목록은 VIP 1개다 — 그게 죽어 있으면 outlier로도 갈 곳이 없고, 복구는 DNS 갱신(TTL)을 기다려야 한다. outlier의 효과는 목록에 살아있는 대안이 있을 때 성립한다 — 우리 실측 (51.7%→0.21%)도 목록에 정상 endpoint가 함께 있던 조건이다 [실측]. 덧붙여 예시 설정의 maxEjectionPercent: 50은 목록이 1개일 때 그 하나를 제외하는 것 자체를 막는다 [공식 문서] — “최소 1개는 무조건 제외"는 별도 옵션 always_eject_one_host(기본 false)를 켜야만 하는 동작이다(outlier_detection.proto: “Will eject at least one host regardless of the value if always_eject_one_host is enabled”). 즉 단일 A레코드 구조에서 outlier는 문자 그대로 아무 일도 하지 않는다. GSLB가 복수 A레코드를 반환하게 할 수 있다면 이 장치의 가치가 온전해진다 (STRICT만 복수 A를 수용한다는 앞 절과 연결되는 지점).

6. 전체 설정 예시

권장 세트 (우리 환경: 앱 HTTPS + L4 passthrough)

# 외부 도메인 등록 — resolution: DNS(STRICT)
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: partner-api
spec:
  hosts: ["api.partner.example"]        # GSLB가 리전 VIP를 로드밸런싱하는 외부 도메인
  location: MESH_EXTERNAL
  resolution: DNS                        # STRICT_DNS: DNS 응답 = IP 목록
  ports:
    - number: 443
      name: tls
      protocol: TLS                      # 앱이 직접 TLS를 맺음 → Envoy는 통과만(L4)
---
# 죽은 VIP 자동 격리 — 실측에서 실패율 51.7% → 0.21%를 만든 설정
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: partner-api-outlier
spec:
  host: api.partner.example
  trafficPolicy:
    connectionPool:
      tcp:
        connectTimeout: 1s               # 죽은 IP의 연결 실패를 1초 안에 판정
    outlierDetection:
      splitExternalLocalOriginErrors: true
      consecutiveLocalOriginFailures: 3  # 연결 실패(연속 3회)면
      interval: 5s                       # 5초마다 판정해서
      baseEjectionTime: 30s              # 그 VIP를 30초간 목록에서 일시 제외
      maxEjectionPercent: 50             # 단 목록의 절반까지만 (전멸 방지)
      minHealthPercent: 0

앱 팀에 요청할 두 가지: ① 연결 실패(connect timeout/reset) 한정 재시도 12회 + connect timeout 13초, ② 커넥션 풀 max lifetime을 절체 완료 목표 시간 이하로.

안티 예시 두 가지

# (1) GSLB 도메인에 LOGICAL — 쓰지 않는다
spec:
  resolution: DNS_ROUND_ROBIN   # outlier 무력 + 복수 A레코드를 받아도 첫 IP만 사용(나머지 무시) + 관측 어긋남
# (2) L7 경로(원격 TLS를 sidecar가 대신 맺는 팀)에서 기본 재시도 끄기 — 쓰지 않는다
http:
  - retries:
      attempts: 0   # Istio가 기본 탑재한 "연결 실패 시 다른 IP로 재시도"가 꺼진다

(L7 경로 팀 참고: Istio는 VS에 retries를 안 쓰면 “연결 실패 → 다른 IP로 최대 2회 재시도"를 자동 적용한다 — 같은 실측에서 L7이 86/86 무손실이었던 이유. 또 DR에서 포트별 portLevelSettings를 쓰면 outlier도 반드시 그 안에 넣어야 적용된다.)

7. 운영 시 주의

  • 연결 정리 상태를 endpoint 목록으로 판단하지 말 것. 목록에서 제거된 VIP에 아직 살아있는 연결은 istioctl proxy-config endpoints에 보이지 않는다(cluster 합계 upstream_cx_active 카운터로만 보임). 실측으로 확인된 관측 사각지대.
  • 클라이언트가 IP를 직접 지정해도 소용없다 [실측]: passthrough SE 경로에서 클라이언트가 특정 backend IP로 강제 접속(--resolve)해도 실제 행선지는 Envoy가 자기 IP 목록에서 고른 곳이었다. 행선지를 지배하는 것은 클라이언트의 접속 IP가 아니라 Envoy의 목록이다 — 디버깅 때 착각하기 쉬운 지점.
  • 미실측 범위: ① 수 분급 초장기 스트림의 drain 동작, ② HTTP/2 경로. 해당 워크로드 적용 전 추가 확인 필요. (계획 절체에서 keepalive 연결이 옛 VIP에 계속 붙어 있는 현상은 2026-07-09 실측으로 확정되어 이 목록에서 제외됨.)

8. 근거 자료 (읽는 순서)

  1. Q&A — GSLB가 IP를 바꾸면 내 요청은 어떻게 되나 — 쉬운 입구 + 실측 부록(모든 원본 수치)
  2. SE resolution × TLS passthrough — in-flight 요청의 운명 — 4조합 정밀 비교 + 공식 문서 대조
  3. DNS/GSLB resolution 재현 랩 — 직접 재현 가능한 절차·킷
  4. ServiceEntry resolution 이론 runbook — 필드 정본 (초기 권장이 뒤집힌 교정 이력 포함)
  5. 공식 문서: Envoy — Service discovery · cluster.proto — CommonLbConfig
  6. 원시 리포트·manifest·재현 스크립트: files.homelab89.com/istio-egress/dns-resolution/
NOTE

이 문서는 전체판(백업)이다. 사내 공유 전에 확인할 것(완성본 말미와 동일): ① GSLB 응답 패턴 — dig를 여러 번 쳐서 A레코드가 몇 개 오는지(복수면 outlier 효과의 전제가 충족되고 STRICT 필수 근거도 강해짐), 고정형인지 회전형인지, TTL 몇 초인지. ② 절체 완료 목표 시간 — 앱 커넥션 max lifetime 권장값이 여기서 나옴. ③ 초장기 스트리밍 워크로드 유무 — 미실측 범위 해당 여부.

Files