aews) ebs csi 체험기
3주차 스터디 내용은 ebs controller를 통해 pv와 pvc사용하는 방법을 공부했다. ebs controller 사용을 위해선 csi설치가 필요하다. eks 생성시 만들어지는 스토리지 드라이버를 사용하지 않고, 클러스터 외부에 있는 aws ebs 스토리지를 사용 할 수 있도록 해주는 것이다. 🔗
# default로 있는 sc를 확인해보면 Provisioner가 kubernetes.io/aws-ebs로 되어있다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k describe sc gp2
Name: gp2
IsDefaultClass: Yes
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"},"name":"gp2"},"parameters":{"fsType":"ext4","type":"gp2"},"provisioner":"kubernetes.io/aws-ebs","volumeBindingMode":"WaitForFirstConsumer"}
,storageclass.kubernetes.io/is-default-class=true
Provisioner: kubernetes.io/aws-ebs
Parameters: fsType=ext4,type=gp2
AllowVolumeExpansion: <unset>
MountOptions: <none>
ReclaimPolicy: Delete
VolumeBindingMode: WaitForFirstConsumer
ebs csi 설치
- 먼저 ebs를 관리할 수 있도록 csi driver에게 권한이 할당되어야한다. irsa를 사용하여 sa와 iam권한을 연결해준다. aws에서 관리하는 정책을 연결할 것이기때문에 따로 만들지 않아도 된다.
# irsa 설정 (이름은 동일해야한다)
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
# 확인
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# eksctl get iamserviceaccount ebs-csi-controller-sa --cluster myeks
NAMESPACE NAME ROLE ARN
kube-system ebs-csi-controller-sa arn:aws:iam::643127389001:role/AmazonEKS_EBS_CSI_DriverRole
- ebs csi driver addon
eksctl create addon --name aws-ebs-csi-driver --cluster ${CLUSTER_NAME} --service-account-role-arn arn:aws:iam::${ARN}:role/AmazonEKS_EBS_CSI_DriverRole --force
# 배포된 리소스 확인
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get deploy,ds -l=app.kubernetes.io/name=aws-ebs-csi-driver -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ebs-csi-controller 2/2 2 2 11m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/ebs-csi-node 3 3 3 3 3 kubernetes.io/os=linux 11m
daemonset.apps/ebs-csi-node-windows 0 0 0 0 0 kubernetes.io/os=windows 11m
# 파드안에 여러 컨테이너가 있는 것을 볼 수 있다. 확인인해보면 provisioner, attacher, snapshotter 등 각 기능들이 컨테이너로 들어가 있다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get pod -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driver
NAME READY STATUS RESTARTS AGE
ebs-csi-controller-67658f895c-7dj8c 6/6 Running 0 25m
ebs-csi-controller-67658f895c-9wjps 6/6 Running 0 25m
ebs-csi-node-7lcnl 3/3 Running 0 25m
ebs-csi-node-fzn9d 3/3 Running 0 25m
ebs-csi-node-pxrvt 3/3 Running 0 25m
# csi가 설치된 노드들도 확인해보자
# spec.drivers아래 보면 설치된 driver와 그 아래, allocatables에서 노드당 최대 연결할 수 있는 볼륨을 (ebs를)확인할 수 있다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl describe csinodes
Name: ip-192-168-1-58.ap-northeast-2.compute.internal
Labels: <none>
Annotations: storage.alpha.kubernetes.io/migrated-plugins:
kubernetes.io/aws-ebs,kubernetes.io/azure-disk,kubernetes.io/azure-file,kubernetes.io/cinder,kubernetes.io/gce-pd
CreationTimestamp: Thu, 11 May 2023 18:05:00 +0900
Spec:
Drivers:
ebs.csi.aws.com:
Node ID: i-03abd706aae96c603
Allocatables:
Count: 25
# 기본적으로 25개이며, 특정 인스턴스 타입에 따라 39개까지 가능하다.
Topology Keys: [topology.ebs.csi.aws.com/zone]
Events: <none>
...
ebs csi 동작
pv요청이 있을 시, csi-controller(deployment로 배포된)가 aws api를 호출하여 ebs를 생성하고 volume에 attach 한다. csi-node(daemonset으로 배포된)를 통해 volume을 pod에 mount시킨다.
이미지 출처는 악분님 블로그에서 가져왔다. 🔗
테스트
# 설치된 csi로 provisioner 설정하여 sc 생성
# 기존 기본으로 있는 스토리지 드라이버의 provisioner는 provisioner는 kubernetes.io/aws-ebs
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: gp3
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
allowAutoIOPSPerGBIncrease: 'true'
encrypted: 'true'
---
# 테스트 po,pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ebs-claim
spec:
accessModes:
- ReadWriteOnce
# etx4, xfs같은 fs은 nfs처럼 동시에 연결하여 사용할 수 없기 때문에 RWO으로 설정
resources:
requests:
storage: 4Gi
storageClassName: gp3
---
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
---
# 동적으로 잘 생성되어 붙은 것을 확인
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get pvc,pv,pod
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/ebs-claim Bound pvc-8c30b306-2853-4937-aedd-cb59bad3760b 4Gi RWO gp3 4m16s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-8c30b306-2853-4937-aedd-cb59bad3760b 4Gi RWO Delete Bound default/ebs-claim gp3 54s
NAME READY STATUS RESTARTS AGE
pod/app 1/1 Running 0 58s
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl get VolumeAttachment
NAME ATTACHER PV NODE ATTACHED AGE
csi-6b459f4ca202aeb1c2e56851103ce56553ebcd5bdeddbf63c15fd4e01f0ac766 ebs.csi.aws.com pvc-8c30b306-2853-4937-aedd-cb59bad3760b ip-192-168-3-6.ap-northeast-2.compute.internal true 52s
콘솔에서도 확인 가능
이렇게 생성된 ebs가 붙은 노드와 파드가 동일한 존에 있어야 할당이 된다. 기본적으로 노드가 각 존에 배치되지만, 만약 특정존에만 노드를 생성하였거나, 해당 존의 노드에 이미 할당된 수만큼의 볼륨이 붙었다면 새로운 노드가 배포되어야한다. 이를 위해 –balance-similar-node-groups 옵션을 사용하여 활성화 해줘야한다. (해당 옵션을 위해선 cluster autoscaler가 선행되어야한다 (🔗)https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/autoscaling.html) 지금 테스트환경에서는 볼륨을 붙이기에 충분히 여유있으므로, 위 작업 없이 진행하였다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# cat test.yaml
...
apiVersion: v1
kind: Pod
metadata:
name: test-app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: failure-domain.beta.kubernetes.io/zone
# 더이상 해당 key를 사용하지 않는다고 한다.
# node label을 확인해보면 topology.kubernetes.io/zone
operator: In
values:
- ap-northeast-2a
terminationGracePeriodSeconds: 3
containers:
- ...
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: test-claim
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k apply -f test.yaml
persistentvolumeclaim/test-claim created
Warning: spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key: failure-domain.beta.kubernetes.io/zone is deprecated since v1.17; use "topology.kubernetes.io/zone" instead
pod/test-app created
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k get po,pv,pvc
NAME READY STATUS RESTARTS AGE
pod/app 1/1 Running 0 103m
pod/test-app 1/1 Running 0 10m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-40f668d9-2750-45f4-a5f2-bd50deb3ef6f 4Gi RWO Delete Bound default/test-claim gp3 10m
persistentvolume/pvc-8c30b306-2853-4937-aedd-cb59bad3760b 4Gi RWO Delete Bound default/ebs-claim gp3 103m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/ebs-claim Bound pvc-8c30b306-2853-4937-aedd-cb59bad3760b 4Gi RWO gp3 106m
persistentvolumeclaim/test-claim Bound pvc-40f668d9-2750-45f4-a5f2-bd50deb3ef6f 4Gi RWO gp3 10m
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k get volumeattachment
NAME ATTACHER PV NODE ATTACHED AGE
csi-287da6a2b2414ed393feade04016f839a01e0bc577fb44f5a32891bd92e151b7 ebs.csi.aws.com pvc-40f668d9-2750-45f4-a5f2-bd50deb3ef6f ip-192-168-1-58.ap-northeast-2.compute.internal true 10m
csi-6b459f4ca202aeb1c2e56851103ce56553ebcd5bdeddbf63c15fd4e01f0ac766 ebs.csi.aws.com pvc-8c30b306-2853-4937-aedd-cb59bad3760b ip-192-168-3-6.ap-northeast-2.compute.internal true 103m
콘솔에서 확인 시 a존에 ebs가 생긴 것을 확인 할 수 있다.
snapshot
snapshot
# ebs controller pod 안을 보면 csi-snapshotter 컨테이너가 동작 중인 것을 알 수 있다.
# 해당 기능을 사용하기 위해서는 먼저 crd 설치가 필요하다
# volume sanpshot crd 설치
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl apply -f snapshot.storage.k8s.io_volumesnapshots.yaml,snapshot.storage.k8s.io_volumesnapshotclasses.yaml,snapshot.storage.k8s.io_volumesnapshotcontents.yaml
customresourcedefinition.apiextensions.k8s.io/volumesnapshots.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotclasses.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotcontents.snapshot.storage.k8s.io created
# rbac 설정과 snapshot controller 설치
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl apply -f rbac-snapshot-controller.yaml,setup-snapshot-controller.yaml
# snapshotclass 설치
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# curl -s -O https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/master/examples/kubernetes/snapshot/manifests/classes/snapshotclass.yaml
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl apply -f snapshotclass.yaml
# 사용하게될 snapshotclass
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k get volumesnapshotclass
NAME DRIVER DELETIONPOLICY AGE
csi-aws-vsc ebs.csi.aws.com Delete 4m39s
# snapshot을 하려하는 pvc와 위의 snapshotclass를 이용한다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# cat ebs-volume-snapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: ebs-volume-snapshot
spec:
volumeSnapshotClassName: csi-aws-vsc
source:
persistentVolumeClaimName: ebs-claim
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k get volumesnapshot
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE
ebs-volume-snapshot true ebs-claim 4Gi csi-aws-vsc snapcontent-c79ef8ed-e0d3-4beb-89a4-32acaf19d552 24s 24s
restore
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# cat ebs-snapshot-restore.yaml
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
---
apiVersion: v1
kind: Pod
metadata:
name: restore-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
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k get po,pvc
NAME READY STATUS RESTARTS AGE
pod/app 1/1 Running 0 119m
pod/restore-app 1/1 Running 0 20s
pod/test-app 1/1 Running 0 26m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/ebs-claim Bound pvc-8c30b306-2853-4937-aedd-cb59bad3760b 4Gi RWO gp3 122m
persistentvolumeclaim/ebs-snapshot-restored-claim Bound pvc-b22ea2c5-2926-4b79-8da0-ad285acde7e1 4Gi RWO gp3 2m21s
persistentvolumeclaim/test-claim Bound pvc-40f668d9-2750-45f4-a5f2-bd50deb3ef6f 4Gi RWO gp3 26m
fstype: xfs
csi로 설치된 controller의 컨테이너 중 csi-provisioner container를 살펴보면 –default-fstype이 ext4로 지정되어있다. 만들어서 사용했던 gp3 sc도 ex4를 기본으로 설정되어 테스트했었는데, xfs으로 한 경우 snapshot이 안될 수도 안될 수도 있다하여 확인차테스트해보았다.
# 먼저 sc를 생성해주었다. 아까와다른 점은 parameters.fsType: xfs 뿐이다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# cat testxfssc.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: xfs-gp3
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
allowAutoIOPSPerGBIncrease: 'true'
encrypted: 'true'
fsType: xfs
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# k get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
xfs-gp3 ebs.csi.aws.com Delete WaitForFirstConsumer true 19s
...
# 위에서 po,pvc로 배포했던 yaml에서 sc만 수정 후 동일하게 배포했다.
# 생성된 pod에 들어가서 확인해보니 mount가 잘되어있다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl exec -it xfs-test-app -- sh -c 'df -hT --type=xfs'
Filesystem Type Size Used Avail Use% Mounted on
/dev/nvme1n1 xfs 4.0G 62M 4.0G 2% /data
/dev/nvme0n1p1 xfs 30G 3.6G 27G 12% /etc/hosts
xfs snapshot & restore
# snapshot
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# cat xfs-snapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: xfs-volume-snapshot
spec:
volumeSnapshotClassName: csi-aws-vsc
source:
persistentVolumeClaimName: xfs-test-claim
# restore
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# cat xfs-restore-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: xfs-snapshot-restored-claim
spec:
storageClassName: xfs-gp3
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 4Gi
dataSource:
name: xfs-volume-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
# sc를 잘 붙여주고 복구했다면, 이상없이 pod에 붙는 것을 확일 할 수 있다.
(nyoung@myeks:default) [root@myeks-bastion-EC2 ~]# kubectl exec -it restore-app-xfs -- sh -c 'df -hT --type=xfs'
Filesystem Type Size Used Avail Use% Mounted on
/dev/nvme2n1 xfs 4.0G 62M 4.0G 2% /data
/dev/nvme0n1p1 xfs 30G 3.7G 27G 13% /etc/hosts
복구된 파일 내용을 확인해보면 snapshot을 찍고 restore되는 시간이 비어있는 것을 볼 수 있다.
참고
- https://kubernetes.io/blog/2021/12/10/storage-in-tree-to-csi-migration-status-update/
- https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/managing-ebs-csi.html
- https://aws.github.io/aws-eks-best-practices/reliability/docs/dataplane/#ensure-capacity-in-each-az-when-using-ebs-volumes
- https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/ebs-sample-app.html
- https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html
- https://aws.amazon.com/ko/blogs/containers/using-ebs-snapshots-for-persistent-storage-with-your-eks-cluster/