모험가

AEWS 3주차 - Storage(PV, PVC, EBS) 본문

쿠버네티스/AEWS

AEWS 3주차 - Storage(PV, PVC, EBS)

라리음 2025. 2. 21. 14:25

 



본 글은 가시다님이 진행하시는 AEWS(AWS EKS Workshop Study)를 참여하여 정리한 글입니다. 
모르는 부분이 많아서 틀린 내용이 있다면 말씀 부탁드리겠습니다!

 

 

 

 


스토리지 이해

 

pv를 사용하지 않으면 파드의 내부 데이터는 파드가 삭제되면 모두 삭제됩니다.

-> 즉 stateless : Temporary filesystem, Volume

 

https://aws.amazon.com/ko/blogs/tech/persistent-storage-for-kubernetes/

 

 

 

pv & pvc를 이용하면 데이터베이스처럼 파드가 삭제되더라도 데이터가 보존됩니다.

-> 즉 stateful : pv & pvc

 

https://aws.amazon.com/ko/blogs/tech/persistent-storage-for-kubernetes/

 

 

 

PV의 사용이 끝났을 때 볼륨을 어떻게 초기화할 것인지 별도로 설정할 수 있는데 이를 Reclaim Policy라고 부릅니다.

 

 

 

Reclaimpolicy에는 Retain(보존), Delete(삭제)가 있습니다.

 

구분 Retain Delete
정의 볼륨이 삭제되어도 데이터가 보존됨 볼륨이 삭제되면 데이터도 함께 삭제됨
데이터 보존 데이터가 보존됨 데이터가 삭제됨
볼륨 재사용 수동으로 볼륨을 삭제해야 재사용 가능 자동으로 볼륨이 삭제되어 재사용 가능
사용 사례 중요한 데이터를 보존해야 하는 경우 임시 데이터나 재생성 가능한 데이터의 경우
장점 데이터 보존 리소스 자동 정리
단점 리소스 정리가 수동으로 필요 데이터 손실 가능성

 

 

이와 같이 Retain 정책은 데이터 보존에 초점을 맞추고, Delete 정책은 리소스 자동 정리에 초점을 맞추고 있습니다. 사용 사례에 따라 적절한 Reclaim Policy를 선택하는 것이 중요합니다.

 

 

 


볼륨

 

 

https://kubetm.github.io/k8s/03-beginner-basic-resource/volume/

 

 

 

  1. emptyDir:
    • 임시 볼륨으로, 파드가 실행되는 동안만 존재합니다.
    • 파드가 종료되면 데이터가 삭제됩니다.
    • 주로 임시 파일 저장 등의 용도로 사용됩니다.
  2. hostPath:
    • 노드의 파일 시스템을 마운트하는 볼륨입니다.
    • 노드의 로컬 스토리지를 사용합니다.
    • 노드 간 데이터 공유가 필요한 경우 사용할 수 있습니다.
    • 보안 및 데이터 지속성 문제가 있을 수 있습니다.
  3. PV(Persistent Volume):
    • 클러스터 관리자가 프로비저닝한 영구 스토리지 볼륨입니다.
    • 파드가 종료되어도 데이터가 유지됩니다.
    • 다양한 스토리지 유형(NFS, AWS EBS 등)을 지원합니다.
    • 클러스터 수준에서 관리되며, 개발자가 직접 생성하지 않습니다.

요약하면, emptyDir은 임시 볼륨, hostPath는 노드의 로컬 스토리지, PV는 클러스터 수준의 영구 스토리지입니다.

 

결국 보존해야할 중요 데이터들은 pv를 사용하는 것이 바람직합니다.

 

 

 

Dynamic Provisioning란?

 

PVC(Persistent Volume Claim)가 생성되면 StorageClass에 정의된 프로비저닝 방식에 따라 자동으로 PV(Persistent Volume)가 생성합니다.

즉 Storage Class만 선언해놓으면 스토리지 리소스를 추상화 하므로 PVC만 생성하면 됩니다.

 

 

 

 

 

 

 


CSI(Container Storage Interface)

 

 

CSI는 컨테이너 환경에서 다양한 스토리지 시스템을 사용할 수 있도록 해주는 표준 인터페이스입니다. 마치 USB 포트가 다양한 외부 장치를 연결할 수 있게 해주는 것처럼, CSI도 컨테이너 플랫폼과 스토리지 시스템 간의 연결을 표준화하고 있습니다.

 

CSI를 사용하면 컨테이너 플랫폼(예: Kubernetes)과 스토리지 시스템 간의 연결이 표준화되어, 개발자는 스토리지 시스템의 구현 방식에 대해 신경 쓰지 않고도 필요한 스토리지를 쉽게 사용할 수 있습니다. 이를 통해 개발 생산성이 높아지고, 다양한 스토리지 솔루션을 활용할 수 있게 되었습니다.

 

요약하면, CSI는 컨테이너 환경에서 스토리지 시스템을 보다 쉽고 유연하게 사용할 수 있도록 해주는 표준 인터페이스라고 할 수 있습니다.

 

 

그러면 AWS에서 CSI Driver은 어떨까요?

 

 

AWS 문서

 

 

관리자가 CSI 드라이버를 지정하는 StorageClass를 사전 정의합니다.

그러면 사용자가 특정 볼륨을 사용하도록 PVC를 생성하면 Control loop가 보고 있다가 해당하는 PV를 생성하고 붙여줍니다. (AWS에서는 편히 EBS CSI Driver을 이용합니다.)

 

 

 

 


EBS Controller

 

AWS CSI Driver에는 두가지가 존재합니다.

 

1. csi-controller

2. csi-node

 

 

csi-controller은 AWS API를 호출하면서 AWS 스토리지를 관리합니다.

csi-node는 kubelet과 상호작용하면서 AWS스토리지를 pod에 마운트합니다.

 

csi-controller은 Deployment로 뿌려지며, csi-node는 DaemonSet으로 뿌려집니다.

 

EBS를 생성하고 pod에 pv를 붙이는 플로우는 아래와 같습니다.

 

 

 

 

VPC CNI와 비교하자면 aws-node가 AWS API를 요청해서 Secondary IP를 확보하듯이 

csi-controller가 AWS API를 요청해서 EBS를 생성하고 attach합니다.

 

 

 

 

 

persistentvolume, persistentvolumeclaim의 accessModes는 ReadWriteOnce로 설정해야 합니다 이유가 뭘까요?

AWS EBS(Elastic Block Store) 볼륨의 특성을 먼저 보면

AWS EBS 볼륨은 단일 EC2 인스턴스에만 마운트할 수 있는 블록 스토리지 볼륨입니다. 따라서 EBS 볼륨은 한 번에 하나의 노드에서만 읽기/쓰기 액세스가 가능합니다.

AWS EKS와의 호환성으로는

AWS EKS는 기본적으로 AWS EBS 볼륨을 사용하므로, PersistentVolume과 PersistentVolumeClaim의 accessModes를 ReadWriteOnce로 설정해야 합니다. 다른 액세스 모드를 사용하면 EBS 볼륨의 특성과 충돌하여 문제가 발생할 수 있습니다.

 

 

또한 Node Affinity를 사용하여 특정 볼륨을 사용하기 위해 pod를 해당 노드에 스케쥴링할 수 있습니다.

 

 

 


설치

 

 

# ISRA 설정 : AWS관리형 정책 AmazonEBSCSIDriverPolicy 사용
eksctl create iamserviceaccount \
  --name ebs-csi-controller-sa \
  --namespace kube-system \
  --cluster ${CLUSTER_NAME} \
  --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
  --approve \
  --role-only \
  --role-name AmazonEKS_EBS_CSI_DriverRole

 

 

# Amazon EBS CSI driver addon 배포(설치)
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
eksctl create addon --name aws-ebs-csi-driver --cluster ${CLUSTER_NAME} --service-account-role-arn arn:aws:iam::${ACCOUNT_ID}:role/AmazonEKS_EBS_CSI_DriverRole --force
kubectl get sa -n kube-system ebs-csi-controller-sa -o yaml | head -5

 

# 배포 확인
eksctl get addon --cluster ${CLUSTER_NAME}
kubectl get pod -n kube-system -l app.kubernetes.io/component=csi-driver

 

 

 

AWS EC2에는 인스턴스당 붙일 수 있는 EBS 개수가 정해져 있습니다.

생성된 노드의 현재 부착 가능한 EBS 개수를 확인합니다.

-> 이후에 add on을 수정해서 최대 개수까지 증가 가능합니다.

 

kubectl describe csinodes

 

해당 노드의 Allocation이 가능한 개수는 25개임을 확인할 수 있습니다.

 

 

csi driver를 확인해보면 아래와 같습니다.

 

 

  • ATTACHREQUIRED: 볼륨을 파드에 마운트하기 전에 별도의 attach 과정이 필요한지 여부를 나타냅니다. true이면 attach가 필요하고, false이면 attach 없이 마운트 가능합니다.
  • PODINFOONMOUNT: 볼륨을 마운트할 때 파드 정보를 제공하는지 여부를 나타냅니다. true이면 파드 정보를 제공하고, false이면 제공하지 않습니다.
  • STORAGECAPACITY: 볼륨의 용량 정보를 제공하는지 여부를 나타냅니다. true이면 용량 정보를 제공하고, false이면 제공하지 않습니다.
  • TOKENREQUESTS: CSI 드라이버가 토큰을 요청하는지 여부를 나타냅니다.
  • REQUIRESREPUBLISH: 볼륨 정보를 다시 게시해야 하는지 여부를 나타냅니다.
  • MODES: 지원하는 볼륨 액세스 모드(ReadWriteOnce, ReadOnlyMany, ReadWriteMany)를 나타냅니다.

 

 

 

기본적으로 설치하면 gp2 StorageClass만 선언되어있습니다.

gp3 타입의 볼륨을 생성하고 부착하려면 gp3 Storage Class를 선언합니다.

 

# gp3 스토리지 클래스 생성
kubectl get sc
cat <<EOF | kubectl apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gp3
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  allowAutoIOPSPerGBIncrease: 'true'
  encrypted: 'true'
  fsType: xfs # 기본값이 ext4
EOF

# 확인
kubectl get sc

 

 

여기에서 VOLUMEBINDINGMODE는 PVC과 PV 간의 바인딩 시점을 결정하는 옵션입니다

immediate를 사용하면 pv와 즉시 연결이 되지만 여러가지 제약이 있고 pv가 먼저 생성되어 있어야한다는 점에서 불편함이 있습니다.

 

이에 일반적으로 WaitForFirstConsumer 모드를 추천합니다. 이 모드를 사용하면 다음과 같은 장점이 있습니다:

  • 프로비저닝 지연 문제를 해결할 수 있습니다.
  • 파드 스케줄링 시 사용 가능한 PV를 보장할 수 있습니다.
  • 리소스 활용도를 높일 수 있습니다.

 

 


pv,pvc,pod 확인

 

# PVC 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  storageClassName: gp3
EOF
kubectl get pvc,pv

# 파드 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  terminationGracePeriodSeconds: 3
  containers:
  - name: app
    image: centos
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo \$(date -u) >> /data/out.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim
EOF

# PVC, 파드 확인
kubectl get pvc,pv,pod
kubectl get VolumeAttachment
kubectl df-pv

 

 

pvc와 생성하면 연결될 pod가 없기에 status가 pending으로 나옵니다.

 

이후 pod를 생성하면 이에 조건을 확인하고 pv를 생성하 Bound됩니다.

 

 

콘솔에서도 생성된 EBS를 볼 수 있습니다.

 

 

 

위에서 언급한 것과 같이 nodeAffinity를 이용해서 해당 가용영역에 있는 EBS를 선택합니다.

밑에는 persistentvolumereclaimpoicy 로 pvc가 삭제되면 생성되었던 pv도 delete됨을 의미합니다.

 

 

 

이제 pv를 4GB -> 10GB로 확장하겠습니다. (증설은 가능하지만 감설은 안됩니다.)

 

# 현재 pv 의 이름을 기준하여 4G > 10G 로 증가 : .spec.resources.requests.storage의 4Gi 를 10Gi로 변경
kubectl get pvc ebs-claim -o jsonpath={.spec.resources.requests.storage} ; echo
kubectl get pvc ebs-claim -o jsonpath={.status.capacity.storage} ; echo
kubectl patch pvc ebs-claim -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'

# 확인
kubectl df-pv

증설 화면