Skip to Content
BlogEBS 파드가 Terminating에 남았을 때 확인할 것

EBS 파드가 Terminating에 남았을 때 확인할 것

#Kubernetes#EKS#EBS#StatefulSet

노드가 죽었고 StatefulSet 파드는 Terminating에 남았습니다.

새 파드는 뜨지 않고 EBS 볼륨은 이전 노드에 붙어 있습니다.

데이터가 EBS에 살아 있으니 파드만 강제로 지우면 될 것 같지만, 여기서 가장 먼저 할 일은 삭제가 아닙니다.

기존 노드가 정말로 꺼졌는지 확인하는 일입니다.

네트워크만 끊긴 노드에서 프로세스가 여전히 쓰고 있는데 볼륨을 다른 노드에 붙이면 동시 쓰기와 데이터 손상으로 이어질 수 있습니다.

왜 StatefulSet 파드가 남아 있나

노드가 정상적으로 drain되면 kubelet이 파드를 종료하고 볼륨을 unmount합니다.

Attach/Detach controller는 기존 attachment가 정리된 뒤 같은 AZ의 새 노드에 볼륨을 붙입니다.

하드웨어 고장이나 OS hang에서는 kubelet이 이 절차를 끝내지 못합니다.

컨트롤 플레인은 노드와 통신할 수 없으므로 프로세스가 멈췄는지 확신할 수 없습니다.

StatefulSet은 같은 이름의 파드 두 개를 함부로 만들지 않습니다.

RWO 볼륨도 이전 attachment가 남은 동안 새 노드에 붙을 수 없습니다.

결과는 다음처럼 이어집니다.

node-monitor-grace-period ~40s→ 노드 NotReady/unreachable 표시+ unreachable:NoExecute taint기본 toleration 300s(5분)→ 파드 삭제 "요청"StatefulSet+RWO: 파드는 Terminating에종료 확인 불가 시 장시간 잔류 가능force-detach는 6분 후 시도하나CSI 정합성에 따라 지연/보류파드 정리·볼륨 해제가 끝나야 대체 가능heartbeat 중단노드 종료 확인 → out-of-service taint → 같은 AZ 재부착죽은 노드컨트롤 플레인Attach/Detach컨트롤러새 노드(같은 AZ)
비정상 종료 노드에서 파드와 볼륨 정리가 지연되는 경우. 종료가 확인된 노드에 out-of-service taint를 적용하는 복구 경로이며, 시간은 환경과 CSI 상태에 따라 달라집니다.

Kubernetes의 Node Shutdown 문서 도 비정상 종료에서 StatefulSet 파드가 Terminating에 남고 VolumeAttachment가 삭제되지 않을 수 있다고 설명합니다.

이 동작은 느린 failover처럼 보이지만, 살아 있을지 모르는 writer로부터 데이터를 지키는 경계이기도 합니다.

계획된 교체와 급사는 다른 사건이다

두 사건을 같은 런북으로 다루면 위험합니다.

사건노드 상태일반적인 볼륨 경로
계획된 drainkubelet 응답 가능unmount → detach → 새 노드 attach
정상 재부팅같은 노드가 돌아옴기존 attachment와 볼륨 재사용
OS hang·전원 상실kubelet 응답 불가파드 종료와 detach 확인이 지연될 수 있음
네트워크 단절프로세스가 계속 실행 중일 수 있음강제 detach 시 동시 쓰기 위험
AZ 장애볼륨이 해당 AZ에 묶임다른 AZ replica가 필요

EBS 볼륨은 같은 AZ의 새 노드에는 재부착할 수 있습니다.

다른 AZ로 직접 옮겨 붙일 수는 없습니다.

따라서 멀티 AZ 복제를 구성했다고 해도 장애 난 replica의 볼륨은 같은 AZ가 돌아오거나 그 AZ에 대체 노드가 생겨야 재사용할 수 있습니다.

먼저 상태를 모은다

파드 하나만 보지 말고 Node, Pod, PVC, PV, VolumeAttachment를 같은 시간에 봅니다.

kubectl get nodes -o wide kubectl get pods -n clickhouse -o wide kubectl get pvc -n clickhouse kubectl get pv kubectl get volumeattachment

노드 이벤트와 조건을 확인합니다.

kubectl describe node <node-name> kubectl describe pod <pod-name> -n clickhouse kubectl get events -n clickhouse \ --sort-by=.metadata.creationTimestamp

다음 신호를 구분합니다.

신호의미
NotReady / Unknowncontrol plane이 kubelet 상태를 확인하지 못함
Terminating삭제 요청은 생겼지만 노드의 종료 처리가 끝나지 않았을 수 있음
Multi-Attach error이전 attachment가 남아 새 노드 attach가 막힘
VolumeAttachment가 이전 노드를 가리킴detach가 아직 완료되지 않음
EC2 인스턴스가 running네트워크 단절·OS hang 가능성을 더 확인해야 함
EC2 인스턴스가 stopped/terminated비정상 종료 복구 조건에 가까움

Kubernetes의 NotReady만으로 전원이 꺼졌다고 확정할 수 없습니다.

클라우드 인스턴스 상태, 시스템 관리 채널, 하이퍼바이저 신호 같은 외부 근거가 필요합니다.

파드 강제 삭제만으로 부족한 이유

kubectl delete pod --force는 API 객체를 빠르게 지울 수 있습니다.

하지만 이전 노드의 프로세스를 종료하거나 파일시스템을 unmount했다는 보장은 아닙니다.

VolumeAttachment 정리가 남으면 새 파드는 계속 attach에서 막힐 수 있습니다.

더 위험한 경우는 기존 프로세스가 살아 있는데 새 writer까지 시작하는 상황입니다.

그래서 파드 객체와 스토리지 attachment를 따로 봐야 합니다.

kubectl get volumeattachment \ -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,PV:.spec.source.persistentVolumeName,ATTACHED:.status.attached

해당 PV가 어느 노드에 연결됐다고 기록되는지 확인합니다.

AWS에서도 볼륨 상태와 attachment를 교차 확인할 수 있습니다.

aws ec2 describe-volumes \ --volume-ids <volume-id> \ --query 'Volumes[0].{State:State,AZ:AvailabilityZone,Attachments:Attachments}'

out-of-service taint는 언제 쓰나

Kubernetes 1.28부터 non-graceful node shutdown 처리는 stable입니다.

종료된 노드에 node.kubernetes.io/out-of-service taint를 붙이면, 이를 tolerate하지 않는 파드를 강제 삭제하고 해당 파드의 볼륨 detach를 즉시 진행할 수 있습니다.

kubectl taint nodes <dead-node> \ node.kubernetes.io/out-of-service=nodeshutdown:NoExecute

이 명령은 일반적인 “NotReady 노드 정리” 명령이 아닙니다.

공식 문서도 노드가 재부팅 중이 아니라 이미 shutdown 또는 power off 상태임을 먼저 확인하라고 명시합니다.

적용 조건을 체크리스트로 만들면 다음과 같습니다.

  • 인스턴스가 실제로 중지 또는 종료됐다는 외부 근거가 있습니다.
  • 단순 API server 연결 문제나 네트워크 partition이 아닙니다.
  • 노드가 재부팅 중이며 곧 돌아올 상황이 아닙니다.
  • 해당 볼륨을 사용하는 다른 프로세스가 기존 노드에서 실행 중이지 않습니다.
  • 대체 파드가 배치될 같은 AZ에 노드 용량이 있습니다.
  • 남은 ClickHouse replica가 서비스와 catch-up을 감당할 수 있습니다.

복구된 노드를 다시 쓸 때는 taint를 제거합니다.

kubectl taint nodes <dead-node> \ node.kubernetes.io/out-of-service=nodeshutdown:NoExecute-

노드가 영구 폐기됐다면 리소스 정리 정책에 따라 Node 객체를 제거하는 경로를 검토합니다.

시간 숫자를 복구 상한으로 더하지 않는다

노드 monitor grace period, 기본 NoExecute toleration, force-detach timeout 같은 숫자가 보입니다.

이 값을 단순히 더해 “몇 분이면 반드시 복구된다”고 계산하면 안 됩니다.

클러스터 설정과 Kubernetes 버전, CSI 구현, 파드의 toleration, controller 상태에 따라 달라집니다.

공식 문서는 unhealthy node에서 파드 삭제가 6분 동안 성공하지 않으면 force detach할 수 있는 동작도 설명합니다.

동시에 기존 workload가 실제로 실행 중이면 CSI 계약 위반과 데이터 손상이 생길 수 있다고 경고합니다.

그래서 운영 목표는 타이머를 외우는 것이 아니라 각 구간을 측정하는 것입니다.

감지 → 노드 종료 판별 → 파드 정리 → 볼륨 detach → 같은 AZ 대체 노드 attach → ClickHouse 시작 → part 로드 → replica delta catch-up → Ready

ClickHouse는 재부착 뒤에도 바로 Ready가 아니다

EBS가 살아 있으면 로컬 NVMe처럼 모든 데이터를 다시 받을 필요는 없습니다.

그렇다고 attach 완료가 서비스 복구 완료는 아닙니다.

ClickHouse는 기존 part를 읽고 검증하며, 중단 중 생긴 변경분을 다른 replica에서 가져와야 합니다.

SELECT database, table, is_readonly, is_session_expired, queue_size, inserts_in_queue, merges_in_queue, absolute_delay, total_replicas, active_replicas FROM system.replicas ORDER BY absolute_delay DESC;

replication queue의 반복 실패도 봅니다.

SELECT database, table, type, create_time, num_tries, last_exception FROM system.replication_queue WHERE num_tries > 0 ORDER BY create_time;

active_replicas가 원래 RF로 돌아오고 queue와 delay가 안정화돼야 복구가 끝났다고 볼 수 있습니다.

PDB가 막아주는 범위

PDB는 Eviction API를 사용하는 계획된 중단에서 동시에 unavailable해질 파드 수를 제한합니다.

노드 급사, 전원 상실, AZ 장애를 막지 않습니다.

Kubernetes의 drain 문서 처럼 계획된 작업에서는 drain이 PDB와 graceful termination을 따릅니다.

급사 리허설은 별도로 해야 합니다.

리허설확인할 것
cordon + drainPDB, graceful shutdown, 정상 detach
인스턴스 stop노드 감지, 재부팅과 영구 소실 판별
강제 종료Terminating, VolumeAttachment, out-of-service 경로
AZ 차단 가정다른 AZ replica로 읽기·쓰기 지속 여부

런북의 시작은 판별이다

EBS 기반 ClickHouse의 장점은 볼륨이 살아 있으면 같은 AZ의 새 노드에 다시 붙일 수 있다는 것입니다.

그 장점을 얻으려다 기존 writer와 새 writer를 동시에 만드는 것이 가장 위험합니다.

따라서 런북의 첫 줄은 “파드를 지운다”가 아니라 다음 문장이어야 합니다.

노드가 정말로 꺼졌고 돌아오는 중이 아님을 두 개 이상의 독립 신호로 확인한다.

그다음에 out-of-service taint, detach, attach, ClickHouse catch-up 순서로 진행합니다.

복구 시간은 이 전체 경로를 staging에서 반복해서 재야 알 수 있습니다.

자료 확인 기준: 2026-09-15. 클러스터의 Kubernetes 버전, EBS CSI 드라이버, cloud-controller-manager 설정에 따라 세부 타이밍과 자동 처리 범위가 달라질 수 있습니다.