Pod가 EBS를 사용하려면 CSI Controller, CSI-Node가 필요하다
출처 : https://malwareanalysis.tistory.com/598

| 구성요소 | 역할 |
|---|---|
| External Provisioner | PVC를 기반으로 EBS 볼륨을 동적으로 생성 |
| External Attacher | Kubernetes에서 ControllerPublishVolume을 호출하여 EBS 볼륨을 특정 노드에 Attach |
| External Resizer | 볼륨 크게 요청이 들어오면 ControllerExpandVolume 을 호출하여 볼륨 크기 조절 |
| External Snapshotter | 볼륨의 스냅샷을 관리 |
| Control Service | EBS 볼륨의 생성, 삭제, Attach/Detach, 크기 조정 등의 제어 작업을 수행하는 CSI 컨트롤러 컴포넌트 |
# 아래는 aws-ebs-csi-driver 전체 버전 정보와 기본 설치 버전(True) 정보 확인
aws eks describe-addon-versions \
--addon-name aws-ebs-csi-driver \
--kubernetes-version 1.31 \
--query "addons[].addonVersions[].[addonVersion, compatibilities[].defaultVersion]" \
--output text# 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
# ISRA 확인
eksctl get iamserviceaccount --cluster ${CLUSTER_NAME} 
# 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 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


kubectl get pod -n kube-system -l app=ebs-csi-controller -o jsonpath='{.items[0].spec.containers[*].name}' ; echo 
kubectl api-resources | grep -i csi
kubectl get csinodes
kubectl describe csinodes
kubectl get csidrivers
kubectl describe csidrivers ebs.csi.aws.com

# 방법 1
aws eks update-addon --cluster-name ${CLUSTER_NAME} --addon-name aws-ebs-csi-driver \
--addon-version v1.39.0-eksbuild.1 --configuration-values '{
"node": {
"volumeAttachLimit": 31,
"enableMetrics": true
}
}'
# 방법 2
*cat << EOF > node-attachments.yaml
"node":
"volumeAttachLimit": 31
"enableMetrics": true
EOF
aws eks update-addon --cluster-name ${CLUSTER_NAME} --addon-name aws-ebs-csi-driver \
--addon-version v1.39.0-eksbuild.1 --configuration-values 'file://node-attachments.yaml'
#확인 명령어
kubectl describe csinodes
kubectl get ds -n kube-system ebs-csi-node -o yaml 위의 명령어를 실행 하였을때 EBS 부착수량이 31으로 변경 된것을 확인할수 있다. 

# 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
kubectl describe sc gp3 | grep Parameters

여기서 VolumeBindingMode 란?
⇒ 볼륨 바인딩 , 동적 프로비저닝 시작 시기를 제어
Immediate(기본값)WaitForFirstConsumernodeSelector, affinity)을 고려한 후에 바인딩되므로, 클러스터 리소스를 더 효율적으로 사용 가능.# 워커노드에서 파드에 추가한 EBS 볼륨 모니터링
while true; do aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" --output text; date; sleep 1; done
# 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모니터링 후 파드를 생성하면 EBS가 생성 된것을 확인 할수 있습니다.


해당 내용은 Console에서도 확인이 가능합니다.

추가된 EBS 볼륨 상세 확인
# 추가된 EBS 볼륨 상세 정보 확인 : AWS 관리콘솔 EC2(EBS)에서 확인
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq

kubectl get node --label-columns=topology.ebs.csi.aws.com/zone,topology.k8s.aws/zone-id
# 파일 내용 추가 저장 확인
kubectl exec app -- tail -f /data/out.txt
## 파드 내에서 볼륨 정보 확인
kubectl exec -it app -- sh -c 'df -hT --type=overlay'
kubectl exec -it app -- sh -c 'df -hT --type=xfs' 
만약 볼륨 증가가 필요하면 다음과 같이 적용 가능 ,단 볼륨을 줄일 순 없다.
볼륨 증가
# 볼륨 증가
kubectl patch pvc ebs-claim -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'

확인
kubectl exec -it app -- sh -c 'df -hT --type=xfs'
kubectl df-pv
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq


Snapshot CRDs 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl get crd | grep snapshot
kubectl api-resources | grep snapshot

Common Snapshot Controller 설치
# Install Common Snapshot Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
kubectl get deploy -n kube-system snapshot-controller
kubectl get pod -n kube-system

SnapshotClass 설치
# Install Snapshotclass
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/master/examples/kubernetes/snapshot/manifests/classes/snapshotclass.yaml
kubectl get vsclass # 혹은 volumesnapshotclasses
kubectl describe vsclass

# 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
# 파일 내용 추가 저장 확인
kubectl exec app -- tail -f /data/out.txt 

VolumeShot 생성
# VolumeSnapshot 생성 : Create a VolumeSnapshot referencing the PersistentVolumeClaim name
# AWS 관리 콘솔 EBS 스냅샷 확인
cat <<EOF | kubectl apply -f -
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: ebs-volume-snapshot
spec:
volumeSnapshotClassName: csi-aws-vsc
source:
persistentVolumeClaimName: ebs-claim
EOF
# VolumeSnapshot 확인
kubectl get volumesnapshot
kubectl get volumesnapshot ebs-volume-snapshot -o jsonpath={.status.boundVolumeSnapshotContentName} ; echo
kubectl describe volumesnapshot.snapshot.storage.k8s.io ebs-volume-snapshot
kubectl get volumesnapshotcontents
# VolumeSnapshot ID 확인
kubectl get volumesnapshotcontents -o jsonpath='{.items[*].status.snapshotHandle}' ; echo
# AWS EBS 스냅샷 확인
aws ec2 describe-snapshots --owner-ids self | jq
aws ec2 describe-snapshots --owner-ids self --query 'Snapshots[]' --output table


# app & pvc 제거 : 강제로 장애 재현
kubectl delete pod app && kubectl delete pvc ebs-claim 
스냅샷으로 복원
kubectl get pvc,pv
# 스냅샷에서 PVC 로 복원
cat <<EOF | kubectl apply -f -
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
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-snapshot-restored-claim
EOF 
파일 내용 확인
파드 삭제 전 의 기록, 파드 재생성 후의 기록이 잘 저장 됨
# 파일 내용 저장 확인 : 파드 삭제 전까지의 저장 기록이 남아 있다. 이후 파드 재생성 후 기록도 잘 저장되고 있다
kubectl exec app -- cat /data/out.txt

# 삭제
kubectl delete pod app && kubectl delete pvc ebs-snapshot-restored-claim && kubectl delete volumesnapshots ebs-volume-snapshot
출처 : https://dev.to/awscommunity-asean/aws-eks-with-efs-csi-driver-and-irsa-using-cdk-dgc
# EFS 정보 확인
aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text 
aws eks describe-addon-versions \
--addon-name aws-efs-csi-driver \
--kubernetes-version 1.31 \
--query "addons[].addonVersions[].[addonVersion, compatibilities[].defaultVersion]" \
--output text

IRSA 설정 및 확인
# ISRA 설정 : 고객관리형 정책 AmazonEKS_EFS_CSI_Driver_Policy 사용
eksctl create iamserviceaccount \
--name efs-csi-controller-sa \
--namespace kube-system \
--cluster ${CLUSTER_NAME} \
--attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEFSCSIDriverPolicy \
--approve \
--role-only \
--role-name AmazonEKS_EFS_CSI_DriverRole
# ISRA 확인
eksctl get iamserviceaccount --cluster ${CLUSTER_NAME}

# Amazon EFS CSI driver addon 배포(설치)
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
eksctl create addon --name aws-efs-csi-driver --cluster ${CLUSTER_NAME} --service-account-role-arn arn:aws:iam::${ACCOUNT_ID}:role/AmazonEKS_EFS_CSI_DriverRole --force
kubectl get sa -n kube-system efs-csi-controller-sa -o yaml | head -5 
# 확인
eksctl get addon --cluster ${CLUSTER_NAME}
kubectl get pod -n kube-system -l "app.kubernetes.io/name=aws-efs-csi-driver,app.kubernetes.io/instance=aws-efs-csi-driver"
kubectl get pod -n kube-system -l app=efs-csi-controller -o jsonpath='{.items[0].spec.containers[*].name}' ; echo
kubectl get csidrivers efs.csi.aws.com -o yaml 
# 노드 모니터링
watch 'kubectl get sc efs-sc; echo; kubectl get pv,pvc,pod'# [운영 서버 EC2]
# 실습 코드 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 스토리지클래스 생성 및 확인
cat storageclass.yaml
kubectl apply -f storageclass.yaml
kubectl get sc efs-sc 
# PV 생성 및 확인 : volumeHandle을 자신의 EFS 파일시스템ID로 변경
EfsFsId=$(aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text)
sed -i "s/fs-4af69aab/$EfsFsId/g" pv.yaml
cat pv.yaml
kubectl apply -f pv.yaml
kubectl get pv; kubectl describe pv 
# PVC 생성 및 확인
cat claim.yaml
kubectl apply -f claim.yaml
kubectl get pvc 
# 파드 생성 및 연동 : 파드 내에 /data 데이터는 EFS를 사용
# 추후에 파드1,2가 각기 다른 노드에 배포되게 추가해두자!
cat pod1.yaml pod2.yaml
kubectl apply -f pod1.yaml,pod2.yaml
kubectl df-pv# 파드 정보 확인 : PV에 5Gi 와 파드 내에서 확인한 NFS4 볼륨 크리 8.0E의 차이는 무엇?
kubectl get pods
kubectl exec -ti app1 -- sh -c "df -hT -t nfs4"
kubectl exec -ti app2 -- sh -c "df -hT -t nfs4" 
# 공유 저장소 저장 동작 확인
tree /mnt/myefs # 운영서버 EC2 에서 확인
tail -f /mnt/myefs/out1.txt # 운영서버 EC2 에서 확인
tail -f /mnt/myefs/out2.txt # 운영서버 EC2 에서 확인
kubectl exec -ti app1 -- tail -f /data/out1.txt
kubectl exec -ti app2 -- tail -f /data/out2.txt 


# [운영 서버 EC2]
# EFS 스토리지클래스 생성 및 확인
curl -s -O https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml
cat storageclass.yaml
sed -i "s/fs-92107410/$EfsFsId/g" storageclass.yaml
kubectl apply -f storageclass.yaml
kubectl get sc efs-sc 
curl -s -O https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/pod.yaml
cat pod.yaml
kubectl apply -f pod.yaml
kubectl get pvc,pv,pod 
kubectl krew install stern
kubectl stern -n kube-system -l app=efs-csi-controller -c csi-provisioner 
kubectl exec -it efs-app -- sh -c "df -hT -t nfs4" 
tree /mnt/myefs # 운영서버 EC2 에서 확인
kubectl exec efs-app -- bash -c "cat /data/out"
kubectl exec efs-app -- bash -c "ls -l /data/out"
kubectl exec efs-app -- bash -c "stat /data/" 

| 특징 | 일반적인 EFS 사용 | EFS Access Point 사용 |
|---|---|---|
| 접근 방식 | 파일 시스템 전체 접근 | Access Point별 특정 디렉터리 접근 |
| 보안 | IAM으로 파일 시스템 전체 권한 관리 | Access Point별 IAM 권한 관리로 보안 강화 |
| 관리 | 여러 사용자 권한 관리 부담 | Access Point별 권한 관리로 용이 |
| 사용 사례 | 단순 환경, 파일 시스템 전체 접근 필요 | 다중 사용자 환경, 애플리케이션별 접근 제한 필요 |