eBPF로 코드 한 줄 안 바꾸고 커널까지 들여다보기 — Kubernetes 관측가능성(Observability) 실전 가이드
프로덕션에서 이상한 레이턴시 스파이크가 생겼는데, 로그엔 아무것도 없고 APM은 "뭔가 느림" 수준으로만 찍힐 때가 있습니다. 저도 그 답답함을 꽤 오래 겪었는데요. 결국 문제는 커널 수준에서 일어나고 있었고, 우리 관측 도구들은 거기까지 손이 닿지 않았던 겁니다.
eBPF는 그 답답함을 해소해주는 기술입니다. 커널 소스를 건드리지 않고, 커널 모듈을 새로 올리지 않고도, 애플리케이션 코드를 단 한 줄도 수정하지 않은 채 CPU·메모리·네트워크·시스템 콜을 동시에 들여다볼 수 있습니다. 2025년 기준으로 AWS EKS가 eBPF 기반 Cilium을 기본 네트워킹 플러그인으로 채택했고, CNCF 보고서에 따르면 프로덕션 채택이 전년 대비 300% 성장했을 만큼 이미 주류 기술이 됐습니다.
이 글을 읽고 나면 프로덕션에서 bpftrace를 실행해보거나, Kubernetes 클러스터에 코드 수정 없이 APM을 붙이는 것이 어떤 의미인지 직접 체감해볼 수 있습니다. 다만 솔직히 말씀드리면, 실전 적용 예시는 Kubernetes나 Linux 서버를 다뤄본 경험이 있는 백엔드·인프라 개발자에게 가장 바로 와닿을 내용입니다.
핵심 개념
eBPF가 커널에서 하는 일
eBPF(Extended Berkeley Packet Filter)는 원래 네트워크 패킷 필터링용으로 설계된 BPF를 대폭 확장한 기술입니다. 이름에 "패킷 필터"가 들어있어서 네트워킹 전용 기술처럼 보이지만, 지금은 관측가능성·보안·네트워킹 전 영역에 걸쳐 사용됩니다.
동작 흐름은 이렇습니다:
- 사용자가 eBPF 프로그램을 C 또는 고수준 DSL로 작성합니다
- 커널의 verifier가 해당 프로그램을 정적 분석해서 무한루프나 비정상 메모리 접근을 사전에 차단합니다
- 검증을 통과하면 JIT 컴파일러가 네이티브 기계어로 변환합니다
- 커널 이벤트(시스템 콜, 네트워크 패킷, 함수 진입/반환)에 훅(hook) 형태로 붙어서 실행됩니다
// bpftrace로 openat() 시스템 콜 레이턴시를 측정하는 예시
// 커널 내부를 건드리는 것처럼 보이지만, 안전하게 sandbox된 환경에서 실행됩니다
tracepoint:syscalls:sys_enter_openat
{
@start[tid] = nsecs;
}
tracepoint:syscalls:sys_exit_openat
/@start[tid]/
{
@latency_us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}verifier란? eBPF 프로그램이 커널에 로드되기 전에 커널이 직접 실행하는 안전성 검사기입니다. 정적 분석을 통해 "이 코드를 실행해도 커널이 죽지 않겠다"는 것을 검증하고 나서야 실행을 허가합니다. 완전한 수학적 증명(formal verification)과는 다르지만, 덕분에 eBPF는 커널 모듈보다 훨씬 안전하게 사용할 수 있습니다.
저는 처음에 이 verifier 때문에 eBPF를 너무 무섭게 생각했는데, 막상 써보면 "이 정도 안전장치면 프로덕션에서도 괜찮겠다"는 신뢰가 생깁니다. verifier가 거절하는 코드는 정말로 커널을 위험하게 만들 수 있는 코드들이고, 그 기준 안에서도 관측가능성 목적으로는 충분히 많은 것을 할 수 있습니다.
Zero-instrumentation이 왜 강력한가
기존 관측 방식은 크게 두 가지였습니다. 애플리케이션 코드에 SDK를 심는 방식, 또는 사이드카 컨테이너를 붙이는 방식입니다. 둘 다 코드 수정이나 인프라 변경이 필요하고, 사이드카는 파드마다 추가 리소스를 소비합니다.
eBPF는 커널 수준에서 이벤트를 직접 가로채기 때문에 이 두 가지 부담이 없습니다. HTTP 요청이 들어오면 커널 네트워크 스택을 지나게 되어 있고, 거기서 바로 캡처합니다. 애플리케이션이 Python이든 Go든 JVM이든 상관없습니다.
| 관측 방식 | 코드 수정 | 오버헤드 | 가시성 범위 |
|---|---|---|---|
| SDK 삽입 | 필요 | 중간 | 애플리케이션 레이어 |
| 사이드카 (Envoy 등) | 불필요 | 높음 | L7 트래픽 |
| eBPF | 불필요 | 매우 낮음 (1~3% CPU) | 커널~L7 전체 |
도구 선택 기준 — bpftrace vs Cilium vs Pixie
실전 예시를 보기 전에 "나는 어떤 걸 써야 하나"를 짚고 가는 것이 좋습니다. 세 도구는 겹치는 영역이 있지만 주된 사용 목적이 전혀 다릅니다.
| 도구 | 언제 쓰는가 |
|---|---|
| bpftrace | 특정 서버나 프로세스에서 일회성 디버깅이 필요할 때. 플레임 그래프, 시스템 콜 레이턴시 등 즉석 프로파일링 |
| Cilium + Hubble | Kubernetes 클러스터 전체의 네트워크 트래픽을 상시 관측하고 싶을 때. CNI를 교체할 수 있는 권한이 있을 때 |
| Pixie | 코드 변경 없이 바로 HTTP/gRPC/DB APM을 붙이고 싶을 때. 클러스터에 kubectl 접근만 있으면 됨 |
실전 적용
예시 1: bpftrace로 프로덕션 서버 실시간 프로파일링
언제: 특정 프로세스가 왜 느린지 즉석에서 파헤치고 싶을 때, 클러스터 설치 없이 단일 서버에서 바로 시도해보고 싶을 때.
솔직히 처음엔 "프로덕션에서 이런 걸 돌려도 되나?" 싶었는데, JIT 컴파일된 네이티브 코드로 실행되기 때문에 일반적으로 CPU 오버헤드가 1~3% 수준입니다. bpftrace 특성상 tracepoint 훅이 활성화되는 시점에만 실행되므로, 조용한 서버에서는 사실상 체감하기 어렵습니다.
코드 예시에서 tracepoint를 사용하는 이유가 궁금하실 수 있습니다. kprobe는 커널 내부 함수에 직접 붙는 방식이라 커널 버전마다 함수 이름이 바뀔 수 있습니다. 반면 tracepoint는 커널이 공식적으로 안정된 인터페이스로 제공하는 훅 포인트여서, 버전 간 이식성이 훨씬 높습니다.
# 특정 프로세스의 read() 시스템 콜 레이턴시 분포 확인
# 사용법: sudo bpftrace read_latency.bt $(pgrep nginx)
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read
/@start[tid] && pid == $1/
{
@read_latency_us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}
' $(pgrep nginx)# CPU 플레임 그래프 수집 — 어디서 CPU를 가장 많이 쓰는지 한눈에
# ustack은 사용자 공간 콜스택, kstack으로 바꾸면 커널 스택도 볼 수 있습니다
sudo bpftrace -e '
profile:hz:99
/pid == $1/
{ @[ustack] = count(); }
' $(pgrep nginx)| 명령 요소 | 설명 |
|---|---|
tracepoint:syscalls:sys_enter_read |
read() 시스템 콜 진입 시점에 훅 부착 |
@start[tid] |
스레드 ID를 키로 시작 시각 저장 (BPF Map — eBPF 프로그램과 사용자 공간 간 데이터를 주고받는 공유 저장소) |
profile:hz:99 |
초당 99회 샘플링 (CPU 프로파일링) |
ustack |
사용자 공간 콜스택 수집 (kstack으로 바꾸면 커널 스택) |
BPF Map이란? eBPF 프로그램이 커널 안에서 수집한 데이터를 사용자 공간으로 꺼내오는 통로입니다. 위 예시의
@start[tid],@read_latency_us,@접두사가 붙은 변수들이 모두 BPF Map입니다. bpftrace가 내부적으로 처리해주기 때문에 직접 선언할 필요는 없지만, "커널에서 수집 → Map에 저장 → 사용자 공간에서 읽기"라는 흐름을 이해해두면 더 복잡한 프로그램을 작성할 때 많은 도움이 됩니다.
예시 2: Cilium + Hubble로 Kubernetes 트래픽 시각화
언제: Kubernetes 클러스터 전체의 서비스 간 통신을 상시 모니터링하고 싶을 때. CNI 교체 권한이 있고, 네트워크 관측가능성과 보안 정책을 동시에 얻고 싶을 때.
Kubernetes 환경이라면 Cilium이 가장 빠르게 eBPF 관측가능성을 도입할 수 있는 경로입니다. 설치 후 Hubble UI를 열면 파드 간 트래픽 흐름, 레이턴시, 드롭된 패킷을 실시간으로 볼 수 있습니다.
# Helm으로 Cilium + Hubble 설치
# 버전은 아래 명령으로 최신 버전을 확인한 후 교체하는 것을 권장합니다
# helm search repo cilium/cilium -o json | jq -r '.[0].version'
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --version 1.16.0 \
--namespace kube-system \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true# Hubble CLI로 실시간 트래픽 흐름 확인
# production 네임스페이스에서 드롭된 HTTP 트래픽 필터링
hubble observe --namespace production \
--protocol http \
--verdict DROPPED# 서비스 간 레이턴시 통계 확인
# 출력 예시: {"flow":{"l7":{"latency_ns":1523400}}} 형태로 나타납니다
hubble observe --namespace production \
--type l7 \
--output json | jq '.flow.l7.latency_ns'예시 3: Pixie로 코드 수정 없이 APM 구축
언제: 가장 빠르게 APM을 붙이고 싶을 때. kubectl 접근만 있으면 되고, CNI 교체나 코드 변경 없이 HTTP/gRPC/DB 요청 전체를 자동으로 트레이싱하고 싶을 때.
Pixie는 제가 가장 인상 깊게 써본 도구 중 하나입니다. kubectl 플러그인 하나 설치하면 HTTP, gRPC, MySQL 요청의 전체 바디를 자동으로 캡처하고 플레임 그래프까지 만들어줍니다.
설치 스크립트로 curl | bash 패턴을 제공하고 있는데, 이 패턴은 스크립트 내용을 미리 확인하지 않고 실행하는 것이어서 보안에 민감한 환경이라면 공식 GitHub에서 직접 스크립트를 내려받아 내용을 검토한 후 실행하는 것을 권장합니다.
# Pixie CLI 설치 (설치 전 스크립트 내용 확인 권장)
# 보안이 중요한 환경이라면: curl -fsSL https://withpixie.ai/install.sh -o install.sh && cat install.sh
bash -c "$(curl -fsSL https://withpixie.ai/install.sh)"
px deploy# HTTP 엔드포인트별 레이턴시 P99 조회
px run px/http_data_filtered -- \
-start_time '-5m' \
-namespace 'production'
# MySQL 슬로우 쿼리 자동 탐지
px run px/mysql_stats -- \
-start_time '-10m'PxL이란? Pixie가 사용하는 쿼리 언어로, pandas와 유사한 문법으로 eBPF가 수집한 커널 레벨 데이터를 쿼리할 수 있습니다. 클러스터 내 로컬 스토리지에서 직접 쿼리하기 때문에 데이터가 외부로 나가지 않는 것도 장점입니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| Zero-instrumentation | 애플리케이션 코드·컨테이너 이미지 수정 없이 텔레메트리 수집 |
| 낮은 오버헤드 | JIT 컴파일된 네이티브 코드 실행, 일반적으로 CPU 오버헤드 1~3% 수준 |
| 광범위한 가시성 | 커널 |
| 안전성 보장 | verifier가 정적 분석으로 커널 크래시 유발 코드를 사전 차단 |
| 동적 부착 | 재부팅·서비스 중단 없이 런타임에 프로브 추가/제거 가능 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 학습 곡선 | 커널 내부 지식, C 언어, verifier 제약 이해 필요 | Pixie·Coroot 같은 고수준 도구부터 시작하는 것을 권장 |
| 커널 버전 의존성 | 기능이 커널 버전마다 다름, 구형 RHEL 등 레거시 환경 지원 어려움 | BTF/CO-RE 지원 여부 확인 후 도입 검토 |
| 프로그램 제약 | 무한루프 불가, 복잡한 로직 구현에 한계 | 복잡한 분석은 사용자 공간으로 데이터를 올린 후 처리 |
| 분석 레이어 부재 | eBPF는 수집 도구, 시각화·분석은 별도 레이어 필요 | Prometheus + Grafana 또는 Hubble UI 연동 |
| Linux 전용 | Windows/macOS 미지원 (Windows eBPF 프로젝트는 초기 단계) | 개발 환경은 Lima/Multipass로 Linux VM 활용 |
| 보안 리스크 | 악성 eBPF 프로그램을 통한 커널 수준 공격 가능성, 높은 권한 필요 | CAP_BPF capability 최소 권한 원칙 적용, 프로그램 서명 검증 |
실무에서 단점 때문에 실제로 고생한 경험을 짧게 공유하자면 — 커널 버전 의존성은 정말 예상보다 자주 맞닥뜨립니다. 개발 환경에서는 잘 되는데 온프레미스 레거시 RHEL에서는 아예 동작하지 않아서 당황했던 기억이 있습니다. 그리고 "eBPF 붙이면 관측가능성 끝"이라고 생각했다가 시각화 파이프라인을 따로 설계해야 한다는 걸 뒤늦게 깨달았는데, 처음부터 Prometheus + Grafana 연동을 고려해두는 것이 좋습니다.
BTF(BPF Type Format)란? eBPF 프로그램이 커널 버전과 무관하게 이식될 수 있도록 타입 정보를 포함하는 포맷입니다. BTF 자체는 커널 4.18부터 도입됐고, CO-RE(Compile Once – Run Everywhere)를 완전히 활용하려면
CONFIG_DEBUG_INFO_BTF옵션이 추가된 커널 5.2 이상, CO-RE 전체 기능은 5.4 이상이 필요합니다.uname -r과bpftool feature로 먼저 확인해보는 것이 좋습니다.
실무에서 가장 흔한 실수
-
커널 버전 확인을 건너뛰는 것 — eBPF 기능은 커널 버전별로 크게 다릅니다.
uname -r과bpftool feature확인이 첫 번째 단계입니다. 특히 CO-RE는 커널 5.4 이상, BTF(CONFIG_DEBUG_INFO_BTF)는 5.2 이상이 필요하다는 점을 기억해두시면 좋습니다. -
root 권한을 무조건 주는 것 — eBPF 프로그램 로드에는 권한이 필요하지만, 최신 커널(5.8+)에서는
CAP_BPFcapability만으로도 충분합니다. 프로덕션에서 컨테이너에 무조건privileged: true를 주는 건 피하는 것이 좋습니다. -
eBPF를 수집과 분석 모두로 기대하는 것 — eBPF는 데이터를 수집하고 BPF Map에 저장하는 역할까지가 전부입니다. 시각화·알림·집계는 별도 파이프라인(Prometheus, Grafana, Jaeger 등)이 필요하다는 점을 설계 초기에 고려해두시면 나중에 아키텍처를 뜯어고치는 수고를 덜 수 있습니다.
마치며
eBPF는 단순한 디버깅 도구가 아니라, 관측가능성 아키텍처 자체를 커널 레이어로 내려보내는 패러다임 전환입니다. 코드 수정 없이 커널까지 들여다볼 수 있는 충분한 생태계가 이미 갖춰져 있고, 지금이 도입을 시작하기에 좋은 시점입니다.
복잡한 커널 프로그래밍부터 시작할 필요는 없습니다. 고수준 도구부터 써보면서 점차 깊이를 더해가는 방식으로 접근하는 것을 강하게 권장합니다.
지금 바로 시작해볼 수 있는 3단계:
-
로컬 또는 개발 서버에서 bpftrace 설치 후 기본 도구 탐색 —
sudo apt install bpftrace또는brew install bpftrace(Linux VM 필요)로 설치 후bpftrace -l 'tracepoint:syscalls:*'로 사용 가능한 훅 목록을 살펴보시면, eBPF가 커널의 어떤 지점에 붙을 수 있는지 직접 체감됩니다 -
Kubernetes 클러스터가 있다면 Pixie 배포 —
px deploy한 줄로 설치되며, 별도 코드 수정 없이 HTTP/gRPC/DB 요청 트레이싱이 바로 동작하는 것을 확인해볼 수 있습니다 -
프로덕션 네트워킹 고도화를 검토 중이라면 Cilium 마이그레이션 고려 — eBPF 데이터패스가 전통적인 iptables 대비 처리량이 크게 향상된다는 것은 Cilium 공식 벤치마크 문서에서 확인할 수 있으며, Hubble 기반 L7 관측가능성도 동시에 얻을 수 있습니다
다음 글: Cilium + Hubble로 Kubernetes 서비스 메시를 사이드카 없이 구성하는 실전 가이드 — iptables에서 eBPF 데이터패스로 전환하는 과정을 단계별로 살펴봅니다.
참고 자료
- What is eBPF? | ebpf.io
- eBPF Applications Landscape | ebpf.io
- Introduction to eBPF for Observability | Better Stack
- eBPF in 2026: The Kernel Revolution | DEV Community
- eBPF Ecosystem Progress in 2024–2025 | eunomia
- 8 Best Open-Source eBPF Tracing Tools | Better Stack
- eBPF Tools: Falco, Inspektor Gadget, Hubble, Cilium | The New Stack
- Advantages and Disadvantages of eBPF | Alibaba Cloud
- When (And When Not) to Use eBPF | Cloud Native Now
- What is eBPF? | Datadog Knowledge Center
- eBPF for Enhanced Observability | New Relic