본문으로 건너뛰기
11.3 etcd 백업과 복구

11.3 etcd 백업과 복구

클러스터의 모든 선언과 상태는 결국 etcd 한 곳에 저장된다. Deployment 정의도, Secret도, RBAC 규칙도 etcd가 유실되면 함께 사라진다. 노드는 다시 만들면 되고 control plane 프로세스는 다시 기동하면 되지만, etcd 데이터만은 백업이 없으면 복원할 방법이 없다. 그래서 이 챕터는 etcd를 데이터베이스로, 백업을 DBA의 규율로 다룬다. 주기, 보관, 검증, 복구 리허설이라는 항목은 PostgreSQL 백업에 요구하는 것과 다르지 않다.

스냅샷이 담는 것과 담지 않는 것

etcd 스냅샷은 apiserver를 거쳐 저장된 모든 오브젝트를 담는다. 워크로드 정의, Service, ConfigMap, Secret, RBAC, CRD와 커스텀 리소스까지 클러스터의 선언적 상태 전체다. 스냅샷 하나로 클러스터의 “구성"은 완전히 복원된다.

담지 않는 것을 아는 일이 더 중요하다. PersistentVolume 오브젝트는 etcd에 있지만 그 볼륨 안의 실제 데이터는 스토리지 시스템에 있다. 컨테이너 이미지는 각 노드의 런타임 저장소와 레지스트리에 있다. 노드 OS 설정과 로컬 파일도 당연히 밖이다. 즉 etcd 백업은 클러스터 구성의 백업이지 애플리케이션 데이터의 백업이 아니다. 데이터베이스를 Kubernetes 위에서 운영한다면 볼륨 스냅샷이나 데이터베이스 자체 백업 도구가 별도로 있어야 하고, 두 백업 체계는 서로를 대체하지 못한다. 볼륨과 스냅샷의 구조는 Part VI. 스토리지에서 다뤘다.

snapshot save와 검증

kubeadm 클러스터의 etcd는 TLS 클라이언트 인증을 요구하므로, 스냅샷 명령에 인증서 세 개를 지정한다. control plane 노드에서 실행한다.

sudo ETCDCTL_API=3 etcdctl snapshot save /var/backups/etcd/snap-$(date +%Y%m%d-%H%M).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

스냅샷은 실행 중인 멤버에서 그대로 생성한다. etcd를 멈출 필요가 없고, 그 시점의 일관된 상태가 파일 하나로 나온다. HA etcd라도 멤버 하나에서 생성하면 충분하다.

저장했다고 끝이 아니다. DBA가 백업 파일의 무결성을 확인하듯 스냅샷도 검증한다. etcd 3.5부터 파일 대상 명령은 etcdutl로 분리됐다.

etcdutl snapshot status /var/backups/etcd/snap-20260822-0300.db --write-out=table

hash, revision, 총 key 수, 파일 크기가 표로 나온다. revision이 직전 백업보다 앞으로 가 있는지, key 수가 평소 규모인지 정도만 대조해도 “빈 파일을 1년째 쌓고 있었다"류의 사고는 걸러진다.

복구 절차

스냅샷 복구를 실행할 상황부터 구분한다. etcd 멤버 3개 중 하나가 유실된 경우라면 quorum이 살아 있으므로 스냅샷은 필요 없다. 고장 난 멤버를 제거하고 새 멤버를 추가하면 나머지 멤버로부터 데이터가 복제된다. 스냅샷 복구가 필요한 상황은 quorum을 잃었거나, 단일 etcd의 데이터가 통째로 유실됐거나, 잘못된 변경을 과거 시점으로 되돌려야 할 때다. 데이터베이스로 치면 replica 재구축과 PITR 복구를 구분하는 것과 같은 판단이다.

복구 자체는 스냅샷을 새 데이터 디렉토리로 풀어낸 뒤, etcd가 그 디렉토리를 보도록 바꾸는 두 단계다. 기존 디렉토리에 덮어쓰지 않는다.

sudo etcdutl snapshot restore /var/backups/etcd/snap-20260822-0300.db \
  --data-dir=/var/lib/etcd-restored

kubeadm 클러스터에서 etcd는 static Pod이므로, /etc/kubernetes/manifests/etcd.yaml의 hostPath 볼륨이 가리키는 경로를 /var/lib/etcd-restored로 바꾸면 kubelet이 etcd Pod를 재생성한다. etcd가 새 데이터로 기동하면 apiserver가 다시 연결되고 API가 다시 응답한다. 공식 문서는 복구 뒤 kube-apiserver, kube-controller-manager, kube-scheduler 같은 컴포넌트를 재시작해 오래된 캐시 상태를 비우라고 권고한다.

복구된 클러스터는 스냅샷 시점으로 되돌아간 클러스터다. 그 이후 생성된 오브젝트는 사라지고, 삭제된 오브젝트는 다시 나타난다. 노드 위에서 실제로 실행 중인 컨테이너와 etcd 기록이 어긋난 부분은 controller와 kubelet의 reconciliation이 선언 쪽으로 다시 수렴시킨다. 이 수렴 과정에서 Pod가 재생성되거나 정리될 수 있으므로, 복구는 API 유실 자체보다 넓은 영향 범위를 가진 작업으로 계획한다.

백업을 규율로 만드는 것

관리형 서비스에서 etcd 백업은 사업자의 내부 절차라 사용자에게 보이지도 않는다. kubeadm 클러스터에서는 그 절차 전체를 직접 설계해야 하고, 명령 한 줄을 아는 것과 백업 체계를 갖춘 것 사이의 거리는 데이터베이스 운영에서의 거리와 같다. 갖춰야 할 항목도 같다.

주기는 클러스터 변경 빈도에 맞춘다. cron이나 CronJob으로 자동화하고, 업그레이드나 대규모 마이그레이션처럼 되돌아갈 지점이 필요한 작업 직전에는 일정 밖 스냅샷을 추가로 생성한다. 보관은 control plane 노드 밖이 원칙이다. 노드 로컬에만 쌓아 두면 그 노드의 디스크 유실이 곧 백업 유실이 된다. 외부 스토리지로 복사하고 세대 수와 보관 기간을 정한다. 스냅샷 작업의 실패는 알람으로 감지되게 한다. 조용히 실패한 백업은 없는 백업과 같다.

그리고 복구 리허설이다. 복구해 본 적 없는 백업은 백업이 아니라 파일이다. 테스트 클러스터나 일회용 VM에 실제로 restore를 실행해 API가 다시 응답하기까지 걸리는 시간을 재 두면, 실제 장애 때 절차를 처음 읽으며 복구하는 상황을 피한다. 리허설 주기는 인증서 만료나 etcd 버전 변경 같은 환경 변화를 따라잡을 정도면 된다.

etcd에 저장된 Secret은 base64 인코딩일 뿐 암호화가 아니다. encryption at rest를 구성하지 않았다면 스냅샷 파일에는 클러스터의 모든 Secret이 사실상 평문으로 들어 있다. 스냅샷 파일의 권한을 제한하고, 보관 저장소를 암호화하고, 전송 구간을 보호하는 일까지가 백업 절차에 포함된다. Secret의 저장 특성은 Part VII. 구성과 시크릿 참고.

정리

  • 스냅샷은 클러스터 구성 전체를 담지만 PV 데이터와 컨테이너 이미지는 담지 않는다. 애플리케이션 데이터 백업은 별도 체계로 병행한다.
  • save, status 검증, 외부 보관, 복구 리허설, 스냅샷 파일 보호까지가 한 묶음이다. 데이터베이스 백업에서 요구하는 규율 그대로다.