Cilium이 eBPF로 kube-proxy를 통째로 바꾸는 법
한 클러스터의 노드가 2000개였다. Service가 만 개 넘게 있었고, kube-proxy가 각 노드에 만든 iptables 규칙이 수십만 줄이었다. 패킷 하나를 라우팅할 때마다 커널이 그 규칙을 선형으로 훑었다 — 지연이 눈에 띄게 커졌다. 팀은 Cilium으로 전환했다. kube-proxy를 끄고, eBPF가 라우팅을 직접 처리하게 했다. 규칙이 해시 테이블로 바뀌어 거의 일정한 속도로 떨어졌다.
이 글이 푸는 것은: Cilium이 eBPF로 왜 iptables/kube-proxy를 대체할 수 있는가, 그리고 그것이 단순히 "빠른 CNI"가 아니라 근본적으로 다른 데이터플레인인 이유다.
왜 iptables가 규모에서 무너지나 — 선형 탐색의 한계
Cilium이 왜 필요한지 이해하려면, 먼저 iptables 기반 kube-proxy가 어디서 한계에 부딪히는지 봐야 한다. 01장에서 kube-proxy(iptables 모드)가 Service→Pod 매핑을 iptables 규칙 체인으로 표현한다고 했다. Service마다 여러 규칙이, 백엔드 Pod마다 추가 규칙이. Service 1만 개, 백엔드 평균 5개면 규칙이 수만~수십만 줄.
패킷이 올 때마다 커널이 이 체인을 처음부터 훑는다 — 선형 탐색(O(n)). 규칙이 늘수록 패킷당 처리 시간이 늘어난다. IPVS 모드는 해시로 이를 줄이지만, 여전히 별도 레이어(커널 netfilter 위)다.
| iptables(kube-proxy) | IPVS | eBPF(Cilium) | |
|---|---|---|---|
| 자료구조 | 선형 규칙 체인 | 해시 테이블 | 해시 맵(커널 안) |
| 조회 복잡도 | O(n) | O(1) | O(1) |
| 레이어 | netfilter(별도) | netfilter 위 | 커널 스택에 통합 |
| 규모 대응 | 느려짐 | 좋음 | 가장 좋음 |
핵심 통찰: 이건 데이터 구조의 문제다. 선형 체인은 규모에서 필연적으로 느려진다. 해시로 바꾸면 규모에 거의 무관해진다. 문제는 "어떻게 해시를 커널 패킷 처리 경로에 끼워넣느냐"인데, 그 답이 eBPF다.
커널 안에서 처리하면 빠른데, 어떻게? — eBPF
패킷 처리를 빠르게 하려면 커널 안에서 결정해야 한다 — 사용자 공간(프록시, 사이드카)으로 패킷을 올렸다 내렸다 하면 컨텍스트 전환 비용이 든다. 하지만 커널 소스를 고치거나 커널 모듈을 올리는 건 위험하다(한 번의 버그가 시스템 패닉). 매번 커널을 재컴파일하는 것도 현실적이지 않다.
리눅스는 이 딜레마를 eBPF(extended Berkeley Packet Filter)로 푼다. eBPF는 런타임에 커널 안에 로드되어 실행되는 작은 프로그램이다. 커널을 고치거나 모듈을 올리지 않고, 커널의 특정 지점(네트워크 패킷 처리, 시스템콜 등)에 후크를 걸어 동작한다. (eBPF 소개)
flowchart LR
APP["사용자 공간<br/>(cilium-agent)"] -->|"eBPF 프로그램 로드"| K["커널"]
K --> H1["네트워크 후크<br/>(패킷 처리)"]
K --> H2["시스템콜 후크"]
H1 -->|"패킷을 eBPF로 처리"| FAST["해시 테이블 조회<br/>(iptables 선형 아님)"]
Cilium은 이 eBPF를 Kubernetes 네트워크 데이터플레인으로 쓴다 — Service 매핑을 해시 맵에 저장하고, 패킷이 오면 eBPF가 해시 조회(O(1))로 목적지를 결정. Service가 1만 개든 10만 개든 조회 시간이 거의 일정하다. 앞 절의 iptables 선형 탐색 문제를 데이터 구조 차원에서 해결하는 것이다. (Cilium docs - Architecture)
왜 "안전"한가 — eBPF 검증기
eBPF 프로그램이 커널에서 실행되면 시스템 전체를 위험에 빠뜨릴 수 있다. 그래서 리눅스는 로드 전 검증기(verifier)를 거친다 — 프로그램이 (1) 정해진 시간 안에 종료되는가(루프 제한), (2) 커널 메모리를 안전하게만 접근하는가, (3) 허용된 후크에만 매달리는가. 검증을 통과한 프로그램만 커널에 적재된다. 이것이 "커널 모듈과 달리 안전"한 이유 — 모듈은 커널 전체에 접근 가능해 한 번의 버그가 패닉을 일으키지만, eBPF는 샌드박스 안에서 동작한다.
이 모든 정확한 동작(eBPF 검증기/후크 종류)은 eBPF docs와 커널 문서가 1차 출처. 세부 버전 의존성이 있어 실측 권장.
패킷이 커널을 지나는 여러 후크 — XDP와 TC
패킷이 커널 네트워크 스택을 통과할 때 여러 후크 지점이 있다. Cilium이 쓰는 주요 두 곳:
| 후크 | 위치 | 속도 | 할 수 있는 일 |
|---|---|---|---|
| XDP(eXpress Data Path) | NIC 드라이버 안, 가장 빠름 | 최고 | 패킷 드롭/리다이렉트(DDoS 방어 등) |
| TC(Traffic Control) | 커널 네트워크 스택 진입부 | 높음 | Service 라우팅, 정책, 메트릭 |
XDP는 패킷이 아직 커널 스택에 들어오기 전*에 처리 — 극단적 처리량이 필요한 작업(대규모 DDoS 드롭)에 적합. TC는 스택 진입부에서 Service 라우팅·정책 같은 복잡한 결정을. Cilium은 이 둘을 목적에 따라 조합 — DDoS 방어 규칙은 XDP로(빠른 드롭), Service 라우팅은 TC로. 패킷이 커널 스택을 다 지나기 *전에 처리하므로 사용자 공간 프록시(사이드카)보다 빠르다. 이것이 "eBPF는 한 곳"이 아니라 여러 후크 지점의 조합이라는 것을 보여준다.
Cilium이 kube-proxy를 대체한다 — 무슨 뜻인가
01장에서 kube-proxy가 Service 라우팅을 iptables/IPVS로 구현한다고 했다. Cilium은 이것을 eBPF로 통째로 대체할 수 있다(kubeProxyReplacement). (Cilium docs - kube-proxy replacement)
flowchart TD
P["패킷: 목적지=Service ClusterIP"]
P -. 전통 .-> KP["kube-proxy<br/>iptables 규칙(선형)"]
KP --> DNAT1["DNAT → Pod IP"]
P -. Cilium .-> EBPF["eBPF 프로그램<br/>(커널 안, 해시 조회)"]
EBPF --> DNAT2["DNAT → Pod IP (빠름)"]
차이의 핵심: kube-proxy는 별도 프로세스가 규칙을 만들고 커널이 그것을 처리. Cilium은 eBPF가 커널의 패킷 처리 경로에 직접 끼어들어 처리. 중간 레이어(iptables 규칙 평가)를 없앤다. 그래서 Cilium 모드에서는 kube-proxy DaemonSet을 아예 안 깔거나 비활성화한다.
두 모드 — 점진적 도입 vs 전체 대체
- kube-proxy와 함께(kubeProxyReplacement=false): Cilium이 CNI(Pod 네트워크)만 하고, Service는 기존 kube-proxy가 처리. 점진적 도입에 적합.
- kubeProxyReplacement(전체 대체): Cilium이 Service 라우팅까지 eBPF로. kube-proxy 제거. 최대 성능.
# Cilium 설치 시 모드 지정
cilium install --set kubeProxyReplacement=true
정확한 설치 파라미터/버전은 Cilium docs에서 실측. 1.36 호환 Cilium 버전 명시.
공존 모드가 단순히 "덜 진보"가 아니다. 한 번에 kube-proxy를 끄면 뭔가 잘못됐을 때 전체 Service 통신이 깨진다. 공존 모드로 먼저 Cilium CNI를 검증한 뒤 전체 대체로 전환하는 단계적 접근이 대규모 프로덕션의 정석이다.
정체성 기반 보안 — IP가 아니라 신원으로
IP 기반 정책에는 근본 문제가 있다 — Pod가 재생성되면 IP가 바뀐다. IP 기반 정책은 그 변화를 따라가야 한다. Cilium은 이 문제를 정체성(identity) 기반 정책으로 푼다: 일반 NetworkPolicy가 IP/라벨 기반인 반면, Cilium은 각 Pod에 Cilium identity(숫자)를 부여하고 eBPF가 패킷에 붙은 identity로 정책을 평가한다. (Cilium docs - identity-based policy)
왜 유용한가? IP는 Pod 재생성 시 바뀐다. IP 기반 정책은 IP 변화를 따라가야 한다. identity는 Pod의 라벨에서 파생되어 IP가 바뀌어도 같은 identity다. 그래서 정책이 "IP가 뭔가"가 아니라 "이 Pod는 web 서비스인가"로 평가된다 — 더 안정적. 이것이 03-k8s-security 네트워크 보안 글에서 보는 "메시 신원 기반 정책"의 eBPF 버전이다.
Hubble — eBPF 기반 가시성
NetworkPolicy가 트래픽을 막고 있는지 디버깅하려면 "누가 누구와 통신하나"를 봐야 하는데, iptables 기반 CNI는 이걸 내기 어렵다 — 로그를 일일이 뒤져야 한다. Cilium은 Hubble로 이 가시성을 추가 프로브 없이 제공한다. eBPF가 이미 모든 패킷을 커널 단에서 처리하므로, 그 흐름(어떤 Pod가 어느 Pod로, 어떤 포트로 통신)을 그대로 노출한다. (Cilium docs - Hubble)
cilium hubble observe # 실시간 플로우
Hubble은 "누가 누구와 통신하는가"를 즉시 보여준다. NetworkPolicy가 트래픽을 막고 있는지 디버깅할 때 결정적 — "이 패킷이 정책에 막혔다"를 실시간으로 본다. iptables 기반 CNI는 이 정도 가시성을 내기 어렵다(로그를 일일이 뒤져야). Hubble UI로 플로우를 시각화하기도 한다.
conntrack까지 eBPF로 — 규모의 마지막 병목
kube-proxy 대체 외에 Cilium이 eBPF로 또 하나 대체하는 것: conntrack(연결 추적). 리눅스 conntrack 테이블이 대규모에서 병목인데, Cilium은 eBPF 기반 conntrack으로 이것도 대체한다 — 더 큰 테이블, 더 빠른 조회.
이게 왜 중요한가. iptables 기반 kube-proxy + 커널 conntrack의 조합이 대규모(만 Service, 수백만 연결)에서 무너진다. Cilium은 이 두 병목을 eBPF 해시 맵으로 동시에 해결한다. 단일 병목 교체가 아니라 전체 경로 최적화. 이것이 "kube-proxy만 대체"가 아니라 전체 데이터플레인을 eBPF로 옮기는 Cilium의 야심이다.
eBPF 검증기의 제약 — 무엇을 못 하는가
검증기가 안전을 보장하지만 제약도 만든다. eBPF 프로그램은:
- 루프 제한: 무한 루프 방지를 위해 제한된 횟수만(또는 bounded loop만).
- 명령어 수 상한: 프로그램 크기에 제한. 복잡한 로직을 한 프로그램에 못 넣음.
- 커널 버전 의존: 후크 지점/헬퍼 함수가 커널 버전마다 다름. 최신 기능은 최신 커널 필요.
이 제약이 "eBPF로 뭐든 된다"가 거짓인 이유다. 복잡한 애플리케이션 로직은 여전히 사용자 공간이 맞고, eBPF는 데이터플레인 패킷 처리에 특화. Cilium도 L7 고급 로직은 Envoy(사용자 공간)에 맡긴다 — eBPF가 모든 걸 대체하는 건 아니다.
데이터플레인 통합 — Cilium이 하나의 eBPF 층으로 모으는 것
패킷이 CNI → kube-proxy(iptables) → 사이드카(메시)를 차례로 거치면 각 층마다 오버헤드가 누적된다. Cilium은 이 여러 층을 하나로 통합한다 — 과거엔 CNI(kube-proxy), 정책(iptables), 관측(별도 프로브), 메시(사이드카)가 각각 다른 층이었는데, 이 모든 것을 하나의 eBPF 데이터플레인으로 모은다:
flowchart TD
EBPF["eBPF 단일 데이터플레인"] --> R1["CNI "]
EBPF --> R2["Service 라우팅 (kube-proxy 대체)"]
EBPF --> R3["정책 (NetworkPolicy + identity)"]
EBPF --> R4["관측 (Hubble)"]
EBPF --> R5["메시 "]
이 통합이 왜 가치인가? 각 층이 독립이면 — CNI가 패킷을 라우팅하고, kube-proxy가 또 iptables를 깔고, 사이드카가 또 가로채고... 패킷이 여러 층을 거쳐 오버헤드가 누적된다. Cilium은 커널의 한 지점에서 이 모든 결정을 한 번에 — 라우팅 + 정책 + 관측을 한 번의 eBPF 평가로. 이것이 "여러 도구를 얹는" 접근 대비 Cilium의 구조적 이점이다.
단, 이 통합은 Cilium 생태계 전 의존을 의미 — 모든 기능이 Cilium에 집중되면 vendor lock-in 우려. 또한 L7 고급 기능은 여전히 Envoy(사용자 공간)가 필요. Cilium은 12장에서 다룰 "사이드카 없는 서비스 메시"의 기반이기도 하다 — eBPF가 커널 단에서 mTLS·트래픽 제어를 끼워 넣으면 Envoy 사이드카 없이 메시 기능을 제공한다. (Cilium Service Mesh)
Calico vs Cilium — 언제 무엇을
| Calico | Cilium | |
|---|---|---|
| 데이터플레인 | iptables/eBPF(선택) | eBPF(기본) |
| Service 라우팅 | kube-proxy 유지 또는 eBPF | eBPF(kube-proxy 대체 가능) |
| 정책 엔진 | 강력(CRD, L7) | 강력(CRD, L7, +identity 기반) |
| 가시성 | 흔히 FlowGen/로그 | Hubble(실시간 eBPF 플로우) |
| 사이드카 메시 | 별도 | eBPF 기반 사이드카리스 |
선택은: 대규모(수천 Service)·고성능·가시성 중시 → Cilium. 단순/검증된 온프렘 BGP → Calico. 둘 다 강력하며 정책 엔진도 갖춤. 조직 숙련도와 환경(클라우드/온프렘)이 결정한다.
직접 확인하기 (Cilium 클러스터 필요)
Cilium 테스트는
disableDefaultCNI: truekind config + Cilium 설치.k8s-verify스킬 참조.
cilium status # Cilium 상태
cilium config | grep kube-proxy-replacement
cilium hubble observe # 실시간 플로우
확인할 것: kubeProxyReplacement 모드 여부, Hubble이 Pod 간 통신 플로우를 실시간으로 보여줌.
흔히 묻는 것, 흔히 틀리는 것
| 오해 | 정정 |
|---|---|
| "Cilium은 그냥 빠른 Calico다" | 다름. 데이터플레인(eBPF)과 kube-proxy 대체라 근본 다른 접근 |
| "eBPF는 커널 모듈이다" | 런타임 로드되는 커널 내 안전 프로그램(검증기 통과). 모듈(재부팅/패닉 위험)과 다름 |
| "Cilium 쓰면 kube-proxy가 자동으로 없어진다" | 모드에 따라. kubeProxyReplacement=true여야 대체 |
| "Hubble은 별도 설치하면 부하가 크다" | eBPF가 커널 단에서 이미 보는 것을 노출. 추가 프로브 부하 작음 |
| "Cilium 정책은 IP 기반이다" | identity 기반(라벨→identity). IP 변화에 강함 |
| "iptables가 항상 느리다" | 소규모에선 차이 작음. 규모(수만 규칙)에서 벌어짐 |
| "eBPF가 모든 걸 대체한다" | L7 고급 로직은 여전히 Envoy(사용자 공간). 데이터플레인에 특화 |
요약 — 이 글의 결론
- iptables 선형 체인(O(n))이 규모에서 무너진다 — Service 수만 개면 지연 폭증. 이건 데이터 구조 문제라 해시로 바꾸면 풀린다.
- eBPF가 검증기를 거쳐 커널 안에서 안전하게 실행되는 작은 프로그램. Cilium이 그것을 Kubernetes 네트워크 데이터플레인으로 써서 해시 맵(O(1))으로 Service 라우팅을 처리. 커널 모듈(패닉 위험)과 달리 샌드박스.
- Cilium은 kube-proxy를 통째로 대체(
kubeProxyReplacement). Service 라우팅이 iptables에서 eBPF로. 단순히 빠른 CNI가 아니라 근본 다른 데이터플레인. - conntrack까지 eBPF로 — 두 병목(kube-proxy + conntrack)을 동시에 해결. 전체 데이터플레인 통합이 Cilium의 야심.
- 정체성(identity) 기반 정책이 IP 기반 NetworkPolicy의 한계(재생성 시 IP 변화)를 넘음 — 라벨→identity로 안정적 평가.
- Hubble이 eBPF 기반 실시간 가시성 — NetworkPolicy 디버깅에 결정적.
- eBPF에도 제약 — 루프·명령어 수·커널 버전. L7 고급은 Envoy(사용자 공간)가 여전히 필요. "eBPF가 모든 걸 대체"는 거짓.
- Calico vs Cilium은 "검증된 온프렘 BGP(Calico)" vs "eBPF 고성능/가시성/identity(Cilium)".
생각해 볼 문제
- kube-proxy를 eBPF로 대체하면 얻는 것과 잃는 것(trade-off)을 각각 말하라.
- iptables 선형 탐색이 규모에 따라 느려지는 이유를 자료구조 관점에서 설명하라. IPVS는 왜 덜 느린가?
- eBPF 검증기가 "안전"을 보장하는 세 가지 조건은? 커널 모듈과의 차이는?
- Cilium identity 기반 정책이 IP 기반보다 안정적인 이유를, Pod 재생성 시나리오로.
- Hubble로 NetworkPolicy가 트래픽을 막고 있는지 확인하는 과정을 시나리오로 그려라.
- Cilium을 kube-proxy 대체 없이(kubeProxyReplacement=false) 쓰면 어떤 장단점인가?
- eBPF가 "커널 모듈이 아니다"라는 점이 운영상 갖는 의미는? (재부팅, 커널 버전)
- Calico와 Cilium 사이에서 대규모 클라우드 클러스터를 골라야 한다면, 근거를 세워 설명하라.
참고
- Cilium docs - Architecture / eBPF - 접근 2026-07-13
- Cilium docs - kube-proxy replacement - 접근 2026-07-13
- Cilium docs - Hubble - 접근 2026-07-13
- Cilium docs - identity-based policy - 접근 2026-07-13
- Cilium docs - datapath modes - 접근 2026-07-13
- Cilium Service Mesh - 접근 2026-07-13
- eBPF 소개 - ebpf.io - 접근 2026-07-13 (검증기, 후크)
'Tech Artifacts > K8s Networking' 카테고리의 다른 글
| K8s Networking - 07. calico advanced-policy (0) | 2026.07.14 |
|---|---|
| K8s Networking - 06. network-policy (0) | 2026.07.14 |
| K8s Networking - 04. calico (1) | 2026.07.14 |
| K8s Networking - 03. cni model (0) | 2026.07.14 |
| K8s Networking - 02. coredns (0) | 2026.07.14 |
