Kubernetes의 뇌, etcd가 클러스터 상태를 지키는 방법

|Platform Decision|12분 읽기

클러스터가 깨졌을 때 가장 먼저 의심받는 녀석

Kubernetes 장애 대응을 몇 번 해보다 보면 특이한 패턴을 발견하게 됩니다. 뭔가 이상할 때마다 "etcd 확인해봐"라는 말이 나온다는 것. 처음엔 그냥 관례인 줄 알았는데, 알고 보니 그럴 만한 이유가 있더라고요.

Kubernetes에서 etcd는 말 그대로 모든 것의 중심입니다. API 서버도, 스케줄러도, 컨트롤러 관리자도 아닌 etcd가 가장 중요한 구성 요소라는 게 좀 의외였어요. 하지만 생각해보면 당연합니다. 다른 컴포넌트들은 etcd 없이는 할 일이 없거든요.

etcd가 정확히 뭐하는 녀석인가

etcd는 분산 키-값 저장소입니다. 여러 서버에 걸쳐 동작하면서도 모든 노드가 완벽하게 동기화된 상태를 유지하는 매우 똑똑한 사전이라고 보면 됩니다.

이름부터 힌트를 줍니다. 리눅스의 /etc 디렉터리는 시스템 설정 파일들이 모여있는 곳이죠. etcd는 distributed /etc의 줄임말입니다. 한 대가 아닌 클러스터 전체의 설정 저장소라는 뜻이에요.

Kubernetes는 처음부터 etcd를 백엔드 스토어로 사용했습니다. Pod 하나를 만들 때마다, 서비스를 등록할 때마다, Secret을 생성할 때마다 모든 정보가 etcd에 기록됩니다.

실제로 etcd 안을 들여다보면 이런 구조로 되어 있습니다:

/registry/deployments/default/my-app
/registry/pods/kube-system/coredns-abc123
/registry/secrets/default/my-secret
/registry/services/specs/default/my-service

kubectl get pod my-pod -o yaml을 실행할 때 보는 그 YAML 데이터가 바로 여기서 나오는 겁니다.

Raft 알고리즘으로 동기화를 지키는 법

프로덕션에서는 etcd를 단일 인스턴스로 돌릴 수 없습니다. 그 노드가 죽으면 클러스터 전체 상태가 날아가거든요. 그래서 보통 3~5개 노드로 클러스터를 구성하는데, 여기서 Raft 합의 알고리즘이 등장합니다.

Raft는 매우 엄격한 규칙을 가진 민주주의 같은 거예요:

  1. 리더 한 명만 존재: 모든 쓰기 요청은 리더를 거쳐야 합니다
  2. 팔로워들은 따라만 함: 리더가 시키는 대로 하고, 리더가 문제 생기면 새 리더 선출 준비
  3. 과반수 동의가 필수: 데이터 쓰기는 과반수가 동의해야 완료

쓰기 과정을 보면 이렇습니다:

  1. 쓰기 요청이 리더에게 도착 ("새 배포 생성해줘")
  2. 리더가 자신의 로그에 추가하고 모든 팔로워에게 전송
  3. 팔로워들이 로그에 기록하고 "OK" 응답
  4. 과반수가 응답하면 리더가 커밋 처리
  5. 리더가 팔로워들에게 "커밋했다" 알림
  6. 클라이언트에게 "성공" 응답

홀수 개의 노드를 쓰는 이유도 여기에 있습니다. 3노드에서는 2개, 5노드에서는 3개가 동의해야 하죠. 4노드 클러스터는 3노드와 똑같이 1개까지만 장애를 견딜 수 있으면서 복잡성만 늘어납니다.

리더가 죽으면 어떻게 될까요? 팔로워들은 리더의 하트비트를 기다리고 있다가, 일정 시간(보통 150~300ms) 동안 신호가 없으면 "리더 죽었나보다" 판단하고 선거를 시작합니다. 가장 먼저 과반수 표를 얻는 노드가 새 리더가 되고요.

API 서버만이 etcd와 대화한다

Kubernetes 아키텍처에서 중요한 포인트 하나: 오직 API 서버만 etcd와 통신합니다. 스케줄러도, 컨트롤러 관리자도, kubelet도 직접 etcd에 접근하지 않아요.

API 서버가 일종의 게이트키퍼 역할을 하는 거죠. 인증, 인가(RBAC), 검증 등을 모두 처리한 다음에야 etcd에 저장하거나 읽어옵니다.

이 구조 덕분에 etcd는 "누가 요청하는지", "권한이 있는지" 같은 걸 신경 쓸 필요가 없습니다. API 서버가 알아서 처리해주니까요.

API 서버는 gRPC로 2379 포트를 통해 etcd와 통신하고, etcd 노드끼리는 2380 포트로 대화합니다. 모든 연결은 mutual TLS로 보호되어 있어서 인증서가 잔뜩 필요해요.

Watch API도 빼놓을 수 없는 기능입니다. Kubernetes의 컨트롤 루프가 "원하는 상태 vs 실제 상태"를 지속적으로 맞춰나가는데, 매번 폴링하지 않고도 변경사항을 즉시 알 수 있는 건 이 기능 덕분입니다.

새 배포를 생성하면 API 서버가 etcd에 저장하고, etcd는 즉시 컨트롤러 매니저에게 watch 이벤트로 알려줍니다. 그러면 deployment 컨트롤러가 깨어나서 ReplicaSet과 Pod를 만들기 시작하죠.

etcd에 들어있는 것, 없는 것

명확히 구분해둘 필요가 있습니다.

etcd에 저장되는 것들:

  • 모든 Kubernetes API 객체 (Pod, Deployment, Service, ConfigMap, Secret 등)
  • 클러스터 설정과 메타데이터
  • 컴포넌트들의 리더 선출 잠금

etcd에 저장되지 않는 것들:

  • 컨테이너 로그 (노드 로컬 스토리지에)
  • 메트릭 (모니터링 스택으로)
  • 컨테이너 이미지
  • 애플리케이션 데이터

etcd는 범용 데이터베이스가 아닙니다. 고일관성이 필요한 소량의 설정 데이터를 위해 설계된 거예요. 권장 용량도 8GB 이하로 유지하라고 되어 있습니다.

용량이 계속 늘어나면 defragmentation을 해줘야 합니다:

etcdctl defrag

업데이트와 삭제가 반복되면서 생긴 파편화된 공간을 정리하는 과정이에요. 데이터베이스 청소기라고 보면 됩니다.

백업은 선택이 아니다

etcd 백업은 협상 불가능한 필수사항입니다. etcd가 클러스터의 뇌라면, 백업하지 않고 운영하는 건 정말 위험한 일이에요.

etcd는 Kubernetes 제어 평면에서 유일한 상태 저장 컴포넌트입니다. etcd를 백업해두면 전체 클러스터 상태를 복원할 수 있지만, 백업 없이 etcd를 잃으면 그 모든 리소스가 사라집니다.

스냅샷 생성은 간단하고 무중단으로 가능합니다:

ETCDCTL_API=3 etcdctl snapshot save /opt/backup/etcd-$(date +%Y%m%d).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

복원할 때는 최근에 도입된 etcdutl을 사용하는 게 좋습니다:

# etcd 3.5 이상에서 권장
etcdutl --data-dir /var/lib/etcd-restored snapshot restore /opt/backup/etcd-20260407.db

프로덕션 운영 시 알아둘 것들

실제 프로덕션에서 etcd를 운영해보면서 얻은 교훈들:

1. 디스크 I/O가 전부다 etcd는 CPU나 메모리보다 디스크 지연에 훨씬 민감합니다. WAL(Write Ahead Log)을 사용해서 모든 커밋마다 fsync를 해야 하거든요. 공유 스토리지나 느린 디스크를 쓰면 선거 타임아웃과 클러스터 불안정이 시작됩니다. SSD는 선택이 아니라 필수예요.

2. 핵심 시스템에는 5노드 3노드는 1개 장애까지, 5노드는 동시에 2개 장애까지 견딜 수 있습니다. 절대 멈춰서는 안 되는 프로덕션 클러스터라면 5개 멤버로 구성하세요.

3. 정기적인 defrag 필요 etcdctl defrag를 정기적으로 실행해야 하는데, 리더를 defrag하면 잠시 리더십 이전이 발생합니다. 팔로워부터 먼저, 리더는 마지막에.

4. 모니터링 지표들

  • etcd_server_leader_changes_seen_total: 빈번한 리더 교체는 불안정 신호
  • etcd_disk_wal_fsync_duration_seconds: p99가 10ms 넘으면 디스크가 고생 중
  • etcd_mvcc_db_total_size_in_bytes: 데이터베이스 크기 모니터링

결국 모든 길은 etcd로

etcd는 매일 직접 다루는 컴포넌트는 아니지만, 모든 것을 조용히 떠받치고 있는 기둥 같은 존재입니다. kubectl 명령 하나하나가 결국 etcd를 거쳐가고, 모든 컨트롤 루프가 etcd에 의존하고, 모든 리더 선출이 etcd를 통해 이뤄지죠.

Kubernetes에서 "항상 DNS 문제"라는 농담이 있는데, etcd의 경우는 "항상 etcd가 문제"가 될 수 있어서 더 신경 써야 합니다. 하지만 제대로 이해하고 운영하면 정말 든든한 동반자가 되어줄 거예요.

#Kubernetes#etcd#분산시스템#DevOps#인프라