--- title: 04. etcd 장애 실험 시나리오 date: 2026-06-29 type: guide domain: k8s tags: [etcd, raft, quorum, failure-testing] --- ## etcd Raft 쿼럼 기본 원리 ``` 3-node etcd 클러스터: - 쿼럼(과반수) = 2 - 1개 장애: 쿼럼 유지 (2/3 살아있음) → 클러스터 정상 운영 - 2개 장애: 쿼럼 붕괴 (1/3만 살아있음) → 클러스터 읽기 전용 / 쓰기 불가 - 3개 장애: 완전 다운 장애 허용 공식: floor((n-1)/2) 3노드: floor((3-1)/2) = 1개까지 허용 ``` ## 실험 전 준비 ```bash export KUBECONFIG=~/.kube/k8s-etcd-lab.conf # 실험 전 etcd 상태 베이스라인 기록 kubectl get nodes kubectl get pods -n kube-system # etcd 헬스체크 (ctrl1에서) ssh k8s-ctrl1 "sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://203.0.113.11:2379,https://203.0.113.12:2379,https://203.0.113.13:2379 \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/member-k8s-ctrl1.pem \ --key=/etc/ssl/etcd/ssl/member-k8s-ctrl1-key.pem \ endpoint health -w table" ``` --- ## 시나리오 1: 단일 노드 장애 (쿼럼 유지) **목표**: etcd 노드 1개 정지 후 클러스터 운영 영향 확인 ### 장애 주입 ```bash # ctrl3의 etcd 서비스 정지 ssh k8s-ctrl3 "sudo systemctl stop etcd" # 또는 virsh로 VM 자체를 강제 종료 (더 극단적) virsh destroy k8s-ctrl3 ``` ### 관찰 포인트 ```bash # 1. etcd 클러스터 상태 - ctrl1에서 확인 ssh k8s-ctrl1 "sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://203.0.113.11:2379,https://203.0.113.12:2379 \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/member-k8s-ctrl1.pem \ --key=/etc/ssl/etcd/ssl/member-k8s-ctrl1-key.pem \ endpoint health" # → ctrl3은 unreachable, ctrl1+ctrl2는 healthy # 2. K8s 클러스터 - 여전히 정상 동작해야 함 kubectl get nodes kubectl create deployment test-nginx --image=nginx kubectl get pods # 3. API Server 로그에서 etcd 연결 오류 확인 ssh k8s-ctrl1 "sudo journalctl -u kube-apiserver -n 50 | grep etcd" ``` ### 복구 ```bash # etcd 서비스 재시작 ssh k8s-ctrl3 "sudo systemctl start etcd" # 또는 VM 재시작 virsh start k8s-ctrl3 # 멤버 재합류 확인 (자동 재합류됨) ssh k8s-ctrl1 "sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://203.0.113.11:2379 \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/member-k8s-ctrl1.pem \ --key=/etc/ssl/etcd/ssl/member-k8s-ctrl1-key.pem \ member list" ``` --- ## 시나리오 2: 과반수 장애 (쿼럼 붕괴) **목표**: etcd 노드 2개 정지 후 K8s 클러스터가 어떻게 반응하는지 관찰 > 주의: 이 상태에서는 kubectl 명령이 타임아웃됩니다. ### 장애 주입 ```bash # ctrl2, ctrl3 동시 정지 virsh destroy k8s-ctrl2 virsh destroy k8s-ctrl3 ``` ### 관찰 포인트 ```bash # 1. kubectl 응답 불가 확인 kubectl get nodes --request-timeout=10s # → 타임아웃 또는 etcd connection refused # 2. API Server 에러 로그 ssh k8s-ctrl1 "sudo journalctl -u kube-apiserver -f" # → "etcdserver: request timed out" # 3. etcd 자체 상태 (ctrl1에서) ssh k8s-ctrl1 "sudo systemctl status etcd" # → active이지만 리더 없음, no quorum # 4. etcd 내부 로그로 Raft 메시지 확인 ssh k8s-ctrl1 "sudo journalctl -u etcd -n 100 | grep -E 'raft|leader|quorum'" # 5. 기존에 실행 중인 파드는 유지됨 확인 (etcd 없어도 kubelet은 동작) ssh k8s-ctrl1 "sudo crictl ps" ``` ### 복구 ```bash virsh start k8s-ctrl2 virsh start k8s-ctrl3 # etcd 자동 Raft 재동기화 후 쿼럼 복구됨 # 쿼럼 복구 확인 ssh k8s-ctrl1 "sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://203.0.113.11:2379 \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/member-k8s-ctrl1.pem \ --key=/etc/ssl/etcd/ssl/member-k8s-ctrl1-key.pem \ endpoint health" kubectl get nodes ``` --- ## 시나리오 3: etcd 데이터 디렉토리 손상 **목표**: 특정 노드의 etcd 데이터가 손상됐을 때 멤버 제거 후 재추가 ```bash # ctrl3의 etcd 정지 후 데이터 삭제 (손상 시뮬레이션) ssh k8s-ctrl3 "sudo systemctl stop etcd" ssh k8s-ctrl3 "sudo rm -rf /var/lib/etcd/member" # ctrl1에서 ctrl3 멤버 제거 ssh k8s-ctrl1 "sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://203.0.113.11:2379 \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/member-k8s-ctrl1.pem \ --key=/etc/ssl/etcd/ssl/member-k8s-ctrl1-key.pem \ member remove " # ctrl3을 새 멤버로 추가 ssh k8s-ctrl1 "sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://203.0.113.11:2379 \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/member-k8s-ctrl1.pem \ --key=/etc/ssl/etcd/ssl/member-k8s-ctrl1-key.pem \ member add k8s-ctrl3 --peer-urls=https://203.0.113.13:2380" # ctrl3에서 etcd를 새 멤버로 재시작 (initial-cluster-state=existing) # → experiments/04-restore-from-snapshot.sh 참조 ``` --- ## 관찰 도구 정리 | 도구 | 용도 | |------|------| | `etcdctl endpoint health` | 각 멤버 헬스 | | `etcdctl endpoint status` | 리더·commit index 확인 | | `etcdctl member list` | 멤버 목록 | | `journalctl -u etcd -f` | etcd Raft 로그 실시간 | | `journalctl -u kube-apiserver` | API Server etcd 연결 상태 | | `kubectl get events -A` | 클러스터 레벨 이벤트 | | `crictl ps` | kubelet 로컬 컨테이너 (etcd 없어도 동작) | ## etcd 주요 메트릭 (Prometheus) ```bash # etcd 메트릭 엔드포인트 curl -sk https://203.0.113.11:2381/metrics | grep -E "etcd_server_leader|etcd_server_proposals" # 주요 메트릭 # etcd_server_leader_changes_seen_total → 리더 변경 횟수 # etcd_server_proposals_failed_total → 쿼럼 실패 횟수 # etcd_server_has_leader → 리더 존재 여부 (0/1) # etcd_disk_wal_fsync_duration_seconds → 디스크 성능 ```