cgroup v2 격리 누수는 폴링과 eBPF 중 뭘로 잡아야 하나?
결론부터 말하면 정기 스캔이 남긴 짧은 스파이크를 잡아야 하면 eBPF, 그럴 필요가 없으면 cgroupfs 폴링으로 충분하다. 두 방식은 대체재가 아니라 감지 대상의 시간 스케일이 다른 도구다. 2026년 기준 상당수 클러스터는 여전히 폴링 기반 파이프라인 위에서 운영되고, eBPF 트레이싱은 문제가 재현될 때만 얹는 보조 계측으로 쓰이는 경우가 많다.
- 폴링(cAdvisor류)은 10~30초 주기 스냅샷이라 누수의 "존재"는 보이지만 "발생 순간"은 놓친다.
- dying cgroup이 수천 단위로 쌓이면 폴링 자체의 스캔 비용이 커져 관측 도구가 부하 원인이 되는 역전이 생긴다.
- eBPF 트레이싱은 이벤트 단위로 붙기 때문에 순간적 charge/uncharge 패턴과 호출 경로까지 잡을 수 있다.
- 대신 BTF/CO-RE 호환 커널, 빌드 파이프라인, 권한 관리가 추가로 필요해 운영 난이도가 올라간다.
- 판단 기준은 클러스터 규모와 커널 버전 통제력이지, 어느 쪽이 "더 나은 도구"인지가 아니다.
두 방식을 나란히 놓으면 이렇다. 한쪽은 /sys/fs/cgroup/.../memory.stat, cpu.stat을 주기적으로 읽어 시계열로 쌓는 방식이고, 다른 한쪽은 memcg charge, cgroup_rstat_flush 같은 커널 이벤트 지점에 프로그램을 붙여 발생 시점에 데이터를 뽑는 방식이다. 전자는 이미 대부분의 Prometheus 기반 파이프라인에 내장돼 있고, 후자는 별도 도구(bpftrace 스크립트, Parca, Pixie류)를 얹어야 한다.
감지까지 걸리는 시간이 왜 방식마다 다른가?
폴링은 샘플링 주기보다 짧은 스파이크를 구조적으로 놓친다. memory.current가 30초 간격 스냅샷 사이에서 튀었다 가라앉으면 그래프에는 흔적이 남지 않는다. eBPF는 charge 이벤트 자체를 훅하기 때문에 밀리초 단위 스파이크도 이벤트 스트림으로 남는다. 다만 이벤트 볼륨이 크면 링버퍼 오버플로로 일부 유실될 수 있어 "이벤트 단위 = 무손실"은 아니다.
dying cgroup이 쌓일 때 오버헤드는 어느 쪽이 커지는가?
컨테이너가 종료돼도 페이지 캐시나 커널 메모리 charge가 완전히 회수되기 전까지 memcg는 dying 상태로 남는다. 커널 문서는 cgroup v2의 rstat 플러시가 하위 트리 전체를 순회하며 통계를 합산하는 구조라고 설명한다 cgroup v2 admin guide. 이 dying cgroup 수가 수천 단위로 쌓이면 매 폴링 주기마다 순회 비용이 늘어나고, 관측 도구 자체가 CPU를 갉아먹는 사례가 보고된 바 있다. eBPF는 순회 대신 이벤트 훅이라 이 문제에서 상대적으로 자유롭지만, 훅 지점이 많아지면 이벤트당 오버헤드가 누적된다.
원인을 프로세스 단위까지 추적할 수 있는가?
폴링은 합산된 카운터 값만 준다. memory.stat의 slab_reclaimable이 늘어난다는 건 알아도 어떤 커널 경로에서 왜 늘었는지는 별도 도구 없이는 못 본다. eBPF 트레이싱은 이벤트에 PID, 호출 스택을 함께 붙일 수 있어 근본 원인까지 좁힐 수 있다. BPF 기반 관측이 커널 이벤트 지점에 프로그램을 부착해 폴링 없이 데이터를 뽑아내는 구조라는 점은 관련 문서에서도 공통적으로 강조된다 Cilium BPF 레퍼런스.
수치로 비교하면 격차가 얼마나 벌어지나?
| 항목 | cgroupfs 폴링 | eBPF 트레이싱 |
|---|---|---|
| 표준 샘플링 간격 | 10~30초 | 이벤트 단위(서브밀리초) |
| dying cgroup 다수 시 오버헤드 | 스캔 비용 증가, 스파이크 보고 사례 존재 | 상대적으로 완만, 훅 수에 비례 |
| 원인 추적 깊이 | 합산 카운터 | 호출 스택 + PID 매핑 |
| 커널 요구사항 | cgroup v2 지원(4.5+)이면 충분 | BTF/CO-RE 지원 커널 권장(5.x+) |
| 운영 난이도 | 낮음, 기존 파이프라인 재사용 | 높음, 빌드·서명·권한 관리 필요 |
폴링에서 eBPF로 옮기면 뭐가 새로 필요한가?
가장 먼저 커널 헤더와 BTF 가용성부터 확인해야 한다. 노드 이미지가 BTF를 내장하지 않으면 CO-RE 빌드가 실패하고, vmlinux 헤더를 별도로 배포하는 작업이 추가된다. 그다음은 권한이다. CAP_BPF, CAP_PERFMON 같은 세분화 capability를 컨테이너 런타임 정책에 반영해야 하고, 기존에 root 전체를 열어주던 노드라면 오히려 축소하는 방향으로 재검토가 필요하다. 마지막으로 알람 임계값 재조정이다. 이벤트 단위 데이터는 폴링 시계열과 스케일이 달라 기존 대시보드 임계값을 그대로 옮기면 오탐이 늘어난다.
그래서 어느 쪽을 써야 하는가?
정답은 없고 조건만 있다. 노드 수가 적고 워크로드 교체 주기가 길어 dying cgroup이 쌓일 일이 드물다면 폴링만으로 충분하다. 반대로 대규모 클러스터에서 짧은 메모리 스파이크가 OOM킬로 이어지는 패턴을 잡아야 하거나, 커널 버전을 팀이 직접 통제할 수 있다면 eBPF 트레이싱을 보조로 얹는 쪽이 맞다. 두 방식을 동시에 상시 가동하는 것은 오버헤드 중복이므로, 폴링을 기본 감시로 두고 이상 징후가 잡히면 eBPF를 한시적으로 붙이는 이원 구조가 실무에서 가장 무난하다.
핵심 정리
- cgroup v2 누수 디버깅은 "감지 시간 스케일"이 폴링과 eBPF를 가르는 축이다.
- dying cgroup 누적은 폴링 도구 자체를 오버헤드 원인으로 만들 수 있다.
- eBPF는 호출 스택까지 잡지만 BTF/CO-RE 커널 요구사항과 권한 관리 비용이 따라온다.
- 전환 시 커널 헤더 확보, capability 재설계, 알람 임계값 재조정이 필요하다.
- 상시 이원화보다는 폴링 기본 + 이상 징후 시 eBPF 보조 투입이 현실적인 운영 방식이다.
더 알아보기
컨테이너 오케스트레이션·런타임: 스케줄링부터 네트워킹까지 — 이 주제의 종합 가이드