포스트

eBPF를 처음 도입할 때 무엇을 확인할까: 훅, Verifier, Map 입문

eBPF는 리눅스 커널을 다시 빌드하지 않고도 정해진 훅에 검증된 프로그램을 로드해 네트워크, 시스템 이벤트를 관찰하거나 제한하는 기술입니다. 강력하지만 아무 C 코드를 커널에 자유롭게 넣는 방식은 아니며, 커널 지원 범위와 Verifier 제약 안에서만 실행됩니다. 첫 도입은 직접 프로그램 작성보다 해결할 문제와 실패 시 복구 경계를 정하는 데서 시작해야 합니다.

eBPF 프로그램은 어떤 순서로 실행되는가

개발자는 제한된 명령과 helper를 사용하는 프로그램을 작성해 바이트코드로 컴파일합니다. 로더가 프로그램을 커널에 요청하면 Verifier가 레지스터 상태, 메모리 경계, 가능한 실행 경로와 종료 조건을 분석합니다. 검사를 통과한 프로그램만 해당 아키텍처의 실행 코드로 변환되거나 해석되어 선택한 훅에 붙습니다.

훅은 프로그램이 언제 호출되는지를 정합니다. XDP는 네트워크 드라이버 가까운 위치에서 패킷을 다루고, tracing 계열 훅은 시스템 콜이나 커널 함수의 실행을 관찰하는 데 쓰입니다. 같은 eBPF라도 연결 위치에 따라 볼 수 있는 데이터, 허용 행동과 성능 비용이 달라집니다. “커널에서 돈다”는 설명만으로 목적에 맞는 훅을 고를 수 없습니다.

프로그램을 붙이는 데는 높은 권한과 커널 설정이 필요할 수 있습니다. 컨테이너 안에서 실행된다는 이유로 호스트 영향이 사라지지 않습니다. 누가 로드, 교체, 분리할 수 있는지, 프로그램과 Map이 프로세스 종료 뒤 남는지, 노드 재부팅 후 어떤 버전이 다시 올라오는지를 배포 설계에 포함해야 합니다.

XDP 예제는 무엇을 보여 주는가

XDP는 패킷이 일반 네트워크 스택의 더 높은 단계로 올라가기 전에 통과, 차단 같은 결정을 내릴 수 있습니다. 다음 코드는 원문에 있던 학습용 스니펫으로, 패킷 경계를 확인한 뒤 특정 IPv4 출발지 값을 비교해 차단하는 흐름을 보여 줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 💡 XDP를 이용해 특정 IP의 패킷을 NIC 단에서 즉시 폐기하는 eBPF 스니펫
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

SEC("xdp")
int drop_malicious_ip(struct xdp_md *ctx) {
    // 1. 패킷의 메모리 포인터 획득
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;

    // 2. 이더넷 및 IP 헤더 파싱 및 경계 검사 (안전성 확보)
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end) return XDP_PASS;
    
    struct iphdr *ip = (void *)(eth + 1);
    if ((void *)(ip + 1) > data_end) return XDP_PASS;

    // 3. 악성 IP (예: 192.168.1.100의 Hex 값) 필터링
    if (ip->saddr == 0x6401A8C0) {
        // 커널의 무거운 네트워크 스택을 타기도 전에 하드웨어/NIC 레벨에서 패킷 삭제!
        return XDP_DROP;
    }

    return XDP_PASS; // 정상 패킷은 통과
}
char _license[] SEC("license") = "GPL";

이 코드는 운영 방화벽을 그대로 만들 수 있는 완성 예제가 아닙니다. 헤더 종류, 네트워크 바이트 순서, VLAN과 IPv6, 조각화, Map 기반 정책 갱신과 관측 로그가 빠져 있습니다. 단일 상수를 코드에 넣으면 차단 목록을 바꿀 때마다 다시 로드해야 하고, 오타 하나가 정상 트래픽을 넓게 버릴 수 있습니다.

파일럿에서는 통과만 하는 프로그램으로 시작해 패킷 수를 관찰한 뒤, 시험 IP와 별도 네트워크에서 차단을 검증합니다. 차단 전후 카운터와 샘플 로그, 프로그램 ID를 남기고 즉시 분리할 명령을 준비합니다. 성능 수치보다 잘못된 정책을 얼마나 빨리 발견하고 원래 경로로 되돌릴 수 있는지가 먼저입니다.

Verifier가 보장하는 것과 보장하지 않는 것은 무엇인가

Verifier의 목적은 프로그램이 커널 안전 규칙 안에서 실행될 수 있는지를 판단하는 것입니다. 패킷 포인터를 사용하기 전에 data_end와 비교하는 이유도 가능한 모든 경로에서 경계 밖 접근이 없음을 보여 주기 위해서입니다. 복잡한 분기나 루프, helper 호출과 Map 값의 타입이 추가되면 사람이 보기에는 안전해도 Verifier가 증명하지 못해 로드를 거부할 수 있습니다.

반대로 로드 성공은 업무 정책의 정답을 뜻하지 않습니다. 잘못된 IP 범위, 뒤집힌 조건, 지나치게 많은 이벤트 수집과 민감 데이터 기록은 메모리 안전성과 별개입니다. Verifier는 정상 사용자를 차단하지 않는지, 로그 보존이 규정을 지키는지, 프로그램이 목표 지연을 만족하는지를 대신 검사하지 않습니다.

Verifier 로그는 지원 커널과 컴파일러가 달라지면 바뀔 수 있습니다. 개발 노드에서 통과한 객체가 운영 노드에서 같은 기능을 쓸 수 있는지 커널 설정과 타입 정보를 확인해야 합니다. 지원 범위가 다양한 환경에서는 배포 대상별 사전 로드 시험과 실패 시 기존 도구 유지가 필요합니다.

BPF Map은 어떤 상태를 전달하는가

BPF Map은 eBPF 프로그램과 유저 공간 프로세스가 키와 값을 주고받는 핵심 인터페이스입니다. 차단할 IP, 연결 정보, 이벤트 카운터나 지연 분포를 저장할 수 있습니다. 프로그램 코드를 다시 로드하지 않고 유저 공간 제어기가 정책 값을 갱신할 수 있다는 점이 하드코딩과 다릅니다.

Map에도 크기, 키 충돌, 동시 접근과 수명 문제가 있습니다. 항목 상한에 도달하면 새 연결이 기록되지 않거나 오래된 상태가 남을 수 있고, CPU별 Map과 공유 Map은 집계 방식이 다릅니다. 프로그램을 교체할 때 기존 Map 스키마를 재사용할지 새로 만들지도 호환성 문제입니다.

관측 도구에서는 이벤트를 너무 많이 유저 공간으로 보내는 것이 병목이 될 수 있습니다. 필요한 필드와 샘플링을 정하고, 누락, 드롭 카운터를 함께 노출해야 “이벤트가 없었다”와 “전달하지 못했다”를 구분할 수 있습니다. Map 값에 주소나 프로세스 정보가 들어간다면 접근 권한과 보존 기간도 정합니다.

XDP, 네트워크, 트레이싱 중 어디서 시작할까

대량의 불필요한 패킷을 네트워크 스택 앞에서 거르는 문제가 명확하다면 XDP가 후보입니다. 쿠버네티스 네트워크와 정책을 운영 제품으로 해결하려면 Cilium처럼 eBPF를 내부 구현으로 사용하는 프로젝트를 먼저 검토할 수 있습니다. 애플리케이션을 바꾸기 어려운 상태에서 시스템 콜과 네트워크 지연을 관찰하려면 BCC의 기존 도구가 더 작은 시작점일 수 있습니다.

훅을 낮은 단계에 붙일수록 빠르게 개입할 수 있지만 사용할 수 있는 맥락은 줄 수 있습니다. XDP에서는 아직 소켓과 애플리케이션 정보를 알기 어렵고, 상위 훅에서는 더 풍부한 맥락 대신 이미 일부 처리 비용을 지불했습니다. 문제에 필요한 최소 정보를 제공하는 가장 좁은 훅을 고르는 것이 좋습니다.

관찰과 차단도 분리합니다. 처음에는 이벤트를 읽는 read-only 모드로 분포와 오탐 후보를 확인하고, 정책 효과가 검증된 뒤 제한된 대상에서만 enforce를 켭니다. 하나의 프로그램에 수집, 판단, 차단을 모두 넣으면 실패 원인과 롤백 단위가 커집니다.

직접 개발과 검증된 도구 중 무엇을 선택할까

직접 코드는 매우 특수한 패킷 형식이나 사내 커널 이벤트처럼 기존 프로젝트가 제공하지 않는 요구에 의미가 있습니다. 그 대신 C와 커널 ABI, Verifier, 로더, 배포와 장기 지원을 팀이 소유해야 합니다. 작성자가 떠난 뒤에도 새 커널에서 빌드, 로드, 디버깅할 담당자가 있는지 확인해야 합니다.

일반적인 네트워크 정책, 쿠버네티스 가시성이나 시스템 진단은 검증된 도구가 운영 문서와 업그레이드 경로를 함께 제공합니다. 제품을 쓴다고 eBPF 지식이 불필요한 것은 아니지만 커스텀 프로그램의 전체 표면을 소유할 필요는 줄어듭니다. 기능 목록보다 지원 커널, 실패 모드, 데이터 수집 범위와 롤백 절차를 비교합니다.

eBPF 공식 사이트의 개념과 생태계 자료를 출발점으로 삼고, 사용하려는 프로젝트의 현재 문서와 커널 요구 조건을 별도로 확인해야 합니다. 같은 “eBPF 기반”이라는 표현도 훅, 프로그램 수명과 권한 모델이 다를 수 있습니다.

파일럿은 어떤 검증을 통과해야 하나

먼저 운영과 같은 커널, NIC, 컨테이너 런타임을 가진 시험 노드를 준비합니다. 프로그램을 붙이지 않은 기준선에서 처리량, 지연과 CPU를 재고 관찰 모드, 제한된 enforce 모드를 차례로 비교합니다. 정상, 비정상 트래픽, Map 가득 참, 프로그램 로드 실패와 제어기 재시작을 포함합니다.

다음으로 기존 tcpdump나 애플리케이션 로그에서 보이던 정보가 새 경로에서도 추적 가능한지 확인합니다. eBPF 훅에서 패킷이 일찍 사라지면 전통 도구에는 나타나지 않을 수 있으므로 프로그램, 정책 ID와 드롭 이유를 찾을 별도 관측 경로가 필요합니다. 온콜 담당자가 문서만 보고 프로그램을 비활성화하고 원인을 좁힐 수 있어야 합니다.

확대 조건에는 기능 정확도, 최고 CPU, 메모리, 이벤트 누락, 오탐, 롤백 시간과 지원 가능한 커널 비율을 둡니다. 수치가 좋아도 정책 오류를 안전하게 되돌리지 못하거나 소수의 전문가만 디버깅할 수 있다면 범위를 유지합니다. eBPF 도입은 커널에 코드를 넣는 데서 끝나지 않고 그 코드를 운영 가능한 제품처럼 관리하는 일입니다.

원문과 버전 확인

함께 읽으면 이해가 이어지는 글

자주 묻는 질문

eBPF는 커널 모듈처럼 서버를 재부팅해야 하나요?

일반적으로 eBPF 프로그램은 지원되는 커널 훅에 런타임으로 로드, 분리할 수 있지만, 실제 가능 기능과 로드 방식은 커널 버전, 설정, 권한에 따라 확인해야 합니다.

Verifier를 통과하면 eBPF 프로그램이 안전하고 정확한가요?

아닙니다. Verifier는 허용되지 않은 메모리 접근과 종료 가능성 같은 조건을 검사하지만 정상 트래픽을 잘못 차단하는 논리 오류와 운영 정책 오류까지 증명하지는 않습니다.

직접 eBPF C 코드를 작성해야 효과를 볼 수 있나요?

대부분의 팀은 Cilium이나 BCC처럼 검증된 프로젝트로 문제를 먼저 해결하고, 제공 기능으로 충족되지 않는 좁은 요구와 유지 인력이 있을 때만 커스텀 프로그램을 검토하는 편이 낫습니다.

THE END / OPSOAI

여기까지 읽었습니다

핵심 장면을 한 번 더 떠올려 보세요. 이해가 남았다면 이 책은 제 역할을 다했습니다.

다른 책 고르기
표지 1 —

←→ 키와 좌우 스와이프를 지원합니다. 읽던 페이지는 이 기기에 저장됩니다.

CONTENTS

이 책의 목차

    11개 장 19 분읽는 시간