FailedAttachVolume — 삭제된 EBS 볼륨 복구

Kubernetes3분조회 –

어제까지 잘 쓰던 파드가 갑자기 안 떴는데, 배포한 것도 없고 노드도 그대로라 파드가 스스로 달라졌을 리는 없었습니다. 그러면 볼륨을 붙이는 쪽이 의심스러우니 이벤트부터 열었습니다.

데이터를 디스크에 두고 쓰는 워크로드라 파드마다 PVC 가 하나씩 붙어 있습니다. 그 PVC 가 PV(PersistentVolume)를 잡고, PV 는 다시 AWS EBS 볼륨 하나를 가리킵니다. 쿠버네티스 쪽 오브젝트와 AWS 쪽 실제 볼륨이 두 겹으로 이어진 구조입니다.

이 두 겹은 파드가 뜰 때마다 다시 쓰여서, 파드가 스케줄되면 컨트롤러가 PV 에 적힌 볼륨 ID 를 보고 그 노드에 EBS 를 붙이고, 붙고 나서야 컨테이너가 시작합니다.

원인 — 존재하지 않는 EBS 볼륨

Warning FailedAttachVolume  attachdetach-controller
AttachVolume.Attach failed for volume "pvc-xxxx":
  rpc error: code = Internal desc = Could not attach volume "vol-xxxx" to node "i-xxxx":
  api error InvalidVolume.NotFound: The volume 'vol-xxxx' does not exist.

InvalidVolume.NotFound 니까, PV 는 여전히 어떤 EBS 볼륨을 가리키고 있지만 그 볼륨이 AWS 에서는 이미 지워져 있었습니다. 두 겹 참조 중 아래쪽이 끊어진 상태라 쿠버네티스가 보기에는 정상인 PV 가 붙일 대상이 없는 껍데기가 된 겁니다. 무엇이 지웠는지는 CloudTrail 보존 기간을 이미 넘긴 뒤라 끝내 특정하지 못했습니다.

파드는 스케줄까지는 되지만 볼륨을 못 붙여서 컨테이너를 시작하지 못하고 FailedAttachVolume 을 반복하며 무한히 대기합니다. 재시도로 풀릴 종류가 아니라 붙일 볼륨을 만들어 주기 전까지는 그대로입니다.

volumeHandle은 immutable — PV를 새로 만들어야 함

복구가 조금 번거로운 건 PV 의 volumeHandle, 그러니까 실제 EBS 볼륨 ID 를 적어 둔 필드가 immutable 이기 때문입니다. 기존 PV 에서 볼륨 ID 만 새 걸로 갈아 끼울 수 없어서 볼륨을 새로 만들고 PV 자체를 지웠다 다시 만들어야 합니다.

새 볼륨 생성 — 크기·타입·가용영역 맞추기

원래 볼륨과 같은 크기, 같은 타입, 같은 가용영역으로 만듭니다. 가용영역이 특히 중요한데, EBS 볼륨은 존을 넘어가지 못해서 다른 존에 만들면 그 노드에 아예 붙지 않습니다.

NEW_VOL=$(aws ec2 create-volume \
  --region ap-northeast-2 --availability-zone ap-northeast-2c \
  --volume-type gp3 --size 55 --iops 3000 \
  --query 'VolumeId' --output text)

aws ec2 wait volume-available --region ap-northeast-2 --volume-ids $NEW_VOL

새로 만든 볼륨이라 안은 비어 있습니다. 데이터가 든 원래 볼륨이 지워진 상황이라 스냅샷이 없으면 내용은 되살릴 수 없고 여기서 목표는 볼륨을 다시 붙여 파드를 띄우는 데까지입니다.

PV 재생성 — reclaimPolicy는 Retain

apiVersion: v1
kind: PersistentVolume
metadata:
  name: <pv-name>
spec:
  accessModes: [ReadWriteOnce]
  capacity:
    storage: 55Gi
  csi:
    driver: ebs.csi.aws.com
    fsType: ext4
    volumeHandle: <NEW_VOL>       # 새 볼륨 ID
  persistentVolumeReclaimPolicy: Retain
  volumeMode: Filesystem

persistentVolumeReclaimPolicy 를 Retain 으로 둔 건 앞으로 PV 를 지우더라도 볼륨은 남기기 위해서입니다. 동적으로 만들어진 PV 는 StorageClass 를 따라 Delete 가 되는데, 그러면 PVC 를 지울 때 AWS 볼륨까지 같이 없어져서 이번 같은 상황을 사람이 직접 만들 수도 있습니다.

애플리케이션이 볼륨 ID 를 자체 DB 나 설정에 따로 들고 있는 구조라면 그쪽도 새 ID 로 바꿔 줘야 하고, 안 그러면 다음번에 다시 없는 볼륨을 찾아갑니다.

복구를 시작하는 순간 원인 추적은 끝남

볼륨을 누가 지웠는지는 끝내 못 밝혔습니다. 관련 로그가 파드를 재시작하는 과정에서 같이 사라졌기 때문입니다. 복구하는 행위 자체가 증거를 지우는 일이라, 파드를 다시 띄우는 순간 원인을 찾을 기회도 같이 없어집니다. 서비스를 먼저 살려야 하는 상황이라도 관련 컴포넌트 로그는 손대기 전에 먼저 빼둬야 합니다.

FailedAttachVolume 이 뜨면 대개 볼륨이나 노드, CSI 쪽 문제라 알람으로 잡을 만한 이벤트입니다. 다만 이번처럼 볼륨 자체가 사라지는 사고는 알람으로 막을 수 있는 게 아니라서 스냅샷을 걸어 두는 것 말고는 데이터를 되찾을 방법이 없습니다.

  1. 불러오는 중