Published on

EKS PVC Bound인데 Mount 실패 - EBS CSI 권한·AZ·fsType

Authors

서론

EKS에서 StatefulSet/Deployment를 올릴 때 PVCBound로 잘 붙었는데도 Pod가 ContainerCreating에서 멈추고, 이벤트에는 MountVolume.MountDevice failed 류의 메시지가 뜨는 경우가 있습니다. 이 상황이 까다로운 이유는 Kubernetes 레벨에서는 PV/PVC 바인딩이 정상이라 “스토리지가 준비됐다”고 착각하기 쉽지만, 실제로는 노드(kubelet)에서 EBS를 Attach/Mount 하는 단계에서 실패하기 때문입니다.

이 글은 “PVC Bound인데 Mount 실패”를 EBS CSI Driver 관점에서 3가지 축으로 정리합니다.

  • 권한(특히 IRSA/ServiceAccount) 문제: EBS API 호출 자체가 막힘
  • AZ(가용영역) 불일치 문제: 볼륨은 한 AZ에 있는데 Pod는 다른 AZ 노드로 스케줄
  • fsType/포맷 문제: ext4/xfs 불일치, 이미 포맷된 볼륨, 마운트 옵션/파일시스템 손상

중간중간 kubectl/AWS CLI로 바로 확인 가능한 커맨드와, 안전하게 고치는 방법(재생성/패치/StorageClass 수정)을 함께 제공합니다.


증상 패턴: “Bound인데 왜 Mount가 안 되지?”

대표적으로 다음 이벤트/로그 조합이 나옵니다.

  • Pod 이벤트
    • Warning FailedMount ... MountVolume.MountDevice failed for volume ...
    • Warning FailedAttachVolume ... AttachVolume.Attach failed ...
  • EBS CSI Controller 로그
    • AccessDeniedException, UnauthorizedOperation
    • could not create volume, failed to attach volume, InvalidVolume.NotFound
  • kubelet 로그(노드)
    • mount failed: exit status 32
    • wrong fs type, bad option, bad superblock

핵심은 **PVC Bound는 “컨트롤 플레인에서 PV 연결이 완료”**라는 뜻이지, 노드에서 디바이스가 정상 마운트되었음을 의미하지 않는다는 점입니다.


1) 1차 트리아지: 이벤트/리소스부터 보고 원인 축을 확정

Pod 이벤트 확인

kubectl describe pod <pod> -n <ns>

Events: 섹션에서 아래 키워드로 분류합니다.

  • AttachVolume.Attach failed권한/EC2 Attach 실패, 또는 AZ/노드 문제
  • MountVolume.MountDevice failed + wrong fs typefsType/포맷 문제
  • timed out waiting for the condition노드 장애/CSI 데몬셋 문제/EC2 API 지연

PV/PVC와 StorageClass 확인

kubectl get pvc -n <ns>
kubectl describe pvc <pvc> -n <ns>

kubectl get pv <pv>
kubectl describe pv <pv>

kubectl get sc
kubectl describe sc <sc>
  • PV의 nodeAffinity에 특정 AZ가 박혀 있는지
  • StorageClass의 volumeBindingModeWaitForFirstConsumer인지
  • csi.volume.kubernetes.io/fstype 또는 parameters: fsType:가 무엇인지

EBS CSI 파드 상태/로그 확인

kubectl -n kube-system get pods -l app.kubernetes.io/name=aws-ebs-csi-driver
kubectl -n kube-system logs deploy/ebs-csi-controller -c ebs-plugin --tail=200

컨트롤러 로그에 AccessDenied가 보이면 거의 확정적으로 IRSA/권한 축입니다.

IRSA/권한 이슈 진단은 아래 글의 체크리스트가 그대로 도움이 됩니다.


2) 원인 A: EBS CSI 권한(IRSA) 문제로 Attach/Mount 실패

왜 PVC는 Bound인데 권한이 문제일까?

동적 프로비저닝(StorageClass로 EBS 생성)이 성공해 PV/PVC는 Bound가 되었더라도, 실제 Attach(EC2에 볼륨 연결)Detach/Modify 같은 작업은 EBS CSI Driver가 계속 수행합니다. 여기서 CSI Controller가 사용하는 IAM 권한이 부족하면 다음이 발생합니다.

  • 볼륨 생성은 됐는데 Attach가 안 됨
  • Attach는 됐는데 Tag/Modify/Describe 호출이 막혀 후속 단계에서 실패

대표 에러

  • UnauthorizedOperation: You are not authorized to perform this operation.
  • AccessDeniedException (특히 KMS 암호화 볼륨이면 kms:Decrypt, kms:CreateGrant 등도 필요)

점검 포인트

  1. EBS CSI Driver가 IRSA로 동작하는지 확인
kubectl -n kube-system get sa ebs-csi-controller-sa -o yaml
  • eks.amazonaws.com/role-arn 어노테이션이 있는지
  1. 해당 Role에 AmazonEBSCSIDriverPolicy(또는 동등 권한)가 있는지
aws iam list-attached-role-policies --role-name <role>
  1. KMS 암호화 EBS라면 KMS 키 정책/권한도 확인
  • CSI Role에 kms:Decrypt, kms:CreateGrant, kms:DescribeKey 등이 필요할 수 있음

빠른 해결 절차(권장 패턴)

  • EKS Add-on aws-ebs-csi-driver 사용 + IRSA 연결
  • AWS 관리 정책 AmazonEBSCSIDriverPolicy 부착

예시(개념 코드):

# (1) OIDC 연결 및 IRSA Role 생성은 eksctl/terraform 등으로 구성
# (2) CSI 서비스어카운트에 role-arn 어노테이션 부여
kubectl -n kube-system annotate sa ebs-csi-controller-sa \
  eks.amazonaws.com/role-arn=arn:aws:iam::<acct>:role/<EbsCsiRole> --overwrite

# (3) 컨트롤러 재시작
kubectl -n kube-system rollout restart deploy/ebs-csi-controller

만약 Pod 내에서 IMDS(169.254.169.254) 접근 관련 401/권한 꼬임이 함께 보인다면, IRSA와 IMDS 설정도 같이 점검해야 합니다.


3) 원인 B: AZ 불일치(가용영역)로 “볼륨은 있는데 노드에 못 붙임”

EBS는 기본적으로 Single-AZ 리소스

EBS gp2/gp3/io1/io2 등 대부분은 특정 AZ에 종속됩니다. 즉, ap-northeast-2a에 만들어진 볼륨은 2c 노드에 Attach할 수 없습니다.

PVC가 Bound인 상태에서 Pod가 다른 AZ에 스케줄되면, kube-scheduler/CSI가 조정하려다 결국 아래처럼 실패합니다.

  • failed to attach volume ... is not in the same availability zone as instance

이 문제가 자주 생기는 조건

  • StorageClass의 volumeBindingModeImmediate인 경우
    • PVC 생성 시점에 아무 노드도 고려하지 않고 “임의 AZ”로 볼륨이 먼저 만들어짐
    • 이후 Pod가 다른 AZ에 스케줄되면 충돌
  • 노드그룹이 멀티 AZ인데, 워크로드는 특정 AZ로 고정되지 않은 경우

올바른 해결: WaitForFirstConsumer 사용

WaitForFirstConsumerPod가 어느 노드(AZ)에 스케줄될지 결정된 다음 그 AZ에 맞춰 볼륨을 생성합니다. 멀티 AZ EKS에서는 사실상 기본값처럼 쓰는 것이 안전합니다.

StorageClass 예시:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3-wffc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  fsType: ext4

적용:

kubectl apply -f sc-gp3-wffc.yaml

기존 PVC/PV가 이미 Immediate로 잘못 생성되어 AZ가 꼬였다면, 가장 확실한 방법은:

  • 데이터가 없다면: PVC 삭제 → 새 StorageClass로 재생성
  • 데이터가 있다면: 스냅샷/백업 후 원하는 AZ로 복구하거나, 워크로드를 해당 AZ로 고정(nodeSelector/affinity)하는 우회가 필요합니다.

현재 PV가 어느 AZ인지 확인

kubectl describe pv <pv> | sed -n '/Node Affinity/,$p'

또는 EBS 볼륨 ID를 뽑아서 AWS CLI로:

VOL_ID=$(kubectl get pv <pv> -o jsonpath='{.spec.csi.volumeHandle}')
aws ec2 describe-volumes --volume-ids "$VOL_ID" \
  --query 'Volumes[0].AvailabilityZone' --output text

4) 원인 C: fsType/포맷 문제(특히 ext4 vs xfs, 기존 데이터 볼륨)

전형적인 로그

Pod 이벤트나 kubelet 로그에서 다음이 보이면 fsType 축입니다.

  • wrong fs type, bad option, bad superblock on /dev/nvme...
  • mount: unknown filesystem type 'xfs' (노드 AMI에 xfs 유틸이 없거나 드묾)

왜 발생하나?

  1. StorageClass/PV에 지정한 fsType과 실제 볼륨 파일시스템이 다름
  • 예: 볼륨은 xfs로 포맷되어 있는데 StorageClass는 ext4로 마운트 시도
  1. 기존에 다른 클러스터/노드에서 쓰던 볼륨을 재사용
  • 스냅샷에서 복구한 볼륨에 이전 파일시스템/UUID가 남아있음
  1. 파일시스템 손상
  • 비정상 종료/강제 detach 등으로 슈퍼블록 손상

확인 방법

  • PV/SC의 fsType 확인
kubectl describe sc <sc> | sed -n '/Parameters/,$p'
  • PV에 fsType이 직접 들어간 경우도 확인
kubectl get pv <pv> -o yaml | yq '.spec.csi,.spec.mountOptions'

해결 전략

(1) 신규 볼륨이라면: fsType을 표준(ext4)로 통일

가장 무난한 조합은 gp3 + ext4입니다.

parameters:
  type: gp3
  fsType: ext4

(2) 기존 데이터 볼륨이라면: “실제 파일시스템”에 맞춰 fsType 지정

예를 들어, 볼륨이 xfs라면 StorageClass/PV의 fsType을 xfs로 맞추거나(가능한 경우), 데이터 마이그레이션을 고려합니다.

(3) 파일시스템 손상 가능성: 복구/마이그레이션

운영 환경에서 무작정 fsck를 돌리기보다는:

  • 스냅샷 생성
  • 별도 복구 인스턴스에 Attach
  • fsck 수행 후 다시 사용

이 과정이 필요할 수 있습니다.


5) 실전 디버깅 체크리스트(15분 컷)

1) 이벤트로 Attach vs Mount 구분

kubectl describe pod <pod> -n <ns>
  • Attach 실패면: 권한/IRSA 또는 AZ
  • Mount 실패면: fsType/포맷/노드 유틸

2) CSI 컨트롤러 로그에서 AccessDenied 검색

kubectl -n kube-system logs deploy/ebs-csi-controller -c ebs-plugin | grep -E 'AccessDenied|Unauthorized|Denied' -n

3) PV nodeAffinity로 AZ 확인

kubectl describe pv <pv> | grep -n "topology.kubernetes.io/zone" -n

4) StorageClass의 volumeBindingMode 확인

kubectl get sc <sc> -o jsonpath='{.volumeBindingMode}{"\n"}'
  • 멀티 AZ면 WaitForFirstConsumer 권장

5) fsType 확인

kubectl describe sc <sc> | grep -i fstype -n

6) 재현 가능한 예시: 문제 SC(Immediate) → 개선 SC(WFFC)

문제 상황(Immediate)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3-immediate
provisioner: ebs.csi.aws.com
volumeBindingMode: Immediate
parameters:
  type: gp3
  fsType: ext4
  • PVC 생성 시점에 볼륨이 특정 AZ로 먼저 만들어짐
  • Pod는 다른 AZ 노드로 스케줄 → Mount/Attach 실패

개선(WaitForFirstConsumer)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3-wffc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  fsType: ext4

PVC 템플릿에서 StorageClass만 바꿔도 많은 케이스가 해결됩니다(데이터 없는 경우).


7) 자주 놓치는 주변 이슈

노드 자체 문제로 CSI 노드 플러그인이 동작하지 않는 경우

EBS CSI는 노드에 DaemonSet(ebs-csi-node)도 깔립니다. 노드가 NotReady/네트워크 문제면 마운트 단계가 연쇄적으로 실패할 수 있습니다. 노드 컨디션이 수상하면 아래 유형의 이슈도 함께 점검하세요.

“볼륨은 붙었는데 컨테이너가 계속 못 뜬다”

마운트 이후 단계에서 종료 훅이나 finalizer로 Pod가 비정상 상태에 빠지는 경우도 있습니다. Mount 이슈를 해결했는데도 Pod가 정리되지 않거나 Terminating에 멈추면 다음 글의 체크리스트가 유용합니다.


결론

EKS에서 PVC Bound인데 Mount가 실패하는 문제는 대부분 다음 3개 중 하나로 수렴합니다.

  1. EBS CSI 권한(IRSA/IAM/KMS): AccessDenied/UnauthorizedOperation이 보이면 거의 확정
  2. AZ 불일치: Immediate로 먼저 만들어진 EBS가 다른 AZ에 박혀 Pod가 붙지 못함 → WaitForFirstConsumer로 설계 변경
  3. fsType/포맷 문제: wrong fs type류 메시지 → SC/PV fsType과 실제 파일시스템 정합성 맞추기

가장 빠른 접근은 “Pod 이벤트로 Attach vs Mount를 먼저 구분하고, CSI 로그에서 권한을 확인한 뒤, PV의 nodeAffinity(AZ)와 StorageClass의 WFFC 여부, 마지막으로 fsType” 순서로 좁히는 것입니다. 이 순서대로 보면 대개 15~30분 내에 원인을 특정하고 재발 방지까지 설계에 반영할 수 있습니다.