본문 바로가기
  • lakescript
스터디 이야기/AWS EKS

[AEWS] 3-1. Amazon EKS - Storage (EBS, EFS)

by lakescript 2024. 3. 19.

사전 준비

더보기

 

위와 같이 사전 준비가 필요합니다.

저번 글에서 설명했듯이, EKS를 배포하기 위한 VPC를 생성하고, Public Subnet, Private Subnet을 생성합니다. 그 후 EKS Cluster에 접근하기 위한 bastion EC2를 미리 생성합니다

Kubernetes Storage

Pod는 stateful하게 관리되는 리소스가 아니고 상태가 없는(Stateless) 애플리케이션이기 때문에 영구 스토리지가 없으면 Pod가 충돌하거나 종료되고, Pod의 데이터는 손실됩니다. 하지만 DB나 여러가지 데이터를 담고 있는 컨테이너들을 Pod로 만들어야 할 때 그 데이터들을 영구적으로 보존되게 해야 합니다. Kubernetes에서 Volume이라는 형태의 Storage 리소스를 제공하는데, 위의 고민들을 해결하기 위해 나온 Volume 리소스가 PV, PVC 입니다. 즉, Pod의 라이프 사이클과 Volume을 분리시켜 Pod가 삭제되거나 수정되어도 Storage는 보존이 가능합니다.

본 시리즈는 Amazon EKS의 관한 개념과 실습 위주의 글이기 때문에 K8s의 개념에 대해서는 생략하도록 하겠습니다.
공식문서를 참고해주세요!

 

현재 EC2 Host의 디스크 공간을 확인해보자!

df -h

 

위의 명령어로 조회하게 되면 아래와 같이 현재 사용하고 있는 디스크의 공간 이력을 확인할 수 있습니다.

 

 

EFS를 Mount 해보자!

 mount -t efs -o tls $EFS-ID:/ /mnt/myefs

 

위의 명령어를 통해. EFS ID를 Mount 하고 난 후 다시 디스크 사용공간을 확인해보겠습니다.

 

정상적으로 Mount 된 것을 확인하실 수 있습니다.

 

 

CSI (Contaier Storage Interface)

ChatGPT가 알려주는 CSI
CSI (Container Storage Interface)는 컨테이너화된 애플리케이션에서 사용할 수 있는 스토리지 시스템을 컨테이너 오케스트레이션 시스템(COS)에 연결하기 위한 업계 표준 인터페이스입니다. CSI의 목적은 컨테이너 오케스트레이션 시스템과 스토리지 시스템 간의 통합을 표준화하여, 다양한 스토리지 제공업체가 자신의 솔루션을 쉽게 통합할 수 있도록 하는 것입니다. 이를 통해 사용자는 컨테이너화된 애플리케이션에서 필요한 스토리지를 보다 유연하고 효율적으로 관리할 수 있습니다.

 

즉, CSI란 컨테이너화된 애플리케이션에서 사용할 수 있는 스토리지 시스템을 컨테이너 오케스트레이션 시스템(COS)에 연결하기 위한 업계 표준 인터페이스입니다. Kubernetes에서 이러한 CSI를 사용하기 위해서는 CSI-Driver를 설치해야 하고, Kubernetes의 공통화된 CSI 인터페이스를 통해 다양한 프로바이더를 사용할 수 있습니다.

CSI Driver 배경
Kubernetes source code 내부에 존재하는 AWS EBS provisioner는 당연히 Kubernetes release lifecycle을 따라서 배포되므로, provisioner 신규 기능을 사용하기 위해서는 Kubernetes version을 업그레이드해야 하는 제약 사항이 있습니다. 따라서, Kubernetes 개발자는 Kubernetes 내부에 내장된 provisioner (in-tree)를 모두 삭제하고, 별도의 controller Pod을 통해 동적 provisioning을 사용할 수 있도록 만들었습니다. 이것이 바로 CSI (Container Storage Interface) driver 입니다.

위의 이미지는 일반적인 CSI driver의 구조입니다.

자세히 살펴보면 AWS EBS CSI driver 역시 아래와 같은 구조를 가지는데, 자세히 살펴보면 오른쪽 StatefulSet 또는 Deployment로 배포된 Pod가 AWS API를 사용하여 실제 EBS volume을 생성하는 역할을 합니다.

왼쪽 DaemonSet으로 배포된 Pod는 AWS API를 사용하여 Kubernetes node (EC2 instance)에 EBS volume을 attach 해줍니다.

 

 

Amazon EBS

ChatGPT가 알려주는 Amazon EBS
AWS EBS (Amazon Elastic Block Store)는 Amazon Web Services(AWS)에서 제공하는 고성능 블록 스토리지 서비스입니다. 이 서비스는 Amazon EC2 (Elastic Compute Cloud) 인스턴스에 사용할 수 있는 영구적이고, 고성능의 블록 레벨 스토리지 볼륨을 제공합니다. EBS 볼륨은 네트워크 연결을 통해 EC2 인스턴스에 연결되며, 인스턴스와 독립적으로 존재하여 인스턴스의 수명 주기와 관계없이 데이터를 유지할 수 있습니다.

 

 

 

AWS Managed Console의 EC2 메뉴에 들어가서 특정 EC2 Instance의 Storage 부분을 확인해보면 EBS가 할당된 것을 확인하실 수 있습니다. 이렇듯 Amazon EBS는 Amazon EC2에 연결할 수 있는 영구적이고 고성능의 Storage 서비스입니다. 

 

Amazon EBS의 또다른 장점중 하나가 쉽게 Volume을 생성해서 EC2 Instnace에 attach할 수 있다는 점인데, 그것을 도와주는 것이 EBS-CSI-Controller입니다.

 

ChatGPT가 알려주는 EBS-CSI-Controller
AWS EBS(Elastic Block Store)를 위한 Container Storage Interface (CSI) 드라이버의 일부로, Kubernetes 클러스터 내에서 AWS EBS 볼륨을 관리하는 데 사용되는 컨트롤러 컴포넌트입니다. CSI 드라이버는 컨테이너화된 애플리케이션에서 사용할 수 있는 스토리지 시스템을 컨테이너 오케스트레이션 시스템에 연결하기 위한 표준 인터페이스를 제공합니다. 이 표준을 통해, 개발자와 시스템 관리자는 다양한 스토리지 솔루션을 쉽게 통합하고 사용할 수 있습니다.

 

 

다만 몇가지 주의할 점이 있습니다.

 

1. PersistentVolume, PersistentVolumeClaim의 accessModes는 ReadWriteOnce로 설정해야 합니다.

> AWS EBS 볼륨은 한 번에 하나의 EC2 인스턴스에만 마운트될 수 있으므로, ReadWriteOnce (RWO) 액세스 모드로 볼륨을 단일 노드에서만 읽기 및 쓰기 작업이 가능하도록 해야합니다. 만약, ReadWriteMany (여러 노드에서 동시에 읽기/쓰기 가능) 또는 ReadOnlyMany (여러 노드에서 동시에 읽기만 가능)와 같은 모드로 사용하게 된다면 충돌이 일어날 수 있습니다.

 

2. EBS스토리지 기본 설정이 동일 AZ에 있는 EC2 인스턴스(에 배포된 파드)에 연결해야 합니다.

> EBS 볼륨의 가용성과 신뢰성을 보장하기 위해 EBS 볼륨이 속해있는 AZ 내의 EC2 인스턴스에만 마운트할 수 있습니다. 그렇기에 K8s에서는 nodeAffinity나 Pod Affinity, Pod Anti-Affinity등을 설정하여 스케줄링 전략을 세워야 합니다.

 

 

Amazon EBS CSI driver as an Amazon EKS add-on 설치

Amazon EKS add-on을 통해 Amazon EBS CSI Driver를 설치해보겠습니다.

 

ISRA 설정 : AWS관리형 정책 AmazonEBSCSIDriverPolicy 사용

가장 먼저, 권한 처리를 위해 rn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy 정책을 설정한 ISRA를 설정합니다. 

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

 

생성 후 ServiceAccount를 확인합니다.

 

eksctl get iamserviceaccount --cluster $CLUSTER_NAME

 

 

 

Amazon EBS CSI driver addon 추가

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

 

위의 명령어로 현재 Cluster에 ServiceAccount를 연결합니다.

 

 

현재 Cluster에 추가된 add-on 목록 확인

eksctl get addon --cluster ${CLUSTER_NAME}

 

현재 Cluster에 설치된 add-on 목록을 확인합니다.

 

 

현재 Cluster에 설치된 Amazon EBS CSI Controller 리소스 확인

kubectl get deploy,ds -l=app.kubernetes.io/name=aws-ebs-csi-driver -n kube-system
kubectl get pod -n kube-system -l 'app in (ebs-csi-controller,ebs-csi-node)'
kubectl get pod -n kube-system -l app.kubernetes.io/component=csi-driver

 

자! 이제 EBS CSI Controller 관련 설치 및 설정을 완료했습니다.

 

 

gp3 스토리지 클래스 생성

생성하기 전 현재 Cluster내에 있는 StorageClass 확인

 

gp3 생성

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gp3
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  #iops: "5000"
  #throughput: "250"
  allowAutoIOPSPerGBIncrease: 'true'
  encrypted: 'true'
  fsType: xfs # 기본값이 ext4

 

(각각의 옵션은 공식문서에서 확인하실 수 있습니다!)

 

생성 후 Cluster 내에 있는 StorageClass 확인

 

 

EBS Volume을 사용하는 PVC/PV 파드 테스트

EBS Volume을 자동으로 생성하고, 생성한 Volume을 Pod가 사용해보는 실습을 진행해보겠습니다.

PVC 생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  storageClassName: gp3

 

위의 명령어로 앞선 생성한 gp3 StorageClass를 사용하는 PVC를 생성합니다.

 

Pod 생성

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

 

 

위에 생성한 PVC를 Volume Mount하게 되면 Amazon EBS가 자동으로 생성됩니다.

 

 

Pod에 접근하여 Mount 리스트 확인

kubectl exec -it app -- sh -c 'df -hT'

exec 명령어를 통해 위에 생성한 Pod에 접근하여 mount 리스트를 확인해보면, StorageClass로 설정한 EBS Volume을 확인하실 수 있습니다.

 

 

Pod에 접근하여 파일 내용 확인

kubectl exec app -- tail -f /data/out.txt

exec 명령어를 통해 위에 생성한 Pod에 접근하여 mount 했던 /data/out.txt 파일을 확인해보며 정상적으로 EBS Volume이 Mount되었음을 확인하실 수 있습니다.

 

 

krew 플러그인을 활용하여 mount된 Volume 사용량 확인

df-pv 플러그인을 사용하면 Mount된 Volume의 정보를 쉽고 간단하게 확인가능합니다.

 

kubectl df-pv

 

사이즈, 사용 중인 용량, 사용가능한 용량, 사용률등 쉽게 확인가능합니다!

 

볼륨 용량 늘리기

운영하던 도중 디스크 용량이 부족하거나 더 필요할 경우 늘려야 할 텐데, AWS에서는 Patch를 통해 쉽게 증가시킬 수 있습니다. (단, 늘릴수는 있어도 줄일수는 없습니다.)

 

kubectl patch pvc ebs-claim -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'

 

 

 

kubectl exec -it app -- sh -c 'df -hT --type=xfs'

 

해당 명령을 적용한 후 조회해보면 볼륨 용량 수정 반영이 되어야 되니, 수치 반영이 조금 느릴수 있습니다!

 

AWS Volume SnapShots Controller

온라인 상에서 현재 동작하고 있는 Amazon EBS Volume을 주기적으로 백업을 해야할 때 SnapShot으로 저장이 가능합니다. 그것을 바로 AWS Volume SnapShots Controller를 통해 K8s native하게 생성할 수 있습니다.

 

AWS Volume SnapShots Controller 설치

현재 K8s 버전 업그레이드를 통해 최신 버전에서는 add-on이 제공되지만 이번 실습에서는 직접 설치를 해보겠습니다.

설치를 위해서는 CRDs, Controller, Class를 설치해야 합니다.

Snapshot CRDs 설치 및 적용

curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f snapshot.storage.k8s.io_volumesnapshots.yaml,snapshot.storage.k8s.io_volumesnapshotclasses.yaml,snapshot.storage.k8s.io_volumesnapshotcontents.yaml

 

Snapshot Controller 설치 및 적용

curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
kubectl apply -f rbac-snapshot-controller.yaml,setup-snapshot-controller.yaml

 

Snapshotclass 설치 및 적용

* StorageClass가 아닌 SnapshotClass입니다. 

curl -s -O https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/master/examples/kubernetes/snapshot/manifests/classes/snapshotclass.yaml
kubectl apply -f snapshotclass.yaml

 

PVC / Pod 생성

PVC 생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  storageClassName: gp3

 

Pod 생성

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

 

위의 EBS CSI Controller 실습과 마찬가지로 PVC를 생성 후 Pod에서 Mount 하게 되면 EBS Volume이 생성됩니다.

 

 

Pod에 접근하여 Mount 리스트 확인

kubectl exec -it app -- sh -c 'df -hT'

 

Pod에 접근하여 파일 내용 확인

kubectl exec app -- tail -f /data/out.txt

 

VolumeSnapshot 생성

curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/ebs-volume-snapshot.yaml

 

ebs-volume-snapshot.yaml 파일에서 .spec.source.persistentVolumeClaimName을 앞서 생성했던 PVC로 적어주셔야 합니다.

 

 

kubectl apply -f ebs-volume-snapshot.yaml

 

해당 명령어를 적용하면 Amazon Managed Console에서 바로 스냅샷이 생성되는 것을 확인하실 수 있습니다.

 

aws ec2 describe-snapshots --owner-ids self --query 'Snapshots[]' --output table

 

aws cli로도 확인하실 수 있습니다.


SnapShot을 통해 복원해보기!

강제로 PVC / Pod 제거

kubectl delete pod app && kubectl delete pvc ebs-claim

 

 PVC를 삭제하면 PVC를 통해 생성된 PV도 지워집니다.

 

 

이렇게 생성되었던 EBS Volume도 삭제되는 것을 확인하실 수 있습니다.

 

 

하지만 위에 보이시는 바와 같이 SnapShot은 남아있기에 이것을 사용하여 EBS Volume을 복원해보도록 하겠습니다.

 

PVC를 생성하여 Snapshot 복원

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-snapshot-restored-claim
spec:
  storageClassName: gp3
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  dataSource:
    name: ebs-volume-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io

 

여기서 보셔야 할 것은 .spec.dataSoruce입니다. VolumeSnapshot(kind에 명시)을 기반으로 PVC를 만든다 라고 보시면 됩니다. 

 

PVC를 VolumeMount하는 Pod 생성

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  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-snapshot-restored-claim

 

Pod 명세를 보시면 .spce.volumes.persistentVolumeClaim.claimName이 위에서 생성한 name과 일치하게 Mount해주게 됩니다.

 

 

해당 yaml 파일을 배포 후 EBS를 확인해보면 정상적으로 Snapshot으로 EBS Volume을 생성한 것을 확인하실 수 있습니다.

 

Pod에 접근하여 파일 내용 확인

 

exec 명령어를 통해 Pod에 접근하여 /data/out.txt를 확인하면 Snapshot에 있던 정보들이 보이는 것을 확인하실 수 있습니다.

 

 

Amazon EFS

 

ChatGPT가 알려주는 Amazon EFS
Amazon Elastic File System (EFS)은 Amazon Web Services (AWS)에서 제공하는 클라우드 기반의 파일 스토리지 서비스입니다. 이 서비스는 여러 Amazon EC2 인스턴스에서 동시에 사용할 수 있는 고성능, 확장 가능한 파일 스토리지를 제공합니다. Amazon EFS는 특히 대규모 데이터 세트를 다루는 애플리케이션, 웹 서버 클러스터, 콘텐츠 관리 시스템 등 다양한 용도로 사용됩니다.

 

즉, Amazon EFS는 AWS에서 제공하는 네트워크 파일 시스템으로 해당 네트워크 경로를 공유하게되면 Storage를 공유할 수 있습니다.

 

 

Amazon EFS는 EBS와는 다르게 여러 AZ에 설정 가능하며 여러 Pod에서도 설정하실 수 있습니다.

 

IAM 정책 생성

먼저, EFS를 사용할 수 있게 권한을 설정해주도록 합니다.

curl -s -O https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/docs/iam-policy-example.json
aws iam create-policy --policy-name AmazonEKS_EFS_CSI_Driver_Policy --policy-document file://iam-policy-example.json

 

해당 권한은 AmazonEKS_EFS_CSI_Driver_Policy으로써 EFS CSIT Driver에 대한 권한들이 명세되어 있습니다.

 

 

ISRA 설정

eksctl create iamserviceaccount \
  --name efs-csi-controller-sa \
  --namespace kube-system \
  --cluster ${CLUSTER_NAME} \
  --attach-policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AmazonEKS_EFS_CSI_Driver_Policy \
  --approve

 

위에서 생성한 IAM Policy(AmazonEKS_EFS_CSI_Driver_Policy)를 기반으로 ISRA를 생성합니다.

 

확인

eksctl get iamserviceaccount --cluster myeks

 

 

EFS Controller 설치

현재는 Add-on으로 제공되는 것으로 알고 있는데, 실습에서는 Helm을 이용하여 설치하도록 하겠습니다. 

add-on으로 설치하시려는 분들은 공식문서를 참고해주세요.

 

helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/
helm repo update
helm upgrade -i aws-efs-csi-driver aws-efs-csi-driver/aws-efs-csi-driver \
    --namespace kube-system \
    --set image.repository=602401143452.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/eks/aws-efs-csi-driver \
    --set controller.serviceAccount.create=false \
    --set controller.serviceAccount.name=efs-csi-controller-sa

 

확인

 

AWS Managed Console에서 EFS 메뉴에 접근한 뒤 해당 EFS에서 네트워크 탭에 들어가서 탑재 대상 ID들을 확인합니다.

 

 

 

EFS 파일시스템을 다수의 파드가 사용하게 설정

실습 코드 clone

git clone https://github.com/kubernetes-sigs/aws-efs-csi-driver.git /root/efs-csi
cd /root/efs-csi/examples/kubernetes/multiple_pods/specs && tree

 

 

 

EFS 스토리지클래스 생성 및 확인

kubectl apply -f storageclass.yaml

 

 

PV 생성 및 확인

sed -i "s/fs-4af69aab/$EFS_ID/g" pv.yaml

 

이때, pod.yaml에서 volumeHandle을 자신의 EFS 파일시스템ID로 변경합니다.

kubectl apply -f pv.yaml

 

 

 

PVC 생성 및 확인

kubectl apply -f claim.yaml

 

 

 

파드 생성 및 연동

kubectl apply -f pod1.yaml,pod2.yaml

 

 

Pod의 명세를 자세히 살펴보면 VolumeMounts의 MountPath를 /data로 지정하였는데, 이 경로가 EFS의 경로인 것을 알 수 있습니다.

 

Pod 정보 확인

kubectl exec -ti app1 -- sh -c "df -hT -t nfs4"
kubectl exec -ti app2 -- sh -c "df -hT -t nfs4"

 

exec 명령어를 통해 app1과 app2에 접근하여 각각 EFS로 Mount한 목록을 출력하니 같은 EFS가 출력되는 것을 보실 수 있습니다.

 

공유 저장소 저장 동작 확인

이 포스트 처음에 EFS를 EC2에 직접 mount하였습니다. 그 경로에 txt 파일하나를 생성하고 app1과 app2에서 그 파일을 실행할 수 있는지 확인해보겠습니다.

 

echo "efs test" >> /mnt/myefs/efs-test.txt

 

먼저, 위의 명령어를 통해 mount 시켰던 EFS 파일 시스템 경로에 efs-test.txt 파일을 생성합니다. 

 

kubectl exec -it app1 -- tail -f /data/efs-test.txt
kubectl exec -it app2 -- tail -f /data/efs-test.txt

 

그 후 kubectl exec 명령어를 통해 VolumeMount 시켰던 /data 경로에 efs-test.txt 파일을 읽어보겠습니다.

 

정상적으로 확인이 가능합니다!!

 

 

 


Reference

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

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

- https://github.com/kubernetes-sigs/aws-ebs-csi-driver

- https://kubernetes.io/docs/concepts/storage/volume-snapshots/