본문으로 건너뛰기
네트워크 L4·L7 스터디

L7 프록시는 요청 단위 처리가 필요한 곳에만 둔다 — 30분 스터디 자료

같은 요청을 30분 동안 따라가기

파드 A가 curl http://svc-b를 실행하면 요청은 어디를 거칠까요? L4는 연결 단위로 파드를 고르고, 요청 단위 처리가 필요한 곳에만 L7 프록시를 둡니다. 프록시의 위치에 따라 비용과 장애 반경도 달라집니다. 도식은 요청의 경로와 L7 프록시가 들어갈 자리를 보여줍니다.

파드 A의 호출은 Service에서 백엔드 파드가 정해지고 CNI 경로로 파드 B에 닿으며, HTTP를 읽어야 하는 요청만 L7 프록시를 거칩니다.
도식 텍스트
  • 파드 A — curl svc-b
  • Service 변환 — 백엔드 파드 고르기
  • CNI 경로 — veth · 노드 간 전달
  • 파드 B — 백엔드
  • L7 프록시 — HTTP를 읽는 자리
  • 호출
  • 목적지
  • 도착
  • HTTP면
  • 요청별
구간시간내용
도입2분질문 하나, 두 계층의 역할
1부 L412분파드 네트워크 모델, 오버레이와 네이티브 라우팅, kube-proxy, Cilium eBPF
2부 L712분L4로 못 하는 일, 사이드카, 비용, ambient, 경계 장애
정리·질의4분비교표, 결론 질문, 질문 받기

근거 표기 — ✓ 1차 출처 확인 · Ⓥ 벤더 주장 · ≈ 추정 · ? 미확인 · Σ 종합 판단. 각 절 끝의 ‘근거와 측정 조건’에 조건과 출처를 모았습니다. 조사 기준일은 2026-10-26이며 Kubernetes 1.37.1, Cilium 1.20.4, Istio 1.31.3, Amazon VPC CNI v1.23.2 문서를 봤습니다.

발표에서 더 풀어 설명할 내용은 근거와 세부 설명 전체본에 모았습니다.

근거와 측정 조건
주장수치·조건출처근거
조사 기준 버전Kubernetes 1.37.1(2026-09-15), Cilium 1.20.4(10-23), Istio 1.31.3(10-22), Amazon VPC CNI v1.23.2(09-30)Kubernetes 릴리스, Cilium 릴리스, Istio 릴리스, VPC CNI 릴리스✓
시간 배분2 / 12 / 12 / 4분발표 구성안Σ

연결을 고르는 L4 경로

쿠버네티스는 파드마다 클러스터에서 유일한 IP를 부여하고, 파드끼리 NAT 없이 직접 통신하도록 정합니다. 리눅스 컨테이너 런타임은 CNI로 구현체를 호출하고, 구현체는 그 통신 경로를 만듭니다. Cilium 오버레이는 터널로 노드를 잇습니다. AWS 문서의 VPC CNI는 오버레이 없이 파드에 VPC IP를 할당합니다.

kube-proxy는 EndpointSlice를 보고 Service IP를 백엔드 파드 IP로 변환합니다. 동작 원리로 보면 같은 연결의 패킷은 conntrack에 저장한 백엔드 선택을 따릅니다. Cilium은 kubeProxyReplacement=true로 켠 대체 모드에서 socket-LB를 사용합니다. 아래는 구현별 백엔드 선택 시점과 연결 단위라는 공통점을 비교한 도식입니다.

iptables와 nftables는 연결의 첫 패킷에서, Cilium은 connect() 시점에 백엔드를 고르므로 어느 쪽이든 분산 단위는 연결입니다.
도식 텍스트
  • iptables — kube-proxy
  • KUBE-SERVICES — 서비스 수만큼 순차
  • 첫 패킷 DNAT — conntrack에 저장
  • nftables — kube-proxy
  • verdict map — 규칙 하나로 디스패치
  • 첫 패킷 DNAT — conntrack에 저장
  • Cilium — 소켓 레벨 LB
  • eBPF 훅 — connect() 시점
  • 목적지 교체 — 패킷마다 NAT 없음
  • 순차
  • 일치
  • 조회
  • 일치
  • 호출 시
  • 교체
근거와 측정 조건
주장수치·조건출처근거
파드 IP 유일, NAT 없는 직접 통신예외는 Windows hostNetwork 파드Kubernetes 서비스·네트워킹✓
Cilium 캡슐화·네이티브 라우팅VXLAN 8472/UDP, Geneve 6081/UDP, VXLAN 패킷당 50바이트Cilium 라우팅 (stable 1.20.x)✓
VPC CNI 동작최대 파드 수 식, /28 프리픽스 16개, 파드 삭제 후 IP 30초 쿨다운, v1.9.0 이상에서 prefix delegationEKS VPC CNI 모범 사례, Prefix modeⓋ
백엔드 선택은 첫 패킷, conntrack에 저장문서에 이 문장은 없고 동작 원리를 설명한 것Virtual IPs 문서의 DNAT 서술≈
Cilium KPR·소켓 LB·MaglevKPR Helm 기본값 false, Maglev는 N-S 한정, maglev.tableSize 기본 16381Cilium kube-proxy 없는 구성 (1.20.4)✓

kube-proxy 모드의 현재 상태와 전환 일정

Kubernetes 1.37의 기본 모드는 iptables입니다. AWS 문서는 nftables가 1.33에서 GA가 됐다고 적고, 기본값을 nftables로 바꾸는 KEP-5343은 아직 Alpha·provisional 제안입니다. Kubernetes 문서는 iptables와 nftables의 패킷 처리 성능 차이를 수만 개 서비스 규모에서 체감한다고 설명합니다. 도식은 nftables 전환과 IPVS 폐기 일정을 보여줍니다.

nftables 모드는 1.33에서 GA가 됐고 1.40에 기본값이 되도록 제안돼 있으며, IPVS는 1.35에서 deprecated돼 1.43에 제거될 예정입니다.
근거와 측정 조건
주장수치·조건출처근거
kube-proxy 모드 현황1.37 기본 iptables, nftables 커널 5.13 이상, ipvs 1.35 deprecated·1.40 기본 꺼짐·1.43 제거Virtual IPs 문서, KEP-5495✓
nftables GA 시점1.29 alpha, 1.31 beta, 1.33 GAAWS nftables 문서Ⓥ
nftables 기본값 전환 일정1.37 경고, 1.39 beta, 1.40 기본 전환. 현재 Alpha·provisionalKEP-5343✓
iptables O(n), nftables 대략 O(1)성능 차이는 수만 개 서비스 규모에서 체감nftables kube-proxy 블로그, Virtual IPs 문서✓

요청을 나누는 L7과 사이드카 비용

L4는 HTTP 요청의 경계와 헤더, 상태 코드를 읽지 못합니다. gRPC 쏠림을 풀려면 클라이언트가 백엔드를 나누거나 L7 프록시가 요청을 나눠야 합니다. 아래 도식은 연결 단위 분산과 요청 단위 분산의 차이를 보여줍니다.

HTTP/2 연결 하나에 요청이 다중화되면 L4 분산은 요청 전부를 한 파드에 보내고, L7 프록시는 요청마다 백엔드를 고릅니다.
도식 텍스트
  • gRPC 클라이언트
  • 분산 지점
  • 파드 1
  • 파드 2
  1. 1. 연결 하나 맺음
  2. 분기 — L4 분산 (Service)
    1. 2. 연결을 파드 1로
    2. 3. 요청 1·2·3 (같은 연결)
    3. 요청을 받지 못함
  3. L7 프록시 (요청 단위)
    1. 연결 안의 요청을 읽음
    2. 2. 요청 1
    3. 3. 요청 2

Istio의 Envoy는 요청 단위 재시도와 헤더 기반 라우팅을 처리합니다. 사이드카는 파드마다 붙으므로 파드 수만큼 리소스 비용도 늘어납니다. Istio 1.24 공식 벤치마크에서 HTTP 1,000 req/s, 1KB 페이로드를 처리하는 사이드카 하나는 약 0.20 vCPU와 60 MB를 사용했습니다.

근거와 측정 조건
주장수치·조건출처근거
gRPC 연결 쏠림HTTP/2는 장수 연결에 요청을 다중화, 연결 후에는 요청이 파드 하나에 고정. 글쓴이가 Linkerd 측이라 일부 벤더 시각Kubernetes 블로그 2018, gRPC 블로그 2017✓
L4가 못 하는 이유5-tuple만 본다는 원리 설명원리 설명≈
Envoy의 재시도·헤더 라우팅·least requestsIstio 1.31 문서 기준Istio 트래픽 관리✓
프록시별 리소스 단가HTTP 1,000 req/s, 1KB 페이로드, Istio 1.24 기준 벤치마크. 사이드카 0.20 vCPU·60 MB, waypoint 0.25 vCPU·60 MB, ztunnel 0.06 vCPU·12 MB14 왜 서비스 메시인가✓

Ambient의 배치와 지연·롤아웃 사례

Ambient는 ztunnel에 L4를 맡기고 요청 단위 처리가 필요한 구간에 waypoint를 둡니다. mTLS는 L7 전용 기능이 아니며 ztunnel 같은 L4 프록시로도 가능합니다. 아래 도식은 사이드카·ambient·Cilium의 프록시 배치를 비교합니다.

L7을 처리하는 Envoy는 사이드카에서는 파드마다, ambient에서는 서비스 앞의 waypoint에, Cilium에서는 노드마다 하나씩 있습니다.
도식 텍스트
  • 클라이언트 파드 — 사이드카
  • 사이드카 Envoy — 발신 파드마다
  • 사이드카 Envoy — 수신 파드마다
  • 클라이언트 파드 — ambient
  • ztunnel — 노드마다 · L4
  • waypoint — Envoy · L7
  • 클라이언트 파드 — Cilium
  • eBPF — 커널 · L4
  • cilium-envoy — 노드마다 · L7
  • iptables
  • mTLS
  • 캡처
  • HBONE
  • 소켓 LB
  • L7만

지연 수치는 atomai의 외부 실험에서 왔습니다. Istio 1.30.2, EKS 1.36.2, m7g.xlarge 노드 3대에서 200 QPS·연결 16개로 측정했습니다. 원시 결과·실행 스크립트가 공개되지 않았고 반복 횟수도 적혀 있지 않아 SLO 판단 근거로 삼아서는 안 됩니다. 다음 도식은 정상 상태의 경로별 P50을 비교합니다.

atomai 실험(Istio 1.30.2, EKS 1.36.2)에서 ambient L4의 P50은 mesh 없음에 가까웠고, 사이드카와 waypoint 경로는 2ms를 넘었습니다.

채널코퍼레이션 DevOps팀이 겪은 롤아웃 중 503은 터널 수명 문제였습니다. 재시도 조건을 reset-before-request에서 reset으로 넓혀 증상을 줄였지만, 근본 해결은 워크로드 신원과 파드 UID를 풀 키에 넣는 upstream 개선으로 남아 있습니다. 도식은 죽은 터널을 재사용하게 된 조건을 보여줍니다.

half-open은 아무도 신호를 보내지 않아서 생깁니다 — Pod가 사라져도 waypoint의 pool에는 살아 있는 터널로 남고, 같은 IP를 받은 다음 Pod에게 handshake 없는 data frame이 날아갑니다. 터널이 이미 걷힌 뒤라면 같은 요청이 정상 처리됩니다.
도식 텍스트
  • 클라이언트
  • waypoint
  • ztunnel
  • destination Pod
  1. 1. Pod-aaa로 요청
  2. 2. HBONE CONNECT :15008
  3. 3. 복호화된 평문 → Pod-aaa
  4. pool key = 10.90.142.96:15008 → ConnectionId 79097
  5. Pod-aaa 종료 · 같은 IP를 Pod-bbb가 승계
  6. ztunnel은 GOAWAY도 FIN도 보내지 않는다 · waypoint에게 79097은 여전히 살아 있는 터널이다
  7. 4. 같은 IP:Port로 다음 요청
  8. 분기 — pool에 79097이 남아 있다 (hboneIdleTimeout 이내)
    1. 5. 재사용 · handshake 없이 data frame
    2. 6. RST · 새 netns에 상태 없음
    3. 7. 503 · UC
  9. pool에서 이미 걷혔다 — idle timeout 만료 또는 reset 재시도
    1. 5'. 새 HBONE 터널 handshake
    2. 6'. 복호화된 평문 → Pod-bbb
    3. 7'. 200
근거와 측정 조건
주장수치·조건출처근거
ztunnel·waypoint 역할과 HBONEztunnel은 노드당 DaemonSet, HBONE은 15008의 HTTP/2 CONNECT mTLS 터널, ambient는 1.24에서 GA01 왜 Ambient mode인가, Istio ambient 개요✓
정상 상태 지연atomai 실험, Istio 1.30.2·EKS 1.36.2·Fortio 1.69.4, 200 QPS, 연결 16개, 60초, 케이스당 12,000건. P50 0.82/2.11/0.86/2.68ms부록 A 실측 비교✓
실험의 한계원시 결과·스크립트 없음, 반복 횟수 미표기. 리소스 절감 수치는 100파드 가정 예산 모델같은 글✓
503 half-open 원인풀 키 IP:Port, ztunnel의 graceful close 부재, IP 재할당의 세 조건. Envoy 로그·pcap·socket 상태로 확인3-1편 503과 Half-open Connection✓
재시도 조건 확장은 완화책EnvoyFilter YAML은 공개되지 않음. 외부 실험의 503이 같은 원인인지는 미확인같은 글, a1?

L7 프록시의 범위와 장애 반경

요청 단위 처리가 필요한 트래픽의 범위와 프록시 하나가 맡는 범위를 함께 봐야 합니다. 동작 원리로 보면 노드 하나의 L7 트래픽을 모두 받는 cilium-envoy는 장애 반경이 더 넓을 수 있습니다. 이는 직접 측정한 결과가 아닙니다. 도식은 HTTP 해석이 필요한 연결을 L7으로 보내는 경계를 보여줍니다.

HTTP를 해석할 필요가 없으면 요청은 ztunnel이나 eBPF에서 끝나고, 필요해지는 순간에만 Envoy로 올라갑니다.
도식 텍스트
  • 요청 — 연결 하나
  • HTTP를 봐야 하나 — L7 규칙 유무
  • L4에서 처리 — ztunnel · eBPF
  • Envoy로 올림 — waypoint · 노드 Envoy
  • L4 기능 — L4 정책 · TCP 메트릭
  • L7 기능 — 라우팅 · L7 정책
  • 아니오
  • 예
근거와 측정 조건
주장수치·조건출처근거
비교표의 배치사이드카 15001/15006, ambient ztunnel·waypoint, Cilium eBPF·노드 Envoy01 L4와 L7✓
Cilium이 Envoy로 보내는 조건L7 규칙이 있는 CiliumNetworkPolicy, Ingress·Gateway API 리스너, CiliumEnvoyConfig, 정책으로 켠 L7 가시성같은 글✓
노드 공유 Envoy의 장애 반경구조에서 이끌어 낸 추정. 잘못된 CiliumEnvoyConfig도 노드 전체에 영향을 줄 가능성같은 글, 04 재시도와 복원력≈

데모와 발표 준비 점검

데모 명령은 노드의 kube-proxy 모드와 Cilium KPR 사용 여부를 확인한 뒤 선택합니다.

명령유효 조건근거
iptables-save | grep KUBE-SVCkube-proxy iptables 모드. KUBE-SERVICES에서 KUBE-SVC-<hash>로 점프하고 엔드포인트별 체인은 KUBE-SEP-<hash>✓ (SEP 이름은 ≈)
nft list table ip kube-proxynftables 모드. map service-ips와 chain services가 보임✓
conntrack -L -d <ClusterIP>kube-proxy 노드에서 DNAT 항목 확인. conntrack-tools 필요. Cilium KPR 환경은 cilium-dbg bpf ct list global≈ / ✓
kubectl -n kube-system exec ds/cilium -- cilium-dbg service listCilium 1.20.4 문서에 그대로 있음✓
  • Istio 1.24 공식 벤치마크, a1의 100파드 예산 모델, 채널팀 자체 측정의 수치를 섞지 않기. MB·Mi 표기는 원문대로 유지
  • 발표 전날 Kubernetes·Cilium·Istio·VPC CNI 릴리스와 패치 버전, KEP-5343 단계 재확인
근거와 측정 조건
주장수치·조건출처근거
명령 유효성위 표의 각 모드 조건. 출력 헤더 ID Frontend Service Type Backendnftables 블로그, Cilium kube-proxy 없는 구성, cilium-dbg bpf ct list✓
섞으면 안 되는 수치1.24 벤치마크, a1 예산 모델 입력, 채널팀 측정은 출처·버전이 다름14, 01 왜 Ambient mode인가, 부록 A✓

참고 자료

나머지 출처는 전체본에 있습니다.

마지막 수정 일자