1. 배경
쿠버네티스는 클러스터에 대한 대부분의 정보를 저장하기 위해 ETCD를 사용합니다. 그렇기 때문에 클러스터를 안전하게 운영하기 위해서 ETCD의 백업은 필수 입니다. 이전에도 대규모 클러스터를 운영하면서, 원인 모를 클러스터 이상이 발생하였을 때도, ETCD백업이 구성되어 있어, 빠른 시간에 복구를 함으로서 이에 대한 중요함을 느낀 적이 있습니다. 이를 위하여 백업과 복구하는 방법에 대해 정리합니다.
테스트를 진행하는 환경은 Ubuntu 서버에 클러스터가 구성되어있는 멀티 마스터 구조입니다. 또한 ETCD는 파드로 설치되어 데몬으로 설치되어있을 때와 파일의 경로가 다를 수 있습니다.
2. ETCDCTL 설치 및 초기 설정
ETCD가 데몬으로 설치되어있을 경우 기본적으로 ETCDCTL은 같이 설치됩니다. 하지만 저는 파드로 클러스터를 구성했기 때문에 설치를 진행 합니다. ETCDCTL만 따로 설치할 수 없기 때문에 etcd를 서버에 설치합니다.
Github의 Release를 참조합니다.
ETCD_VER=v3.5.9
# choose either URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
/tmp/etcd-download-test/etcd --version
/tmp/etcd-download-test/etcdctl version
/tmp/etcd-download-test/etcdutl version
설치가 완료되면 다음과 같이 etcdctl을 복사한 후 설치를 확인합니다.
하지만 설치한 후 etcdctl member list 로 조회시 정상적으로 조회가 되지 않습니다. ETCD가 secured 모드로 설치 되어있기 때문에 인증을 위한 키를 입력해야합니다.
저는 이를 alias로 설정하여 사용하도록 변경하였습니다. 추가로 주어야 되는 파라미터는 —cacert, —cert, —key,--endpoints
옵션 입니다. 다음과 같이 alias를 설정한 후 통신을 시도합니다.
alias etcdctl='etcdctl --endpoints=172.31.30.247:2379,172.31.21.9:2379,172.31.27.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key'
이후 endpoint 조회시 다음과 같이 정상적으로 통신 되는 것을 확인 할 수 있습니다.
3. Snapshot 생성하기
etcd 클러스터로 구성 할 경우 각 노드의 데이터가 유지되고 동기화 되기 때문에 각 노드에서 모두 스냅샷을 생성할 필요는 없습니다. 클러스터 중 하나의 노드에서만 스냅샷을 생성해도 되지만, 해당 노드가 문제가 발생하였을 경우 스냅샷이 생성되지 않을 수 있기 때문에 이를 고려하여 스냅샷을 생성할 노드의 개수를 정해야됩니다. 저는 테스트를 위해 한 곳에서만 스냅샷을 생성하도록 하였습니다. 또한 스냅샷 생성 후 동일한 파일을 각 클러스터에서 백업할 때 사용해야 하기 때문에 파일이 공유되는 곳에 저장해야됩니다.
백업 및 복구가 제대로 되는 지 확인 하기 위해 파드를 생성합니다.
snapshot의 경우 etcdctl로 간단하게 생성할 수 있습니다 . etcdctl snapshot save
커맨드를 이요해 생성합니다.
다만, 이전에 alias를 통해 endpoint를 지정하였는데, snpashot 생성시 단일 endpoint를 지정해야되기 때문에 alias를 해제하고 수동으로 커맨드를 실행합니다. 만약 해제를 안할 경우 다음과 같은 에러가 발생 할 수 있습니다.
Snapshot 파일 확인
3. ETCD Restore
이제 생성된 스냅샷으로 복구하기 위하여 생성되어 있는 nginx 파드를 모드 지웁니다. 복구 이후 파드가 생성되어있으면, 복구가 정상적으로 이루어진 것으로 판단 할 수 있습니다.
Restore의 경우 다음과 같은 과정으로 모든 마스터 노드에서 이루어집니다.
- Kubernetes Static Pod 및 ETCD 중지
- ETCD Restore
- Kubernetes Static Pod 및 ETCD 재시작
이를 위해 Static 파드 및 ETCD를 중지합니다. 저는 단순히 Static Pod 매니페스트 파일의 위치를 옮겨서 중지 시켰습니다. 또한 ETCD가 파드로 생성되어있기 때문에 따로 중지할 필요 없습니다. 데몬으로 설치한 경우 systemctl stop etcd
로 중지해야합니다.
이후 각 마스터 노드에서 restore를 진행합니다.
etcdctl snapshot restore /data/backup/20231114-snapshot.db \
--name master1 --initial-cluster master1=https://172.31.30.247:2380,master2=https://172.31.21.9:2380,master3=https://172.31.27.1:2380 \
--initial-advertise-peer-urls=https://172.31.30.247:2380 \
--data-dir=/var/lib/etcd-new \
--initial-cluster-token etcd-cluster-1
etcdctl snapshot restore /data/backup/20231114-snapshot.db \
--name master2 --initial-cluster master1=https://172.31.30.247:2380,master2=https://172.31.21.9:2380,master3=https://172.31.27.1:2380 \
--initial-advertise-peer-urls=https://172.31.21.9:2380 \
--data-dir=/var/lib/etcd-new \
--initial-cluster-token etcd-cluster-1
etcdctl snapshot restore /data/backup/20231114-snapshot.db \
--name master3 --initial-cluster master1=https://172.31.30.247:2380,master2=https://172.31.21.9:2380,master3=https://172.31.27.1:2380 \
--initial-advertise-peer-urls=https://172.31.27.1:2380 \
--data-dir=/var/lib/etcd-new \
--initial-cluster-token etcd-cluster-1
각 옵션은 다음과 같은 의미를 같습니다.
initial-advertise-peer-urls
: 복원을 진행하는 노드의 경로를 입력하여 클러스터에 자신의 정보를 공유할 때 사용합니다.--initial-cluster
: 초기 클러스터를 구성할 때의 내용과 동일한 구성으로 이루어지며, 클러스터에 대한 정보를 나타냅니다.—data-dir
: ETCD 복구 후 저장되는 데이터의 경로를 나타냅니다. 설정하지 않을 경우 Overwrite되며, 기본 값은/var/lib/etcd
입니다.—initial-cluster-token
: ETCD 클러스터를 식별하는 토큰입니다. 멀티 클러스터에서 구분을 위해 사용되며, 각 노드에서 동일한 값이 입력되어야합니다.
저는 —data-dir 옵션으로 데이터를 따로 지정하였기 때문에 etcd가 해당 경로를 바라보도록 수정해야합니다.
#etcd.yml
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://172.31.30.247:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd-new
...
volumeMounts:
- mountPath: /var/lib/etcd-new
name: etcd-data
...
- hostPath:
path: /var/lib/etcd-new
type: DirectoryOrCreate
name: etcd-data
이후 정상적으로 복구가 완료되면 지웠던 nginx 파드가 생성된 것을 확인 할 수 있습니다.
4. ETCD CronJob 생성
위의 과정을 바탕으로 CronJob을 생성하여 12시마다 백업을 생성하도록 설정합니다. cronJob 생성을 위한 과정은 다음 링크를 참조하였습니다. 저는 해당 링크의 Dockerfile을 바탕으로 ETCDCTl이 설치된 이미지를 만든 후 프라이빗 레포에 넣은 후 사용하였습니다.
apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-backup
spec:
schedule: "0 12 * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
concurrencyPolicy: Allow
timeZone: Asia/Seoul
jobTemplate:
spec:
template:
spec:
containers:
- name: etcd-backup
image: seokbin9023/etcd-backup
imagePullPolicy: Always
env:
- name: ETCDCTL_API
value: "3"
- name: ETCDCTL_ENDPOINTS
value: "https://172.31.30.247:2379"
- name: ETCDCTL_CACERT
value: "/etc/kubernetes/pki/etcd/ca.crt"
- name: ETCDCTL_CERT
value: "/etc/kubernetes/pki/etcd/server.crt"
- name: ETCDCTL_KEY
value: "/etc/kubernetes/pki/etcd/server.key"
command: ["/bin/bash","-c"]
args: ["etcdctl snapshot save /data/etcd-backup/etcd-snapshot-$(date +%Y-%m-%dT%H:%M).db"]
volumeMounts:
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
readOnly: true
- mountPath: /data/etcd-backup
name: etcd-backup
restartPolicy: OnFailure
hostNetwork: true
nodeSelector:
kubernetes.io/hostname: master01
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
operator: Exists
volumes:
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
type: Directory
- name: etcd-backup
hostPath:
path: /data/etcd-backup
type: DirectoryOrCreate
위의 내용을 살펴보면, nodeSelector와 Toleration 을 이용해 master1번에서 잡이 실행되도록 하고, /data/etcd-backup 경로에 스냅샷이 생성되도록 하였습니다.