EBS CSI driver를 통한 EBS PersistentVolume 사용하기
By Bys on December 9, 2022
EBS CSI driver
EBS CSI driver는 Amazon EKS 클러스터가 영구 볼륨을 위해 Amazon EBS 볼륨의 수명 주기를 관리할 수 있게 해주는 CSI 인터페이스를 제공한다.
The Amazon Elastic Block Store (Amazon EBS) Container Storage Interface (CSI) driver allows Amazon Elastic Kubernetes Service (Amazon EKS) clusters to manage the lifecycle of Amazon EBS volumes for persistent volumes.
Amazon EBS CSI driver
EKS v1.23 부터는 In-tree controller는 deprecated 되고 EBS CSI driver를 사용하여야 한다.
1. IAM Role과 ServiceAccount생성하기
The Amazon EBS CSI plugin requires IAM permissions to make calls to AWS APIs on your behalf.
eksctl create iamserviceaccount \
--name ebs-csi-controller-sa \
--namespace kube-system \
--cluster bys-dev-eks-main \
--attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
--approve \
--role-name AmazonEKS_EBS_CSI_DriverRole
2. Installation, self-managed
설치 가이드에 따라 EBS CSI Driver를 설치하고 나면 Controller가 Deployment로 배포가 되고, EBS CSI Driver daemonSet이 설치된다.
# kubectl
kubectl apply -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.13"
kubectl delete -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.13"
# Helm
helm repo add aws-ebs-csi-driver https://kubernetes-sigs.github.io/aws-ebs-csi-driver
helm repo update
helm upgrade --install aws-ebs-csi-driver --namespace kube-system aws-ebs-csi-driver/aws-ebs-csi-driver -f values.yaml
3. Dynamic Provisioning 동작방법
- StorageClass를 정의한다. StorageClass는 provisioner, parameters, reclaimPolicy 필드를 포함하는데 이는 dynamic provisioning을 통해 PV를 생성 할 때 사용된다.
- provisioner는 PV를 provisioning할 때 어떤 볼륨 plugin을 사용할지 결정한다.
- Parameters는 사용되는 provisioner에 따라 허용되는 값이 달라진다. EBS CSI driver에서는 ‘ebs.csi.aws.com’ provisioner를 사용하며 Parameters값은 type에 따라 gp2, gp3, io1 등의 종류를 결정할 수 있고, iops 옵션, encrypted 옵션 등을 설정할 수 있다.
- StorageClass에 의해 동적으로 생성 된 PV는 reclaimPolicy필드를 갖는데 ‘Delete’ or ‘Retain’ 값을 갖는다.
-
Developer는 생성되어있는 cluster에서 StorageClass들을 리스트하여 각각의 정의를 보고 어떤 볼륨을 생성할지 결정한다. 그리고 원하는 StorageClass의 볼륨을 생성하기 위한 요청을 진행하게 되는데 이 내용을 담은 것이 PVC다.
- PVC를 요청하게 되면 Provisioner는 요청을 받아들여 PV를 생성하게 된다. 이 요청을 처리하는 것은 실제로 ebs-csi-controller에서 진행한다. 따라서, 아래와 같이 ebs-csi-controller로그를 확인한 상태로 PVC를 생성하면 PV가 생성되는 로그를 확인할 수 있다.
kubectl logs -f -l app=ebs-csi-controller -n kube-system I1208 14:25:15.016041 1 cloud.go:670] Waiting for volume "vol-07435d5e6e23bbc3b" state: actual=attaching, desired=attached I1208 14:25:58.977160 1 cloud.go:670] Waiting for volume "vol-024cb9263523da2f8" state: actual=detaching, desired=detached I1208 14:26:00.058710 1 cloud.go:670] Waiting for volume "vol-024cb9263523da2f8" state: actual=detaching, desired=detached I1208 14:26:01.911935 1 cloud.go:670] Waiting for volume "vol-024cb9263523da2f8" state: actual=detaching, desired=detached I1208 14:27:57.399082 1 cloud.go:670] Waiting for volume "vol-07435d5e6e23bbc3b" state: actual=detaching, desired=detached I1208 14:27:58.463509 1 cloud.go:670] Waiting for volume "vol-07435d5e6e23bbc3b" state: actual=detaching, desired=detached I1208 14:28:00.302592 1 cloud.go:670] Waiting for volume "vol-07435d5e6e23bbc3b" state: actual=detaching, desired=detached
- 볼륨 바인딩과 dynamic provisioning을 통한 PV가 생성되는 시점은 StorageClass의 volumeBindingMode와 값과 관련이 있다. ‘Immediate’ 모드에서는 PVC가 생성되는 시점에 즉시 volume binding과 dynamic provisioning을 통한 PV가 생성된다. ‘WaitForFirstConsumer’ 모드에서는 binding과 PV의 provisioning의 시점을 Pod가 PVC를 사용하기 전까지 지연시킨다.
아래 테스트에서 manifest를 SC -> PVC -> Pod 순으로 배포중 PVC까지 생성하고 PVC의 상태를 살펴보면 pending상태임을 알 수 있다. 그리고 Pod를 생성하면 그 때서야 binding과 dynamic provisioning이 발생하는 것을 알 수 있다. 이 것은 StorageClass의 volumeBindingMode 모드가 WaitForFirstConsumer 값을 가지기 때문이다.
4. Dynamic Provisioning Test
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-sc-gp3
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete # Default
parameters:
type: gp3
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ebs-gp3-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-sc-gp3
resources:
requests:
storage: 10Gi
---
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-gp3-pvc
StorageClass, PVC까지만 배포를 하고 나면 PVC의 상태는 아직 pending 중이다. 이 후 Pod를 정상 배포 하면 PVC의 상태가 Bound상태로 변경 되었고, PV를 보면 StorageClass에서 정의한 볼륨이 생성 된 것을 알 수 있다.
$ k get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
ebs-sc-gp3 ebs.csi.aws.com Delete WaitForFirstConsumer false 25m
$ k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
ebs-gp3-pvc Pending ebs-sc-gp3 10m
$ k get po app -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app 1/1 Running 0 4m48s 10.20.11.25 ip-10-20-11-227.ap-northeast-2.compute.internal <none> <none>
$ k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
ebs-gp3-pvc Bound pvc-fbd333d4-f74e-4dcc-b60b-d5d79a73b0ed 10Gi RWO ebs-sc-gp3 11m
$ get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-fbd333d4-f74e-4dcc-b60b-d5d79a73b0ed 10Gi RWO Delete Bound default/ebs-gp3-pvc ebs-sc-gp3 5s
5. 볼륨의 Mount 살펴보기
Pod가 생성된 노드(10.20.11.227)로 접속
EC2에서 lsblk 명령어로 리눅스 디바이스 정보를 확인해보면, nvme1n1 이름으로 ext4 파일시스템 타입이 /var/lib/kubelet/pod 하위 경로에 마운트 된 것을 확인 할 수 있다.
$ lsblk -f
NAME FSTYPE LABEL UUID MOUNTPOINT
nvme0n1
├─nvme0n1p1 xfs / 1569e1c8-ad2a-4099-b3be-8ccd6ac8e7e9 /
└─nvme0n1p128
nvme1n1 ext4 e853ae12-34a1-4399-84f5-fde227b683c2 /var/lib/kubelet/pods/48c42e3a-073d-46b9-9a18-73679e9eaf31/volumes/kubernetes.io~csi/pvc-fbd333d4-f74e-4dcc-b60b-d5d79a73b0ed/mount
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1 259:0 0 80G 0 disk
├─nvme0n1p1 259:1 0 80G 0 part /
└─nvme0n1p128 259:2 0 1M 0 part
nvme1n1 259:3 0 10G 0 disk /var/lib/kubelet/pods/48c42e3a-073d-46b9-9a18-73679e9eaf31/volumes/kubernetes.io~csi/pvc-fbd333d4-f74e-4dcc-b60b-d5d79a73b0ed/mount
해당 경로에 이동해보면 실제 EBS볼륨이 EC2인스턴스에 우선 마운트 된 것을 확인 할 수 있다.
$ cd /var/lib/kubelet/pods/48c42e3a-073d-46b9-9a18-73679e9eaf31/volumes/kubernetes.io~csi/pvc-fbd333d4-f74e-4dcc-b60b-d5d79a73b0ed/mount
$ ll
total 20
drwx------ 2 root root 16384 Dec 8 14:49 lost+found
-rw-r--r-- 1 root root 1932 Dec 8 14:55 out.txt
Pod로 접속
Pod에서 lsblk 명령어로 확인해보면 nvme1n1이름으로 /data 경로에 마운트 된 것을 확인 할 수 있다.
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1 259:0 0 80G 0 disk
|-nvme0n1p1 259:1 0 80G 0 part /etc/resolv.conf
`-nvme0n1p128 259:2 0 1M 0 part
nvme1n1 259:3 0 10G 0 disk /data
해당 경로로 이동해서 데이터를 확인
$ cd /data
$ ls -l
total 20
drwx------ 2 root root 16384 Dec 8 14:49 lost+found
-rw-r--r-- 1 root root 3864 Dec 8 15:01 out.txt
Pod삭제
- Pod를 삭제하면 /var/lib/kubelet/pods 하위 경로인 48c42e3a-073d-46b9-9a18-73679e9eaf31 디렉토리가 삭제된다.
Ref: https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html
Ref: https://docs.aws.amazon.com/eks/latest/userguide/csi-iam-role.html
Ref: https://github.com/kubernetes-sigs/aws-ebs-csi-driver/tree/master/docs#set-up-driver-permission
Ref: https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/install.md
Ref: https://hyperconnect.github.io/2021/07/05/ebs-csi-gp3-support.html
kubernetes
eks
ebs
csi
controller
]