削除事故をスナップショットで戻す
한국어 원문으로 표시합니다.
목표
실제로 오브젝트를 지운 뒤 스냅샷에서 되살려 봅니다. 복구된 데이터 디렉터리로 두 번째 etcd 를 직접 띄워 "정말 돌아왔다"를 눈으로 확인합니다.
왜 중요한가
복구 절차를 문서로만 아는 것과 한 번 해 본 것의 차이는 큽니다. 특히 snapshot restore 가 데이터를 되돌리는 명령이 아니라 새 etcd 클러스터를 만드는 명령이라는 사실은 손으로 해 봐야 몸에 남습니다. 그래서 --name, --initial-cluster, --initial-advertise-peer-urls, --initial-cluster-token 같은 신원 플래그를 요구하고, --data-dir 로 비어 있는 새 경로를 요구합니다. 기존 /var/lib/etcd 를 그대로 주는 순간 살아 있는 데이터를 건드리게 됩니다. 또 하나 중요한 것이 순서입니다. 스냅샷을 먼저 검증하고, apiserver 를 멈춰 쓰기를 끊고, 복구하고, 매니페스트의 hostPath 를 새 경로로 바꾸고, 마지막에 kubectl 로 확인합니다. 이 순서를 뒤집으면 못 쓰는 스냅샷으로 클러스터를 세우거나, 복구 중에 들어온 쓰기를 잃거나, 옛 데이터로 다시 뜨는 일이 벌어집니다. 이 랩에서는 라이브 클러스터를 멈추지 않고 별도 포트에 복구본을 띄워 같은 결론에 도달합니다.
단계
- 네임스페이스
etcd-lab과 그 안의 ConfigMapetcd-lab-marker(data.owner=platform)를 만드세요. 그다음/root/etcd/restore/out/pre.json에 사고 전 상태를 JSON 으로 기록하세요. 키는marker_owner(값platform),registry_keys(/registry아래 키 개수, 20 이상),revision(현재 etcd revision, 0보다 큼) 세 개입니다. - 복구에 쓸 스냅샷을
/root/etcd/restore/before.db로 뜨고(20000 바이트 이상), 검증 결과를 JSON 으로/root/etcd/restore/out/before.json에 저장하세요.revision이 0보다 커야 합니다. - ConfigMap
etcd-lab-marker를 삭제해 사고를 재현하세요. 삭제 후 그 오브젝트를 조회한 출력을/root/etcd/restore/out/gone.txt에 남기세요. 파일에NotFound또는not found같은 "없다"는 응답이 들어 있어야 하고, 라이브 클러스터에는 이 ConfigMap 이 다시 생기면 안 됩니다. before.db를/root/etcd/restore/data로 복구하세요. 복구 후/root/etcd/restore/data/member/snap/db와/root/etcd/restore/data/member/wal이 생겨야 합니다. 복구 명령의 출력(표준 오류 포함)을/root/etcd/restore/out/restore.txt에 저장하세요.- 이번에는 신원 플래그를 모두 붙여
/root/etcd/restore/data2로 한 번 더 복구하세요.--data-dir,--name,--initial-cluster,--initial-advertise-peer-urls,--initial-cluster-token다섯 플래그가 모두 들어가야 하며, 이름은restored, 피어 주소는http://127.0.0.1:12380, 토큰은etcd-restore-lab로 하세요. 실제로 실행한 명령 전체를/root/etcd/restore/out/restore-cmd.txt에 그대로 남기세요(--data-dir에/var/lib/etcd를 적으면 안 됩니다). /root/etcd/restore/data2를 데이터 디렉터리로 하는 두 번째 etcd 프로세스를 백그라운드로 띄우세요. 클라이언트 주소는http://127.0.0.1:12379, 피어 주소는http://127.0.0.1:12380, 이름은restored, 초기 멤버는restored=http://127.0.0.1:12380, 토큰은etcd-restore-lab입니다. 채점이 끝날 때까지 이 프로세스를 종료하지 마세요. 기동에 쓴 명령을/root/etcd/restore/out/second-etcd.txt에 저장하세요(파일에12379와--data-dir이 보여야 합니다).- 복구본에서
/registry/configmaps/etcd-lab/etcd-lab-marker키를 읽어 값에platform이 들어 있는지 확인하고, 그 출력을/root/etcd/restore/out/recovered.txt에 저장하세요. 조회 대상은127.0.0.1:12379이며, 라이브 클러스터(2379)에는 이 오브젝트가 여전히 없어야 합니다. /root/etcd/restore/runbook.md에 복구 런북을 400바이트 이상으로 쓰세요. 각 단계는 서로 다른 줄에 두고 아래 순서를 지켜야 합니다. (1) 스냅샷 검증(snapshot status), (2)kube-apiserver중지, (3)snapshot restore, (4) etcd 매니페스트의hostPath/data-dir을 새 경로로 교체, (5)kubectl get으로 확인. 마지막에 복구가 실패했을 때의 롤백 방법도 반드시 적으세요.
참고
- 스냅샷 검증과 복구는
etcdutl이 표준입니다.command -v etcdutl로 먼저 확인해 있으면etcdutl snapshot status/etcdutl snapshot restore를 쓰고, 없으면etcdctl의 같은 하위 명령으로 대체하세요(경고가 붙지만 동작합니다). - etcd 서버 실행 파일은 별개입니다.
command -v etcd로 먼저 찾고, 없으면find "$HOME/.kwok" -name etcd -type f로 찾으세요(kwokctl 이 내려받은 바이너리가 그 아래에 있습니다). 백그라운드 기동은nohup <etcd 경로> <플래그들> > /root/etcd/restore/out/second-etcd.log 2>&1 &형태가 편합니다. - 두 번째 etcd 의 포트를 라이브 etcd(2379/2380)와 겹치게 하면 기동에 실패합니다. 반드시 12379/12380 을 쓰고, 6·7번을 채점받을 때까지 프로세스를 살려 두세요.
- 복구 로그와
kubectl의 NotFound 메시지는 모두 표준 오류로 나갑니다.명령 > 파일 2>&1또는명령 2>&1 | tee 파일로 받아야 파일에 남습니다. - etcd 에 저장된 값은 protobuf 라 그대로 보면 깨져 보입니다.
| tr -d '\0'로 널 바이트만 걷어 내면 안에 든 문자열은 그대로 읽힙니다. - 흔한 실수 1: 8번 런북에서
etcdctl snapshot restore --data-dir ...을 한 줄에 쓰는 것. 그러면snapshot restore와data-dir이 같은 줄이 되어 순서 검사에 걸립니다. 여러 줄로 나누거나 hostPath 교체를 별도 항목으로 두세요. 같은 이유로 문서 앞부분에서data-dir,kubectl get,kube-apiserver를 미리 언급하지 마세요 — 각 단어의 첫 등장 위치로 순서를 판정합니다. - 흔한 실수 2: 3번에서 라이브 클러스터의 ConfigMap 을 다시 만들어 버리는 것. 이 실습의 결론은 "복구본에서만 되살아난다"입니다.
- 실습 파드는 실습마다 새로 뜨므로 앞 실습에서 만든
etcd-lab네임스페이스와 마커는 남아 있지 않습니다. 1번에서 직접 만들고 시작하세요. 운영 절차를 기억이 아니라 런북과 매니페스트로 남겨야 하는 이유가 바로 이것입니다.
사고 전 상태를 숫자로 기록하기
네임스페이스 etcd-lab 과 그 안의 ConfigMap etcd-lab-marker(data.owner=platform)를 만드세요. 그다음 /root/etcd/restore/out/pre.json 에 사고 전 상태를 JSON 으로 기록하세요. 키는 marker_owner(값 platform), registry_keys(/registry 아래 키 개수, 20 이상), revision(현재 etcd revision, 0보다 큼) 세 개입니다.
복구는 '무엇이 있었는지'를 아는 데서 시작합니다. 마커 값, /registry 키 개수, 현재 revision 세 가지를 JSON 하나로 묶으세요. revision 은 endpoint status 의 헤더에 있습니다.
복구에 쓸 스냅샷 확보하고 검증하기
복구에 쓸 스냅샷을 /root/etcd/restore/before.db 로 뜨고(20000 바이트 이상), 검증 결과를 JSON 으로 /root/etcd/restore/out/before.json 에 저장하세요. revision 이 0보다 커야 합니다.
복구용 스냅샷은 뜨자마자 검증합니다. 사고가 난 다음에 파일이 깨졌다는 사실을 알면 이미 늦습니다.
삭제 사고 재현하고 흔적 남기기
ConfigMap etcd-lab-marker 를 삭제해 사고를 재현하세요. 삭제 후 그 오브젝트를 조회한 출력을 /root/etcd/restore/out/gone.txt 에 남기세요. 파일에 NotFound 또는 not found 같은 "없다"는 응답이 들어 있어야 하고, 라이브 클러스터에는 이 ConfigMap 이 다시 생기면 안 됩니다.
오브젝트를 지우고 조회해 보세요. 없는 리소스 조회는 표준 오류로 메시지가 나가므로 리다이렉션에 표준 오류를 함께 넣어야 파일에 남습니다.
스냅샷을 새 데이터 디렉터리로 복구하기
before.db 를 /root/etcd/restore/data 로 복구하세요. 복구 후 /root/etcd/restore/data/member/snap/db 와 /root/etcd/restore/data/member/wal 이 생겨야 합니다. 복구 명령의 출력(표준 오류 포함)을 /root/etcd/restore/out/restore.txt 에 저장하세요.
복구는 기존 경로를 덮는 것이 아니라 새 경로를 만드는 일입니다. 복구 로그도 표준 오류로 나갑니다. 결과 디렉터리 안에 member 구조가 생겼는지 보세요.
클러스터 신원 플래그를 붙여 다시 복구하기
이번에는 신원 플래그를 모두 붙여 /root/etcd/restore/data2 로 한 번 더 복구하세요. --data-dir, --name, --initial-cluster, --initial-advertise-peer-urls, --initial-cluster-token 다섯 플래그가 모두 들어가야 하며, 이름은 restored, 피어 주소는 http://127.0.0.1:12380, 토큰은 etcd-restore-lab 로 하세요. 실제로 실행한 명령 전체를 /root/etcd/restore/out/restore-cmd.txt 에 그대로 남기세요(--data-dir 에 /var/lib/etcd 를 적으면 안 됩니다).
restore 는 사실 '새 클러스터를 하나 만드는' 명령입니다. 이름, 초기 멤버 목록, 피어 주소, 토큰 네 가지를 명시하면 뒤이어 그 데이터로 etcd 를 띄울 수 있습니다.
복구본으로 두 번째 etcd 띄우기
/root/etcd/restore/data2 를 데이터 디렉터리로 하는 두 번째 etcd 프로세스를 백그라운드로 띄우세요. 클라이언트 주소는 http://127.0.0.1:12379, 피어 주소는 http://127.0.0.1:12380, 이름은 restored, 초기 멤버는 restored=http://127.0.0.1:12380, 토큰은 etcd-restore-lab 입니다. 채점이 끝날 때까지 이 프로세스를 종료하지 마세요. 기동에 쓴 명령을 /root/etcd/restore/out/second-etcd.txt 에 저장하세요(파일에 12379 와 --data-dir 이 보여야 합니다).
복구한 데이터 디렉터리를 실제 프로세스에 물려야 확인이 됩니다. 클라이언트·피어 포트를 라이브 etcd 와 겹치지 않게 하고, 채점이 끝날 때까지 프로세스를 살려 두세요.
지워진 오브젝트가 복구본에 살아 있는지 확인하기
복구본에서 /registry/configmaps/etcd-lab/etcd-lab-marker 키를 읽어 값에 platform 이 들어 있는지 확인하고, 그 출력을 /root/etcd/restore/out/recovered.txt 에 저장하세요. 조회 대상은 127.0.0.1:12379 이며, 라이브 클러스터(2379)에는 이 오브젝트가 여전히 없어야 합니다.
쿠버네티스 오브젝트의 etcd 키는 /registry/<종류>/<네임스페이스>/<이름> 입니다. 값은 protobuf 라 사람이 읽기 어렵지만 문자열은 그대로 보입니다.
복구 런북 쓰기
/root/etcd/restore/runbook.md 에 복구 런북을 400바이트 이상으로 쓰세요. 각 단계는 서로 다른 줄에 두고 아래 순서를 지켜야 합니다. (1) 스냅샷 검증(snapshot status), (2) kube-apiserver 중지, (3) snapshot restore, (4) etcd 매니페스트의 hostPath/data-dir 을 새 경로로 교체, (5) kubectl get 으로 확인. 마지막에 복구가 실패했을 때의 롤백 방법도 반드시 적으세요.
새벽 3시에 읽을 문서입니다. 단계 순서가 중요하고, 실패했을 때 어디로 돌아갈지도 적어야 합니다.