Kubernetes와 ETCD 백업 복구
클러스터 운영 실습 중에 Kubernetes control plane의 ETCD 스냅샷으로 상태를 백업하고 복구하기
현재 제가 개발하고 있는 서비스는 VM(Virtual Machine)에 Kubeadm으로 구축한 Kubernetes 클러스터에 배포되어 있습니다.
저는 장애에 대비해 클러스터를 복구할 수 있도록 백업을 수행하고 싶었습니다.
물론 저는 GitOps를 통해 코드형 인프라(Infrastructure as Code, IaC)를 구현했으므로 큰 걱정은 없었으나, 제가 수동으로 배포한 리소스들을 생각하면 백업이 필요했습니다.
그래서 백업할 수 있는 방법을 찾다가 ETCD 스냅샷을 활용하는 방식을 확인했습니다.
ETCD
ETCD는 분산형 Key-Value 저장소입니다.
비슷한 Key-Value 저장소인 Redis처럼 조회 성능이 좋아서 메타 데이터 등의 작은 크기의 데이터를 다루는데 적합합니다.
etcdctl set <key> <value>ETCD는 함께 제공되는 CLI(Command Line Interface)인 etcdctl을 통해 다룰 수 있습니다.
Kubernetes에서의 ETCD
Kubernetes에서 ETCD는 컨트롤 플레인의 컴포넌트 중 하나로, 클러스터 내의 상태 정보를 저장합니다.
kubectl로 조회하는 리소스 상태도 결국 API Server를 거쳐 ETCD에 저장된 데이터를 기반으로 합니다.
따라서 ETCD 스냅샷은 클러스터 상태를 복구하는 핵심 백업 자료가 됩니다.
kubectl get pods -n kube-systemNAME READY STATUS RESTARTS AGE
coredns-5d78c9869d-6b6zd 1/1 Running 0 12m
coredns-5d78c9869d-8szh6 1/1 Running 0 12m
etcd-controlplane 1/1 Running 0 12m
kube-apiserver-controlplane 1/1 Running 0 12m
kube-controller-manager-controlplane 1/1 Running 0 12m
kube-proxy-crxgd 1/1 Running 0 12m
kube-scheduler-controlplane 1/1 Running 0 12mKubeadm 기반 클러스터에서 ETCD는 kube-system 네임스페이스에 Static Pod로 배포되므로 /etc/kubernetes/manifests에 있는 etcd.yaml을 통해 설정 정보를 확인할 수 있습니다.
apiVersion: v1
kind: Pod
metadata:
...
spec:
containers:
name: etcd
image: registry.k8s.io/etcd:3.5.7-0
- command:
- etcd
- --advertise-client-urls=https://192.12.77.3:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --experimental-initial-corrupt-check=true
- --experimental-watch-progress-notify-interval=5s
- --initial-advertise-peer-urls=https://192.12.77.3:2380
- --initial-cluster=controlplane=https://192.12.77.3:2380
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://192.12.77.3:2379
- --listen-metrics-urls=http://127.0.0.1:2381
- --listen-peer-urls=https://192.12.77.3:2380
- --name=controlplane
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-client-cert-auth=true
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --snapshot-count=10000
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
...매니페스트(Manifest)의 내용을 보면 ETCD가 마운트(Mount)하고 있는 디렉토리와 ETCD의 엔드포인트, 서버 인증서 경로 등을 알 수 있습니다.
이 정보를 통해 현재 ETCD 데이터를 스냅샷(Snapshot)으로 저장할 수 있습니다.
클러스터 백업
export ETCDCTL_API=3
etcdctl versionetcdctl version: 3.3.13
API version: 3.3백업을 하기 전에 etcdctl의 API 버전을 3 이상으로 설정해야 합니다.
etcdctl snapshot save <snapshot_path>그 다음, 위 명령어로 스냅샷을 생성해 특정 경로에 저장합니다.
이때, 추가 인자로 CA(Certificate Authority) 인증서, 서버 인증서, Private Key가 필요합니다.
이에 대해서는 앞서 보았던 ETCD 매니페스트의 정보를 활용할 수 있습니다.
etcdctl snapshot save --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key /opt/snapshot.dbls /optcni containerd snapshot.db명령을 실행하면 /opt/snapshot.db가 생성된 것을 볼 수 있습니다.
클러스터 복구
kubectl get allNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m47s클러스터 복구 테스트를 위해 default 네임스페이스에 존재하는 Deployment, Pod 등의 모든 오브젝트를 삭제했습니다.
etcdctl snapshot restore <snapshot_path>백업과 마찬가지로, etcdctl을 통해 스냅샷을 가지고 클러스터를 복구할 수 있습니다.
이때, 추가 인자로 복구할 데이터를 저장할 디렉토리를 지정할 수 있습니다.
etcdctl snapshot restore --data-dir /var/lib/etcd-from-backup /opt/snapshot-pre-boot.dbls /var/libapt cni dbus dpkg etcd-from-backup git kubelet misc pam private rancher systemd vim
buildkit containerd docker etcd gems k0s man-db PackageKit polkit-1 python sudo ucf명령을 실행하면 /var/lib/etcd-from-backup이 생성된 것을 볼 수 있습니다.
apiVersion: v1
kind: Pod
metadata:
...
spec:
containers:
...
volumeMounts:
- mountPath: /var/lib/etcd-from-backup
name: etcd-data
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
...마지막으로 ETCD 매니페스트에서 기존에 마운트하던 데이터 디렉토리를 복원한 데이터 디렉토리로 바꿔야 합니다.
이렇게 하면 ETCD가 복원된 데이터를 참조하고, Kubelet이 Static Pod 변경을 감지해 클러스터에 반영합니다.
kubectl get allNAME READY STATUS RESTARTS AGE
pod/blue-6b478c8dbf-2pxxs 1/1 Running 0 47m
pod/blue-6b478c8dbf-bjqwm 1/1 Running 0 47m
pod/blue-6b478c8dbf-wcqww 1/1 Running 0 47m
pod/red-6684f7669d-7cqct 1/1 Running 0 47m
pod/red-6684f7669d-cvmg4 1/1 Running 0 47m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/blue-service NodePort 10.98.76.47 <none> 80:30082/TCP 47m
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 50m
service/red-service NodePort 10.97.154.230 <none> 80:30080/TCP 47m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/blue 3/3 3 3 47m
deployment.apps/red 2/2 2 2 47m
NAME DESIRED CURRENT READY AGE
replicaset.apps/blue-6b478c8dbf 3 3 3 47m
replicaset.apps/red-6684f7669d 2 2 2 47m모든 오브젝트를 조회해보면 클러스터가 복구가 된 것을 확인할 수 있습니다.