Cilium + Hubble로 사이드카 없이 Kubernetes 네트워킹 구성하기 — iptables에서 eBPF 데이터패스로
이 글은 Kubernetes 클러스터를 운영 중이거나 도입을 검토 중인 개발자를 대상으로 합니다. kube-proxy나 CNI가 낯선 분이라면, 쿠버네티스 네트워킹 기초 문서를 먼저 보시면 읽기 한결 수월합니다.
솔직히 고백하면, 저도 처음엔 "사이드카 없는 서비스 메시"라는 말을 들었을 때 마케팅 문구쯤으로 여겼습니다. Istio를 도입하면서 pod마다 Envoy 컨테이너가 붙는 걸 당연하게 받아들였고, 그게 서비스 메시의 본질이라고 생각했거든요. 그런데 실제 클러스터에서 500개 pod가 뜰 때마다 500개의 사이드카가 함께 뜨고, pod 하나당 약 50~100MB씩 메모리를 잡아먹는 걸 직접 보고 나서야 다른 방법을 찾게 됐습니다.
Cilium은 그 "다른 방법"입니다. Linux 커널 안에서 동작하는 eBPF 기술을 활용해 네트워크 정책, 로드밸런싱, L7 트래픽 제어를 pod 밖에서 처리합니다. kube-proxy가 관리하던 iptables 규칙 수천 개는 eBPF 해시맵으로 대체되고, Istio가 각 pod에 주입하던 프록시는 노드당 하나의 공유 Envoy로 통합됩니다. 이 글에서는 iptables 기반 클러스터에서 eBPF 데이터패스로 전환하는 과정과, Hubble로 코드 한 줄 수정 없이 전체 네트워크 흐름을 들여다보는 방법을 다룹니다.
2025년 현재 GKE Autopilot의 기본 CNI, AKS의 공식 통합 옵션으로 Cilium이 채택됐고, CNCF Graduated 프로젝트가 됐습니다. "모험적 선택"에서 "업계 표준"으로 자리잡은 만큼, 이제는 어떻게 동작하고 어디서 주의해야 하는지를 제대로 이해할 필요가 있습니다.
핵심 개념
iptables의 한계와 eBPF가 해결하는 문제
kube-proxy가 서비스 라우팅을 처리하는 방식을 한번 생각해보겠습니다. Service가 하나 추가될 때마다 iptables 규칙이 수십 개씩 추가되고, 패킷이 들어오면 이 규칙들을 처음부터 순차적으로 탐색합니다. 클러스터에 서비스가 100개면 괜찮지만, 수천 개가 되면 패킷마다 수만 개의 규칙을 훑어야 합니다. O(n) 복잡도가 실제로 체감되는 순간이죠.
eBPF(Extended Berkeley Packet Filter)는 이 문제를 완전히 다른 방식으로 접근합니다. 커널 소스코드를 수정하거나 모듈을 추가하지 않고도, 커널 내부에서 샌드박스 프로그램을 실행할 수 있습니다. 서비스 라우팅은 해시맵 기반 O(1) 룩업으로 처리합니다. 그리고 eBPF의 Socket LB(소켓 레벨 로드밸런싱) 덕분에 같은 노드의 서비스끼리는 패킷이 네트워크 스택을 타기 전에 소켓 레벨에서 가로채져, 네트워크 홉 자체가 사라집니다.
eBPF 검증기: 커널에 로드되는 eBPF 프로그램은 커널 내장 검증기(verifier)를 통과해야만 실행됩니다. 무한루프나 잘못된 메모리 접근이 불가능하도록 정적 분석을 수행하기 때문에, 커널 크래시 없이 안전하게 동작합니다.
Cilium의 아키텍처 — 사이드카 없이 L7까지 처리하는 방법
eBPF는 패킷 레벨에서 동작하는데, L7 파싱은 어떻게 하는 걸까요? 처음엔 좀 의아했습니다. 답은 레이어 분리에 있습니다.
| 레이어 | 처리 주체 | 위치 |
|---|---|---|
| L3/L4 (IP, TCP/UDP) | eBPF 프로그램 | 커널 직접 |
| L7 (HTTP, gRPC, Kafka) | Envoy 프록시 | 노드당 DaemonSet |
| 네트워크 정책 집행 | eBPF (암호학적 ID 기반) | 커널 직접 |
L7 정책이 필요한 경우, Cilium은 노드당 하나의 Envoy 인스턴스(DaemonSet)로 해당 트래픽을 투명하게 리디렉션합니다. pod마다 사이드카를 붙이는 게 아니라, 노드 하나에 프록시 하나를 두는 방식이죠. 1,000개 pod가 있어도 Envoy는 노드 수만큼만 존재합니다.
비슷한 방향으로 가고 있는 Istio Ambient Mode도 사이드카를 없애는 접근이지만, Cilium은 eBPF를 네트워크 데이터패스 자체로 활용한다는 점에서 차이가 있습니다. Ambient는 Istio의 제어 플레인 생태계를 유지하면서 사이드카만 걷어낸 구조고, Cilium은 CNI부터 서비스 메시까지 eBPF 중심으로 새로 설계된 구조입니다. 어느 쪽이 낫다기보다는 출발점이 다릅니다.
한 가지 더 짚고 넘어가면, Cilium의 네트워크 정책은 IP 주소가 아닌 암호학적 ID를 기반으로 동작합니다. pod의 Kubernetes 레이블로부터 ID가 생성되고, eBPF 프로그램이 이 ID로 정책을 커널에서 직접 집행합니다. pod가 재시작되면 IP는 바뀌지만 레이블은 그대로이기 때문에, ID 기반 정책은 IP 변경에 영향받지 않습니다. 레이블이 바뀌면 ID도 바뀌고, 정책도 즉시 반영됩니다.
Hubble — 코드 수정 없이 전체 트래픽을 보는 방법
Hubble은 Cilium 위에 구축된 네트워크 관찰가능성 레이어입니다. eBPF 레벨에서 흐름(flow)을 캡처하기 때문에 애플리케이션 코드나 사이드카가 전혀 필요 없습니다.
Hubble Agent (각 노드)
│ eBPF flow 이벤트 수집
↓
Hubble Relay (클러스터 집계, gRPC 스트리밍)
│
↓
Hubble CLI / Hubble UI (시각화)각 노드의 Hubble Agent는 eBPF 이벤트를 수집하고, Hubble Relay가 gRPC 기반 스트리밍으로 이를 클러스터 단위로 집계합니다. CLI나 UI는 이 Relay에 연결해 전체 클러스터 흐름을 단일 뷰로 조회합니다.
Hubble이 보여주는 것: 서비스 간 L4/L7 트래픽 흐름, 드롭된 패킷과 그 이유(
policy-denied,ct-map-insertion-failed등), DNS 쿼리/응답, HTTP 요청 메서드/경로/상태코드. 이 모든 것을 애플리케이션 레벨에서 아무것도 건드리지 않고 볼 수 있습니다.
Hubble의 데이터 모델은 크게 세 가지입니다. flow(개별 패킷 이벤트), verdict(허용/차단 판정), policy 이벤트(정책 변경 감지). 네트워크 문제를 디버깅할 때 이 세 가지를 조합하면, 어떤 트래픽이 어떤 정책에 의해 왜 차단됐는지를 구조화된 이벤트로 바로 확인할 수 있습니다.
실전 적용
아래 예시 1~3은 독립된 스니펫이 아니라 클러스터 구성 → Hubble 활성화 → 정책 적용 순서로 이어집니다. 예시 3을 먼저 적용하려면 예시 1, 2가 완료된 환경이 필요합니다.
예시 1: kube-proxy 없는 클러스터 구성
가장 큰 전환점은 kube-proxy를 완전히 제거하는 것입니다. 기존 클러스터에서 마이그레이션하는 경우라면 기존 연결이 끊길 수 있으므로, 신규 클러스터에서 시작하는 것을 권장합니다.
# kubeadm으로 클러스터 초기화 시 kube-proxy 단계 건너뛰기
kubeadm init --skip-phases=addon/kube-proxy
# Cilium Helm 차트 추가 및 설치
helm repo add cilium https://helm.cilium.io/
helm repo update
# <API_SERVER_IP>는 `kubectl get nodes -o wide`에서 control-plane 노드의 INTERNAL-IP로 확인할 수 있습니다
# kind/minikube 환경이라면 `docker inspect <control-plane-container> | grep IPAddress`로도 확인됩니다
helm install cilium cilium/cilium \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost=<API_SERVER_IP> \
--set k8sServicePort=6443설치 후 cilium status를 실행하면 아래와 비슷한 출력이 나옵니다.
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: disabled
\__/
KubeProxyReplacement: True
Masquerading: BPF (masq)
NodePort: ENABLED (Range: 30000-32767)확인해볼 핵심 항목들입니다.
| 확인 항목 | 정상 상태 |
|---|---|
KubeProxyReplacement |
True |
Cilium |
OK |
NodePort |
ENABLED |
Masquerading |
BPF |
# 내부 네트워크, NodePort, 외부 연결을 종합 검증하는 연결성 테스트
cilium connectivity test예시 2: Hubble 활성화와 실시간 트래픽 분석
Hubble은 Cilium 설치 시 함께 활성화하거나, 이후에 helm upgrade로 추가할 수 있습니다.
# Hubble + Relay + UI 활성화
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
# hubble CLI 포트포워딩 설정
cilium hubble port-forward &
# 실시간 흐름 모니터링
hubble observe --namespace production --follow
# 차단된 트래픽만 필터링 (정책 디버깅에 가장 유용합니다)
hubble observe --verdict DROPPED
# HTTP 레이어 가시성
hubble observe --protocol http --namespace production
# 더 세밀한 HTTP 필터 — 메서드와 경로 조합도 가능합니다
hubble observe --protocol http --http-method POST --namespace production
# 특정 서비스로 향하는 트래픽
hubble observe --to-pod production/backend-api저는 네트워크 정책을 처음 적용할 때 --verdict DROPPED를 가장 많이 썼습니다. 이 명령을 처음 실행했을 때, 어느 서비스에서 어느 서비스로 가는 트래픽이 왜 드롭됐는지가 바로 찍혀 나오는 게 솔직히 신기했습니다. 정책 오탈자 하나로 트래픽이 조용히 사라지는 상황에서 특히 빛을 발합니다.
예시 3: 사이드카 없이 L7 HTTP 정책 적용
아래는 frontend에서 backend-api의 /api/ 경로에 GET 요청만 허용하는 정책입니다. Istio에서라면 VirtualService + AuthorizationPolicy를 조합해야 했을 텐데, CiliumNetworkPolicy 하나로 처리됩니다.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-allow-get-only
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend-api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/.*" # RE2 정규식 문법입니다. Cilium은 glob이 아닌 RE2를 사용합니다이 정책이 적용되면 frontend에서 backend-api:8080/api/*로 오는 POST 요청은 자동으로 차단됩니다. Hubble로 확인하면 드롭 이유(policy-denied)까지 구조화된 이벤트로 볼 수 있습니다.
# 정책 적용 후 Hubble로 즉시 검증
hubble observe \
--namespace production \
--to-pod production/backend-api \
--verdict DROPPED \
--protocol http실제로 POST 요청을 차단했을 때 Hubble 출력은 이런 식으로 나옵니다.
TIMESTAMP SOURCE DESTINATION TYPE VERDICT SUMMARY
May 13 10:24:31.412 production/frontend production/backend-api:8080 http DROPPED HTTP/1.1 POST /api/orders
Reason: policy-denied어느 소스에서, 어떤 메서드로, 왜 차단됐는지가 한 줄에 담깁니다. 이 가시성이 사이드카 없이 나온다는 점이 Cilium을 처음 접했을 때 가장 인상 깊었던 부분입니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 성능 | iptables O(n) → eBPF O(1), CPU 사용량 25~40% 절감, L4 처리 지연 최대 10배 개선 (Cilium 공식 벤치마크 참고) |
| 리소스 절약 | pod마다 사이드카 없음 → pod 밀도 향상, 사이드카 하나당 약 50~100MB 절약 |
| 운영 단순화 | 사이드카 주입·업그레이드·버전 호환 관리 불필요 |
| 통합 관찰가능성 | Hubble로 코드 수정 없이 L4/L7 전 계층 네트워크 흐름 확보 |
| 확장성 | 서비스 수 증가해도 라우팅 성능 선형 유지, GKE에서 65,000 노드 규모 검증 |
| 클라우드 네이티브 | CNCF Graduated, GKE/AKS 공식 기본 CNI로 채택 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 커널 버전 요구 | 전체 기능 스택에 최소 Linux 5.10(LTS) 필요 | 도입 전 노드 커널 버전 일괄 확인 (uname -r) |
| L7 기능 성숙도 | gRPC 로드밸런싱 등 일부 기능이 베타, Linkerd보다 성숙도 낮음 | 프로덕션 전 해당 기능 충분한 검증 |
| L7 활성화 시 성능 | L7 정책·암호화 활성화 시 Istio 대비 일부 벤치마크에서 뒤처짐 | L7이 필수인 경로만 선택적 적용 |
| 운영 전문성 | eBPF 디버깅은 Envoy 로그 보는 것보다 난이도 높음 (bpftool로 eBPF 맵을 직접 덤프해야 할 수도 있습니다) |
Hubble UI, bpftool map dump 활용, 팀 학습 투자 |
| 기존 클러스터 마이그레이션 | kube-proxy와 eBPF 대체 공존 전환 시 기존 연결 끊김 위험 | 신규 클러스터에서 시작 후 점진적 전환 |
| 메모리 상주 | 트래픽 없어도 메모리·CPU 일정 수준 유지 | 리소스 baseline 설계 시 반영 |
bpftool: eBPF 맵과 프로그램을 직접 조회·덤프할 수 있는 커널 내장 디버깅 도구입니다. 위 "운영 전문성" 단점이 실제로 체감되는 순간에 꺼내 쓰는 도구로,
bpftool map dump명령으로 Cilium이 관리하는 서비스 엔드포인트 맵을 직접 확인해볼 수 있습니다.
실무에서 가장 흔한 실수
아래 실수들은 위 단점들에서 직접 파생됩니다. 알고 나면 간단하지만, 모르면 몇 시간을 날릴 수 있습니다.
-
커널 버전 확인을 건너뛰는 것:
uname -r로 노드 커널 버전을 먼저 확인하지 않고 설치했다가 일부 기능이 조용히 비활성화되는 경우가 많습니다. 5.10 미만이면 eBPF Host Routing, Socket LB 등 핵심 기능이 fallback됩니다. 설치는 성공하는데 성능이 예상과 다르다면 커널 버전부터 확인해보시면 좋습니다. -
기존 클러스터에서 kube-proxy를 갑자기 제거하는 것: 운영 중인 클러스터에서 kube-proxy DaemonSet을 삭제하면 기존 iptables 규칙이 남아 충돌합니다. Cilium이
--set kubeProxyReplacement=true로 완전히 준비된 이후에 제거하는 순서가 중요합니다. -
L7 정책을 모든 서비스에 일괄 적용하는 것: L7 정책이 활성화되면 해당 트래픽은 노드의 Envoy를 거치게 됩니다. 저는 성능 민감한 내부 서비스에는 L4 정책만 적용하고, 외부 접점이나 인증이 필요한 서비스에만 L7을 활성화합니다. 처음부터 전체에 L7을 켰다가 지연이 늘어난 뒤에야 되돌리는 케이스를 꽤 봤습니다.
마치며
eBPF는 커널을 재컴파일하지 않고도 네트워킹의 규칙을 바꾸는 기술이고, Cilium + Hubble은 그 힘을 Kubernetes 운영자가 실제로 쓸 수 있는 형태로 만들어준 도구입니다.
처음 도입할 때 "커널 레벨"이라는 말이 주는 부담감이 있습니다. 저도 처음엔 그랬고, 솔직히 마케팅 문구라고 의심했습니다. 그런데 실제로 cilium-cli 하나로 설치하고, hubble observe --verdict DROPPED 명령 하나로 트래픽 드롭 이유를 바로 보는 경험을 하고 나면 그 의심이 사라집니다. "마케팅 문구"가 아니라 실제로 동작하는 것이었습니다. GKE나 AKS를 쓰고 있다면 이미 Cilium이 클러스터 아래에서 동작하고 있을 가능성도 높습니다.
지금 바로 시작해볼 수 있는 3단계입니다.
-
로컬에서 전체 흐름을 먼저 경험해 보시면 좋습니다.
kind나minikube로 로컬 클러스터를 만들고helm install cilium cilium/cilium --set kubeProxyReplacement=true로 설치한 뒤,cilium connectivity test로 정상 동작을 확인해볼 수 있습니다. 운영 환경 접근 없이 전체 플로우를 경험할 수 있습니다. -
Hubble UI가 텍스트 로그와 얼마나 다른지 눈으로 보여줍니다.
helm upgrade로hubble.ui.enabled=true를 추가하고,kubectl port-forward -n kube-system svc/hubble-ui 12000:80으로 브라우저에서 서비스 의존성 그래프를 확인해볼 수 있습니다. -
L7 정책 하나를 테스트 네임스페이스에 적용해보시는 것을 권장합니다. 위 예시의
CiliumNetworkPolicy를 실제로 적용하고, 허용된 요청과 차단된 요청을hubble observe --verdict DROPPED로 비교해보시면 사이드카 없이 L7 정책이 집행되는 과정을 직접 확인할 수 있습니다.
막히는 부분이 생기면 Cilium Slack이나 GitHub Discussions가 활발합니다. 커뮤니티 응답 속도가 빠른 편이라 트러블슈팅할 때 도움받기 수월합니다.
참고 자료
- Cilium 공식 문서 - Service Mesh — Cilium 서비스 메시 전체 기능 레퍼런스
- Cilium 공식 문서 - Kubernetes Without kube-proxy — kube-proxy 없는 클러스터 구성의 공식 설치 가이드
- Cilium kube-proxy Replacement Use Case — 성능 수치 벤치마크 원본 자료
- GitHub - cilium/cilium — 소스코드, 릴리스 노트, 이슈 트래커
- GitHub - cilium/hubble — Hubble CLI 소스 및 릴리스
- How eBPF Streamlines the Service Mesh | The New Stack — eBPF와 서비스 메시 아키텍처의 관계를 설명한 글
- Istio Ambient vs. Cilium 공식 비교 | Istio Blog — Istio Ambient Mode와 Cilium 접근법의 차이를 비교할 때 참고
- Linkerd vs Cilium: Five Key Differences | Buoyant — Linkerd 측 시각에서 쓴 비교글, 반론 포함해서 읽으면 균형 잡힌 시각 얻기 좋음
- Introducing eBPF Host Routing: Azure CNI Powered by Cilium | Microsoft — AKS에서 Cilium 도입 배경과 성능 측정 자료
- Configure Azure CNI Powered by Cilium in AKS | Microsoft Learn — AKS 환경에서 Cilium을 적용하려는 경우 실습 시 참고
- GKE Network Interface: from kubenet to eBPF/Cilium to DRANET | Google Cloud Blog — GKE가 Cilium을 채택한 경위와 향후 방향
- eBPF-Based Network Observability with Cilium Hubble | CloudRaft — Hubble 관찰가능성 레이어를 처음 접할 때 보기 좋은 입문 자료
- Monitor Cilium and Kubernetes with Hubble | Datadog — Hubble과 외부 모니터링 도구를 연동하는 방법이 궁금할 때 참고
- Cilium Hubble Cheatsheet | Isovalent —
hubble observe명령어 옵션을 빠르게 찾아볼 때 유용한 치트시트