Istio Ambient mode 503 에러, 원인은 stale connection!
프로덕션 환경에서 Istio Ambient mode 사용 중 워크로드 롤아웃 시 간헐적으로 503 에러 발생
초기에는 타임아웃 설정이나 config 전파 지연으로 의심했으나, 로그 분석 결과 waypoint에서 upstream connection이 끊기는 문제 확인
Pod IP 재사용과 stale connection이 겹치며 발생한 문제로, Envoy의 connection pool 관리 방식과 ztunnel의 비정상적인 connection 종료 방식이 원인으로 지목됨
근본 해결책은 upstream 개선이 필요하나, 단기적으로는 RST에 대한 retry 정책 추가로 증상 완화
503 에러의 근본 원인: Stale Connection과 IP 재사용
본문에서는 Istio Ambient mode 환경에서 워크로드 롤아웃 시 간헐적으로 발생하는 503 에러의 원인을 stale connection과 Pod IP 재사용의 복합적인 문제로 진단함.
Envoy(waypoint)의 connection pool 관리: IP:Port를 기준으로 connection을 관리하며, 목적지 Pod가 종료되어도 해당 connection을 즉시 폐기하지 않고 stale 상태로 유지함.
ztunnel의 비정상적인 connection 종료: Pod 종료 시 HBONE connection을 graceful하게(GOAWAY/FIN) 닫지 않아, upstream인 Envoy가 connection이 끊어졌음을 인지하지 못함.
IP 재사용: AWS VPC CNI 등에서 Pod IP가 재할당될 경우, Envoy는 stale connection을 마치 살아있는 connection처럼 인식하여 새 Pod로 잘못 재사용하게 됨. 이는 UpstreamConnectionTermination 에러를 유발하며, 결과적으로 503 응답으로 이어짐.
결론적으로, 이는 Envoy의 connection pool 관리 방식과 ztunnel의 connection 종료 방식, 그리고 IP 재사용이라는 조건이 맞물려 발생하는 Ambient mode 특유의 문제임.
문제 재현 및 분석을 위한 데이터 수집 전략
프로덕션 환경에서의 직접적인 디버깅 어려움을 극복하기 위해, 격리된 재현 환경을 구축하고 다각적인 데이터 수집을 수행함.
격리된 환경 구성: 노이즈를 제거한 전용 gateway, waypoint, ztunnel을 띄워 문제 재현에 집중함.
TCP 패킷 캡처(pcap): destination Pod에 `tcpdump` sidecar를 주입하여 Pod 생성부터 종료까지 전체 라이프사이클 동안의 TCP 패킷을 캡처함. 이를 통해 암호화 구간(HBONE/mTLS)과 복호화 구간의 트래픽을 비교 분석함.
Envoy Debug 로그 수집: Waypoint의 상세 로그를 통해 connection ID 재사용 여부를 직접 추적함.
Socket 상태 관찰: Pod 삭제 후에도 waypoint 내부에 해당 Pod IP를 peer로 하는 socket이 ESTABLISHED 상태로 남아있는지 확인하여 stale connection의 존재를 검증함.
이러한 데이터 기반 접근은 문제의 근본 원인을 정확히 파악하는 데 결정적인 역할을 함.
Envoy의 Connection Pool 관리와 HBONE 터널링
본문에서 설명하는 Envoy(waypoint)의 아키텍처는 downstream과 upstream connection을 분리하여 관리하는 특징을 가짐.
Downstream Listener: 클라이언트의 요청을 받는 부분.
Internal Listener (connect_originate): HBONE 터널을 통해 upstream(목적지 Pod)으로 연결하며, connection pool을 별도로 관리함.
ORIGINAL_DST Cluster: 이 cluster가 IP:Port를 key로 하여 connection pool을 관리하고 connection을 재사용함.
이러한 구조 때문에 downstream 클라이언트는 upstream connection의 상세 상태(예: Pod 종료 여부)를 즉각적으로 알기 어려움. 따라서 Envoy는 connection pool에 남아있는 stale connection을 마치 유효한 것처럼 재사용하게 되고, 이는 Pod가 이미 종료되었음에도 불구하고 handshake 없이 application data가 전송되는 현상으로 이어짐. 결과적으로 새 Pod의 TCP stack에서 RST 응답을 유발하며 503 에러가 발생함.
Istio Ambient mode의 근본 해결책과 단기 대응 방안
본 글에서는 Istio Ambient mode의 503 에러 문제에 대한 근본 해결책과 즉시 적용 가능한 대응 방안을 제시함.
근본 해결책 (Upstream 개선 필요):
1. Connection Pool Key 확장: Envoy의 connection pool key에 IP:Port 외에 Pod UID 같은 메타데이터를 추가하여, 동일 IP라도 다른 Pod라면 별개 connection으로 취급하도록 개선.
2. Graceful Connection Close 강화: ztunnel이 Pod 종료 시 HBONE connection을 GOAWAY/FIN 등으로 정상적으로 종료하도록 개선하여 Envoy가 stale connection을 인지하도록 함.
단기 대응 방안: Envoy에 RST(reset)에 대한 retry 정책을 추가하여, stale connection으로 인한 RST 발생 시 자동으로 재시도하도록 함. 이는 증상 완화에는 효과적이나 근본 해결책은 아님.
이 외에도 `meshConfig.hboneIdleTimeout` 조정이나 HTTP/2 keepalive 설정 변경 등도 보조적인 수단으로 검토되었으나, 문제의 핵심인 stale connection 재사용 자체를 막지는 못함.
Half-open Connection의 의미와 Istio Ambient mode의 함정
본 글에서 지칭하는 half-open(stale) connection은, 새로운 Pod와 그 ztunnel은 인지하지 못하는 채로 Waypoint(Envoy)는 아직 살아 있다고 믿는 connection을 의미함.
이는 Ambient mode에서 sidecar 대신 Envoy(waypoint)와 ztunnel이 분리되면서 발생한 새로운 종류의 문제임.
Envoy(waypoint) → ztunnel 경로의 취약성: Istio 메인테이너의 의견처럼, 이 경로는 ztunnel → ztunnel 경로보다 connection 상태 관리에 덜 확실할 수 있음.
IP 재사용의 방아쇠 역할: Pod가 삭제된 후 해당 IP가 새 Pod에 재할당될 때, Envoy가 들고 있던 stale connection이 새 Pod로 잘못 연결되는 확률을 높임.
결론적으로, 이 문제는 connection 재사용(Envoy pool, IP:Port 키), graceful close 부재(ztunnel), 그리고 IP 재사용(IPAM)이라는 세 가지 요소가 복합적으로 작용한 결과이며, Ambient mode 도입 시 주의해야 할 함정으로 분석됨.