1. 개요
Kubernetes 클러스터에서 etcd는 모든 클러스터 상태 정보를 저장하는 핵심 데이터베이스다. etcd 데이터가 손실되면 전체 클러스터를 재구성해야 하는 치명적인 상황이 발생할 수 있다.
예전에 쿠버네티스 클러스터를 구성할 때 etcd를 백업하지 않은 채 노드 join을 하다가 etcd 클러스터 장애가 발생했던 경험이 있다. 결국 쿠버네티스 클러스터 전체를 재구성해야 했고, 운영 서버가 아니었기 때문에 망정이지 정말 땀나는 경험이었다. 그 이후로 백업은 생활이 되었다.
IMPORTANT
etcd 백업은 Kubernetes 클러스터 운영에서 필수적인 작업이다. 정기적인 백업 없이는 클러스터 장애 시 복구가 불가능하다는 것을 반드시 인지해야 한다.
2. 백업 전략
이 설정에서는 다음과 같은 백업 전략을 사용했다.
- 백업 주기: 매일 오후 5시 (Asia/Seoul 기준)
- 보관 정책: 로컬 및 영구 저장소에 각각 5일간 보관
- 이중화: 로컬 스토리지와 PVC를 활용한 이중 백업
- 자동 정리: 오래된 백업 파일 자동 삭제
3. CronJob 구성
3-1. 기본 설정
CronJob은 매일 정해진 시간에 etcd 스냅샷을 생성하고 백업 파일을 관리한다.
apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-backup-cron-job
namespace: kube-system
spec:
schedule: "0 17 * * *" # 매일 오후 5시
timeZone: "Asia/Seoul"
concurrencyPolicy: Allow
failedJobsHistoryLimit: 1
successfulJobsHistoryLimit: 3
3-2. Pod 스케줄링
백업 작업은 반드시 control-plane 노드에서 실행되어야 한다. etcd 서버에 직접 접근할 수 있는 노드에서만 백업이 가능하기 때문이다.
spec:
template:
spec:
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
operator: Exists
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- kdev-master-a-04 # 특정 마스터 노드 선호
weight: 100
3-3. etcd 백업 수행
InitContainer에서 실제 etcd 스냅샷 생성 작업을 수행한다. etcdctl snapshot
명령어를 사용하여 현재 etcd 상태를 백업 파일로 저장한다.
initContainers:
- name: etcd-backup
image: bitnami/etcd:latest
command:
- /bin/sh
- -c
- |
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
BACKUP_DIR="/backup/host"
SNAPSHOT_FILE="etcd-snapshot-${DATE}.db"
etcdctl \
--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 \
snapshot save "${BACKUP_DIR}/${SNAPSHOT_FILE}"
NOTE
etcd 백업 시에는 etcd 서버의 TLS 인증서가 필요하다. Kubernetes에서는 기본적으로
/etc/kubernetes/pki/etcd/
경로에 필요한 인증서들이 위치한다.
3-4. 백업 파일 관리
메인 컨테이너에서는 백업 파일을 영구 저장소로 복사하고, 오래된 백업 파일들을 정리한다.
containers:
- name: backup-purge
image: busybox:latest
command:
- /bin/sh
- -c
- |
# 로컬 백업을 영구 저장소로 복사
cp -u /backup/host/*.db /backup/persist/
# 5일 이상 된 백업 파일 삭제
find /backup/host -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
find /backup/persist -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
4. 볼륨 구성
백업 파일을 저장하기 위해 두 가지 볼륨을 사용한다:
- etcd-backup: 노드의 로컬 스토리지 (
/data/etcd-backup
) - second-backup: PVC를 통한 영구 저장소
- etcd-certs: etcd TLS 인증서 디렉토리
volumes:
- name: etcd-backup
hostPath:
path: /data/etcd-backup
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
type: Directory
- name: second-backup
persistentVolumeClaim:
claimName: etcd-backup-pvc
5. 전체 설정
완전한 CronJob YAML 설정
apiVersion: v1
items:
- apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-backup-cron-job
namespace: kube-system
spec:
concurrencyPolicy: Allow
failedJobsHistoryLimit: 1
jobTemplate:
metadata:
creationTimestamp: null
spec:
template:
metadata:
creationTimestamp: null
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- kdev-master-a-04
weight: 100
containers:
- command:
- /bin/sh
- -c
- |
cp -u /backup/host/*.db /backup/persist/
find /backup/host -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
find /backup/persist -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
image: busybox:latest
imagePullPolicy: IfNotPresent
name: backup-purge
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /backup/host
name: etcd-backup
- mountPath: /backup/persist
name: second-backup
dnsPolicy: ClusterFirst
hostNetwork: true
initContainers:
- command:
- /bin/sh
- -c
- |
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
BACKUP_DIR="/backup/host"
SNAPSHOT_FILE="etcd-snapshot-${DATE}.db"
ARCHIVE_FILE="${SNAPSHOT_FILE}.gz"
etcdctl \
--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 \
snapshot save "${BACKUP_DIR}/${SNAPSHOT_FILE}"
image: bitnami/etcd:latest
imagePullPolicy: IfNotPresent
name: etcd-backup
resources: {}
securityContext:
allowPrivilegeEscalation: false
runAsGroup: 0
runAsUser: 0
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /backup/host
name: etcd-backup
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
readOnly: true
nodeSelector:
node-role.kubernetes.io/control-plane: ""
restartPolicy: OnFailure
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
operator: Exists
volumes:
- hostPath:
path: /data/etcd-backup
type: ""
name: etcd-backup
- hostPath:
path: /etc/kubernetes/pki/etcd
type: Directory
name: etcd-certs
- name: second-backup
persistentVolumeClaim:
claimName: etcd-backup-pvc
schedule: 0 17 * * *
successfulJobsHistoryLimit: 3
suspend: false
timeZone: Asia/Seoul
6. 백업 확인 및 복구
백업이 정상적으로 수행되는지 정기적으로 확인해야 한다:
# 백업 파일 확인
ls -la /data/etcd-backup/
# 백업 파일 무결성 검증
etcdctl snapshot status /data/etcd-backup/etcd-snapshot-<timestamp>.db
# 복구 테스트 (테스트 환경에서만)
etcdctl snapshot restore /data/etcd-backup/etcd-snapshot-<timestamp>.db \
--data-dir=/var/lib/etcd-restore
INFO
백업은 생성하는 것도 중요하지만, 실제로 복구가 가능한지 주기적으로 테스트하는 것이 더욱 중요하다. 테스트 환경에서 정기적으로 복구 테스트를 수행하는 것을 권장한다.