0. Contents


1. Overview

질문"앱 대신 바깥일(주소 찾기, 재시도, 분산...)을누가, 어디서 해줄 것인가?"1세대앱이 직접라이브러리 내장근무지: 앱 안2세대Pod 안 전담 컨테이너Ambassador — Ch.18근무지: Pod 안3세대노드당 프록시 1개Sidecarless Mesh근무지: 노드다음커널 속으로eBPF근무지: 커널일은 그대로, 근무지만 이사 중
같은 일을 하는 대리인의 근무지 이사: 앱 → Pod → 노드 → 커널

실무에서 자주 듣는 평가

  • 18장에서 Ambassador 패턴을 정리했다
  • 실무에서는 “요즘 이 패턴 잘 안 쓴다"는 말을 자주 듣는다
    • 컨테이너끼리 라이프사이클이 안 맞는다
    • 이제는 메시 + CNI 조합으로 넘어갔다
    • 다음 단계는 커널 아래까지 내려간다

결론 먼저: 물러난 것은 구현 방식

  • 이 포스트에서는 그 말이 정확히 무슨 뜻인지 하나씩 짚어본다
  • 안 쓰이게 된 건 Pod 안에 사이드카 컨테이너를 두는 구현 방식이지 패턴의 아이디어가 아니다
  • “앱은 비즈니스 로직만, 네트워크 잡일은 대리인이"라는 방향은 오히려 더 극단적으로 실현되는 중이다

2. 사이드카 방식의 한계

2.1 라이프사이클 불일치

한집에 사는 두 컨테이너

  • 같은 Pod에 있다는 게 장점만은 아니다
  • 두 컨테이너는 한집에 살지만 서로의 생사를 조율할 방법이 없다
① 시작 순서 문제시간 →Pod 시작 → 메인 앱이 먼저 떴는데 앰배서더가 아직 안 뜸메인 앱앰배서더메인 앱 실행 중Connection refused 💥앰배서더 뜸앱: "localhost:9009로 던질게!"② 종료 순서 문제시간 →Pod 종료 → 앰배서더가 먼저 죽음메인 앱앰배서더메인 앱앰배서더먼저 죽음받아줄 사람이 없음 → 유실 💥앱의 마지막 로그③ Job에서의 악명 높은 문제시간 →배치 Job: 메인 컨테이너는 일 끝내고 종료메인 컨테이너사이드카일하는 중일 끝내고 종료사이드카: "나는 서버니까" 계속 생존→ Job이 영원히 Completed 안 됨 🧟
사이드카 라이프사이클 불일치: 시작 순서, 종료 순서, Job

네이티브 사이드카와 남은 문제

  • Kubernetes는 오랫동안 “A가 준비된 후 B를 시작하라"를 보장하지 않았다
  • 1.28에서 네이티브 사이드카(initContainers + restartPolicy: Always)가 알파로 도입됐다
    • 1.29에서 베타(기본 활성화), 1.33에서 GA가 됐다
    • 순서 문제는 어느 정도 완화됐다
  • 하지만 구조 자체에서 오는 다음 문제는 남는다

2.2 N배의 비용

Pod 1,000개 = 프록시 1,000개

  • 메모리/CPU: 프록시 오버헤드 × 1,000
  • 업그레이드: 프록시 버전 하나 올리려면 1,000개 Pod 전체 재시작
  • 운영 부담: 장애 지점도 1,000개

대표 사례: Istio 클래식(사이드카 모드)

  • 이 비용을 치른 대표 사례다
  • Pod마다 Envoy를 자동 주입하는 방식은 Ambassador 패턴의 대규모 자동화 버전이었다
  • 패턴의 장점과 함께 단점도 N배로 물려받았다

3. 세대 진화 — 프록시의 이사 기록

3.1 3단계 진화 지도

1세대: 앱 안에 라이브러리 내장

  • 앱 + Consul클라이언트 + 재시도로직이 한 덩어리
  • 책 18장 도입부의 “문제 상황” 그 자체

2세대: Ambassador / Sidecar (Ch.18, 책 출간 시점의 답)

  • [앱] + [앰배서더], Pod마다 한 쌍
  • Istio 클래식 = 이 패턴의 자동화

3세대: Sidecarless 메시 + CNI (현재)

  • 프록시를 Pod에서 꺼내 노드 레벨로
    • Istio Ambient Mesh: 노드당 ztunnel 1개 (L4 담당)
      • L7 처리(HTTP 라우팅·정책)는 별도 waypoint 프록시가 맡는다
    • Cilium: CNI 계층에 메시 기능 통합

다음: eBPF (방향)

  • 처리 로직 자체가 커널 속으로

3.2 3세대 — 개인 비서에서 층 안내데스크로

비유로 보는 세대 차이

  • 2세대와 3세대의 차이는 비유로 보면 이해가 쉽다

2세대 = 직원마다 개인 비서 1명

  • 직원(Pod) 1,000명이면 비서(프록시)도 1,000명
  • 월급(리소스)이 2배
  • 직원과 비서의 출퇴근이 안 맞으면 일이 멈춘다(라이프사이클)
  • 비서 재교육(업그레이드)은 전사적 행사다

3세대 = 층마다 안내데스크 1개

  • 층(노드) 단위로 데스크(프록시)를 통합한다
  • 직원이 몇 명이든 데스크는 층 수만큼만 있다
  • 직원의 출퇴근과 무관하게 데스크는 항상 그 자리에 있다
  • 대신 데스크가 문을 닫으면(장애·업그레이드) 그 층 직원 전체가 영향을 받는다
2세대 (Pod마다 사이드카)노드Pod앱프록시Pod앱프록시프록시 수 = Pod 수라이프사이클 문제 × N3세대 (노드당 프록시)노드Pod앱Pod앱Pod앱[ 노드 프록시 × 1 ]라이프사이클 불일치: 사라짐대가: 프록시 하나의 업그레이드·장애가그 노드의 모든 Pod에 영향
2세대 Pod마다 사이드카 vs 3세대 노드당 프록시 1개

프록시 수와 라이프사이클 문제

  • 2세대: 프록시가 Pod 수만큼 늘어나고 라이프사이클 문제도 쌍마다 생긴다
  • 3세대: 노드 프록시로 통합되면서 앱과 프록시의 라이프사이클 불일치는 사라진다
    • 대신 노드 프록시 하나의 업그레이드·장애가 그 노드의 모든 Pod에 영향을 준다

두 가지 대표 구현

Istio Ambient MeshCilium
접근노드마다 L4 프록시(ztunnel) 배치, L7은 별도 waypoint 프록시L3/L4는 프록시 없이 CNI 계층(eBPF)에서 처리, L7 기능(HTTP 정책, Ingress/Gateway)은 노드당 Envoy
비유층마다 안내데스크 신설건물 배선 자체에 자동응답 기능 내장
핵심 기술ztunnel (zero-trust tunnel) + waypointeBPF (+ L7은 Envoy)

Cilium: 배관에 직접 심은 기능

  • Cilium은 여기서 한 발 더 나간다
  • 어차피 네트워크 배관(CNI)을 자기가 다 깔았다
    • 프록시를 따로 세우는 대신 배관 자체에 그 기능을 심어버렸다
    • L3/L4에서는 데스크라는 별도 존재마저 생략한 셈이다
    • 다만 L7 기능은 노드마다 Envoy 프록시를 띄워 처리한다
  • “커널 아래까지 내려간다"는 말이 여기서 나온다

4. CNI의 실체

3세대 이해의 전제

  • 3세대를 이해하려면 CNI가 정확히 무엇인지 알아야 한다
  • 먼저 흔한 오해 하나 — CNI는 프로토콜이 아니다

4.1 프로토콜이 아니라 규격이다

CNI(Container Network Interface)의 정의

  • “컨테이너에 네트워크를 붙이는 프로그램은 이렇게 만들어라” 라는 규격이다
  • USB와 같은 구조다
    • USB는 포트 모양과 신호 방식을 정의한 규격이다
    • 그 규격을 지키면 어떤 마우스든 꽂힌다

CNI 규격 (문서)

  • 네트워크 플러그인은
    • ① 실행 파일(binary)이어야 하고
    • ② ADD/DEL 명령을 받아야 하고
    • ③ 설정과 결과는 JSON으로 주고받아야 한다

규격을 따르는 제품들

  • Calico, Flannel, Cilium, AWS VPC CNI, Weave…

같은 규격이 주는 것: 교체 가능성

  • 규격이 같으니 K8s는 어떤 CNI 플러그인이든 갈아끼울 수 있다
  • 중요한 사실 — CNI는 특정 세대의 기술이 아니라 모든 세대에 항상 존재하는 필수 기반이다
  • CNI 없이는 Pod가 IP조차 받지 못한다

노드 디스크에서 보는 실체

  • 실체는 노드의 디스크에서 직접 확인할 수 있다
# 플러그인 = 그냥 실행 파일
$ ls /opt/cni/bin/
calico  bridge  loopback  host-local  portmap ...

# 설정 = 그냥 JSON
$ cat /etc/cni/net.d/10-calico.conflist

4.2 Pod가 생길 때 실제로 벌어지는 일

상주 데몬이 아닌 실행 파일

  • CNI 플러그인은 상주 데몬이 아니다
  • Pod 생성/삭제 순간에만 호출됐다가 일 끝내고 종료되는 실행 파일이다
kubelet① "Pod 하나 만들어야겠다"런타임② Pod의 빈 네트워크 공간(netns) 생성런타임③ CNI 플러그인 호출CNI_COMMAND=ADD, 설정 JSON을 stdin으로CNI 플러그인④ 플러그인의 실제 작업가상 랜선(veth pair) 생성 — 한쪽은 Pod, 한쪽은 노드IP 할당 (예: 10.244.1.5)라우팅 규칙 추가CNI 플러그인⑤ 결과 JSON 반환 → 종료 (퇴근)Pod⑥ Pod 통신 가능 ✅랜카드도 IP도 없는 깡통 📦플러그인호출 ~ 종료이때만 실행
Pod 생성 시 CNI 플러그인 호출 흐름 (CNI_COMMAND=ADD)

전기기사 비유

  • 새 입주자(Pod)가 오면 관리사무소(kubelet)가 기사(플러그인)를 호출한다
  • 기사는 일을 마치고 돌아간다
    • 콘센트를 뚫고(veth)
    • 계량기 번호를 부여하고(IP)
    • 배전반에 등록한다(라우팅)
  • 상주하지 않고 부를 때만 온다

프로토콜과의 차이

  • 이걸 보면 프로토콜과의 차이가 분명해진다
프로토콜 (TCP, HTTP)CNI
정의하는 것데이터를 주고받는 방법네트워크를 설치하는 프로그램의 규격
동작 시점통신하는 내내Pod 생성/삭제 순간에만
비유전화 통화 예절전화기 설치 기사 자격 규정

공사 담당과 통화 담당

  • CNI가 배선을 깔고 나면, 그 위로 흐르는 트래픽은 평범한 TCP/IP다
  • CNI는 공사 담당이지 통화 담당이 아니다

4.3 “CNI 레이어"라는 관용어

모순처럼 보이는 지점

  • 설치 기사는 퇴근한다
  • 그런데 “Cilium은 CNI 레이어에서 트래픽을 처리한다"는 말은 무엇인가?

답: 기반시설 전체를 가리키는 관용 표현

  • “CNI 레이어"는 공식 용어가 아니라 관용 표현이다
  • 가리키는 것은 규격이 아니라 “CNI 제품이 깔아놓고 관리하는 네트워크 기반시설 전체” 다
  • “Cilium을 설치한다"는 것은 실제로 부품 3개를 배치하는 일이다
"Cilium" 설치 시 실제 배치되는 것노드유저 공간① CNI 플러그인 바이너리/opt/cni/bin/cilium-cni→ 규격 담당. Pod 생성 시만 호출, 퇴근 ✅② cilium-agent (데몬)노드마다 상주→ 정책 관리, eBPF 프로그램 로드/갱신커널③ eBPF 프로그램 — 커널 안에 상주 ⭐→ 흐르는 트래픽을 실시간 처리(로드밸런싱, 암호화, 관측)로드/갱신
"Cilium" 설치 시 실제 배치되는 부품 3개

트래픽 처리 담당: ③ eBPF 프로그램

  • 트래픽을 실제로 처리하는 것은 ③이다
  • 설치 기사(①)가 공사하러 온 김에 벽 안에 스마트 배전 시스템(③)을 심고, 상주 관리인(②)을 배치하고 간 구조다
  • 용어를 분리하면 모순이 사라진다
용어의미동작 시점
CNI (규격)문서상의 인터페이스 정의—
CNI 플러그인규격을 따르는 실행 파일Pod 생성/삭제 순간
“CNI 레이어” (관용어)CNI 제품이 관리하는 기반시설 전체 (veth + 라우팅 + eBPF + 에이전트)24시간 상시
Pod 생성Pod 삭제CNI 플러그인규격을 따르는 실행 파일프로토콜 (TCP, HTTP)데이터를 주고받는 방법"CNI 레이어" (관용어)veth + 라우팅 + eBPF + 에이전트ADDDELPod 생성/삭제 순간에만통신하는 내내24시간 상시시간 →
동작 시점 비교: CNI 플러그인 · 프로토콜 · CNI 레이어

제품별로 얹은 기능

  • 같은 규격에 꽂히는 플러그인이라도 제품별로 얹은 것이 다르다
    • Flannel: 규격 최소한(IP 붙이기)만
    • Calico: + NetworkPolicy
    • Cilium: + 메시 기능까지

“메시 + CNI"의 뜻

  • CNI를 새로 도입한다는 뜻이 아니다
  • 원래 있던 배관 계층에 메시 기능을 통합하는 방향을 뜻한다

5. eBPF — 커널 아래로

“커널 아래까지"의 정체

  • “다음 단계는 커널 아래까지 내려간다"의 정체가 eBPF다

출발점: 커널을 지나는 모든 패킷

  • 출발점은 단순한 사실이다 — 어차피 모든 패킷은 커널을 통과한다
  • 그렇다면 유저 공간의 프록시로 패킷을 올렸다 내렸다 왕복시킬 게 아니다
    • 커널 안에서 바로 처리하면 된다
앱(유저 공간)커널(네트워크 스택)하드웨어사이드카 경로 (왕복 지옥)앱 → 커널 → 프록시(유저 공간) → 커널 → 네트워크앱프록시네트워크↑ 매 요청마다 컨텍스트 스위칭 비용eBPF 경로앱 → 커널 (여기서 처리 끝) → 네트워크앱🎯 eBPF 프로그램이 여기서트래픽을 직접 처리로드밸런싱, 라우팅,관측, 보안 정책네트워크
사이드카 경로(왕복) vs eBPF 경로(커널에서 처리)

eBPF와 Cilium

  • eBPF는 커널을 재컴파일하지 않고도 커널 안에서 검증된 프로그램을 실행하게 해주는 기술이다
  • Cilium이 이것의 대표 주자다
    • CNI 플러그인이면서 eBPF로 로드밸런싱·네트워크 정책·관측(Hubble)까지 커널 레벨에서 해결한다
  • “메시 + CNI + 커널"이라는 흐름이 정확히 Cilium이 걷는 길이다

6. 정리 — 패턴은 죽지 않았다

하나의 질문, 바뀐 근무지

  • 처음의 질문으로 돌아가자 — “앱 대신 바깥일을 누가 해줄 것인가”
  • Ambassador 패턴과 그 후계자들은 전부 이 하나의 질문에 대한 답이다
  • 달라진 것은 답변자의 근무지뿐이다

질문: 앱 대신 바깥일 해줄 사람 구함

세대답변자근무지와 결과
1세대없음. 앱이 직접책임 2개, 재사용 불가
2세대개인 비서 (Ambassador)Pod 안. 비서가 Pod 수만큼 필요
3세대층 안내데스크 (ztunnel)노드당 1개. 라이프사이클 불일치는 해소, 대신 장애·업그레이드 영향이 노드 단위
다음배선 내장 (Cilium/eBPF)커널 속. 대리인의 존재조차 안 보임

Ambassador와 후계자 비교

Ambassador (2세대)ztunnel / eBPF (3세대~)
하는 일앱 대신 외부 통신 처리완전히 동일
사는 곳Pod 안 (앱과 한집)노드 / 커널 (앱 밖)
개수Pod마다 1개노드마다 1개 (또는 0개처럼 보임)
앱 YAML직접 넣으면 컨테이너 추가 필요 (Istio 같은 자동 주입이면 변경 없음)건드릴 필요 없음

18장을 공부한 가치

  • 그래서 18장을 공부한 가치는 사라지지 않는다

원리가 이어진다

  • “앱은 비즈니스 로직만, 네트워크는 인프라가"라는 방향은 세대가 바뀌어도 그대로다
  • Ambassador를 이해하고 있으면 바로 이해된다
    • Ambient Mesh는 “같은 일을 노드에서 하는 것”
    • Cilium은 “같은 일을 커널에서 하는 것”

레거시가 남아 있다

  • 기존 클러스터에는 여전히 사이드카 방식이 대량으로 돌아가고 있다
  • Istio 클래식 환경을 트러블슈팅하려면 결국 이 패턴을 알아야 한다

설명할 때 깊이가 달라진다

  • “Ambassador 패턴 아세요?“라는 질문에 패턴 설명만 하는 것보다 이어서 답할 수 있으면 훨씬 낫다
    • “다만 라이프사이클 불일치와 Pod당 프록시 비용 때문에 요즘은 Ambient Mesh나 eBPF 기반으로 넘어가는 추세”

대리인은 옆방(Pod) → 관리실(노드) → 건물 배관(커널) 속으로 점점 깊이 숨어들었다. 이제 앱은 대리인의 존재조차 모른다. 패턴이 죽은 것이 아니라, 너무 성공해서 보이지 않게 된 것이다.