본문 바로가기
1. K8s Core & Architecture/1.1. 컨트롤 플레인 (Control Plane) 심층 분석

쿠버네티스 이벤트(Events) 아키텍처: 클러스터 내의 모든 기록 추적하기

by K8s Architect 2026. 3. 18.

쿠버네티스 이벤트(Events) 아키텍처: 클러스터 내의 모든 기록 추적하기

1. 쿠버네티스 이벤트(Event)의 본질: 상태 변화의 기록

쿠버네티스 클러스터에서 발생하는 모든 유의미한 상태 변화, 에러, 라이프사이클 전환은 단순한 표준 출력 로그(stdout)로만 남지 않습니다. 쿠버네티스는 이러한 발생 이력을 '이벤트(Event)'라는 독립적인 1급 API 오브젝트(First-class API Object)로 생성하여 관리합니다. 파드가 스케줄링 대기 중일 때, Kubelet이 컨테이너 이미지를 다운로드하기 시작할 때, OOM(Out of Memory)으로 컨테이너가 강제 종료될 때 등 클러스터 내부의 수많은 컴포넌트들은 각자의 작업을 수행하며 API 서버에 이벤트 오브젝트를 발행(Publish)합니다.

이벤트는 파드나 디플로이먼트처럼 사용자가 직접 YAML로 선언하여 생성하는 리소스가 아니라, 시스템 컴포넌트들이 클러스터의 가시성(Observability)을 제공하기 위해 동적으로 생성하는 감사 및 트러블슈팅의 핵심 데이터입니다.

2. 이벤트 생성 파이프라인 (Event Generation Pipeline)

Kubelet, Kube-scheduler, Kube-controller-manager 등 쿠버네티스의 핵심 컴포넌트들은 내부적으로 client-go 라이브러리의 EventRecorderEventBroadcaster라는 메커니즘을 사용하여 이벤트를 생성합니다.

  • EventRecorder: 각 컴포넌트 코드 내부에서 특정 상황(예: 이미지 풀링 실패)이 발생했을 때 이벤트를 기록하는 인터페이스입니다. 발생한 사건의 원인(Reason), 메시지(Message), 심각도(Type: Normal 또는 Warning), 연관된 대상 오브젝트(Involved Object) 정보를 조합합니다.
  • EventBroadcaster: Recorder가 수집한 이벤트 데이터를 모아 Kube-apiserver로 전송하는 역할을 합니다. API 서버의 과부하를 막기 위해 내부적으로 큐잉(Queueing)과 속도 제한(Rate Limiting)을 적용하여 안전하게 이벤트를 발송합니다.

API 서버가 이 요청을 수신하면, 해당 이벤트는 다른 모든 쿠버네티스 리소스와 마찬가지로 etcd 스토리지에 영구적으로 기록됩니다.

3. 스토리지 부하와 보관 주기(TTL)의 한계

이벤트 아키텍처에서 가장 주의해야 할 점은 etcd의 데이터베이스 용량입니다. 대규모 클러스터에서는 분당 수천에서 수만 개의 이벤트가 생성될 수 있습니다. etcd는 고속의 상태 동기화를 위한 저장소이지, 대용량 로그를 무한정 쌓아두기 위한 시계열 데이터베이스가 아닙니다.

이러한 스토리지 고갈을 방지하기 위해 쿠버네티스의 이벤트 오브젝트는 기본적으로 1시간(1h)이라는 매우 짧은 TTL(Time-To-Live)을 가집니다. API 서버의 --event-ttl 플래그를 통해 이 주기를 조정할 수 있지만, 1시간이 지난 이벤트는 etcd의 가비지 컬렉터에 의해 자동으로 삭제됩니다. 이는 장애가 발생한 지 수 시간이 지난 뒤에 사후 분석(Post-mortem)을 시도할 때, CLI 명령어를 통해 조회해도 이벤트가 하나도 남아있지 않아 원인 규명에 어려움을 겪는 주된 이유입니다.

4. 이벤트 압축(Event Compression) 및 스팸 필터링

짧은 시간 내에 동일한 파드에서 동일한 에러(예: CrashLoopBackOff나 ImagePullBackOff)가 무한히 반복된다면 어떻게 될까요? 쿠버네티스는 etcd를 보호하기 위해 이벤트 압축(Event Compression) 메커니즘을 작동시킵니다.

컴포넌트의 EventBroadcaster는 API 서버로 이벤트를 보내기 전, 최근에 발생한 이벤트와 대상(Involved Object), 원인(Reason), 메시지가 완벽히 일치하는지 확인합니다. 만약 동일한 이벤트가 반복적으로 발생하고 있다면, API 서버에 매번 새로운 이벤트 오브젝트를 생성하는 대신 기존 이벤트 오브젝트의 Count 필드 값만 1씩 증가시키고 lastTimestamp를 최신 시간으로 업데이트합니다. 이를 통해 etcd의 디스크 I/O와 스토리지 공간 낭비를 획기적으로 줄이면서도 몇 번의 에러가 지속되었는지 정확히 추적할 수 있습니다.

5. 대규모 클러스터를 위한 이벤트 아키텍처 고도화

기본 1시간의 보관 주기를 극복하고 엔터프라이즈 수준의 감사(Audit) 및 모니터링 체계를 구축하기 위해서는 아키텍처 레벨의 확장이 필수적입니다.

  • etcd 클러스터 분리 (Event Isolation): 클러스터 규모가 노드 500대 이상으로 커지면, 이벤트 기록으로 인한 디스크 I/O가 API 서버의 메인 상태 동기화 성능을 저하시킬 수 있습니다. Kube-apiserver의 --etcd-servers-overrides=/events#https://[새로운-etcd-주소] 플래그를 사용하여 이벤트 데이터만 전담으로 저장하는 별도의 물리적 etcd 클러스터를 분리 구축하는 것이 강력히 권장됩니다.
  • 외부 저장소로의 이벤트 내보내기 (Exporting): 1시간의 한계를 넘어 이벤트를 영구 보관하려면, 이벤트가 etcd에서 삭제되기 전에 외부 로깅 시스템으로 퍼내야 합니다. kube-eventer, Eventrouter와 같은 전용 파드를 클러스터 내에 배포하면, 이 파드들이 API 서버의 이벤트 Watch 스트림을 구독하여 발생하는 모든 이벤트를 가로챕니다. 이후 Elasticsearch, Loki, Kafka, 또는 Slack 알림 등으로 이벤트를 라우팅하여 수개월 단위의 장기 보관 및 검색 인프라를 완성할 수 있습니다.

6. 이벤트 기반 트러블슈팅 메커니즘

실무에서 장애를 추적할 때 이벤트 오브젝트를 어떻게 활용해야 하는지 명확히 이해해야 합니다.

이벤트는 항상 특정 리소스(Involved Object)에 종속되어 있습니다. 파드가 스케줄링되지 못해 Pending 상태일 때, 해당 파드의 컨테이너 내부 로그를 확인하는 것은 아무런 의미가 없습니다. 컨테이너 런타임 자체가 아직 시작되지 않았기 때문입니다. 이 단계에서는 오직 Kube-scheduler가 API 서버에 발행한 FailedScheduling 이벤트만이 유일한 단서가 됩니다.

마찬가지로 워커 노드의 리소스가 부족해져 파드가 축출(Evicted)될 때도, 원인은 파드 내부 로직이 아니라 노드 수준의 압박(MemoryPressure, DiskPressure)입니다. Kubelet은 노드 오브젝트를 대상으로 이러한 상태 이벤트를 발행합니다. 따라서 클러스터 전체의 이상 징후를 가장 빠르게 파악하는 방법은 모니터링 시스템에서 Type: Warning으로 분류된 이벤트들을 실시간으로 필터링하고 이를 대시보드화하여 관제하는 것입니다. 이벤트는 분산 시스템의 블랙박스 내부를 들여다볼 수 있게 해주는 가장 직관적이고 강력한 시스템 진단 기록입니다.