본문 바로가기

DevOps

[AWS EKS] EKS CSi driver와 NFS provisioner

CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.

✅   Storage 소개                                                                                                                                       

 

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

 

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

 

✅   Kubernetes에서 스토리지를 사용할때 이해 해야 할 점                                                                    

🚫 Stateful 하게 관리되는 리소스가 아니고 상태가 없는(Stateless) 애플리케이션이기 때문에 영구 스토리지가 없으면 Pod가 충돌하거나 종료되고, Pod의 데이터는 손실됩니다.

  • 현재 호스트의 디스크 공간을 확인 해보자

  • EFS를 Mount 해보자 Network 파일시스템을 마운트 하여 사용하게 되면 가상머신이 사라지거나 umount 하더라도 내부의 데이터는 유실되지 않는다
  • 이러한 특징을 사용해서 쿠버네티스에서도 네트워크 파일시스템을 PV,PVC로 만들어 사용하는 방식이 존재한다.
$ mount -t efs -o tls $EFS-ID:/ /mnt/myefs
$ df -h 
# 127.0.0.1:/     8.0E     0  8.0E   0% /mnt/myefs

$ cd /mnt/myefs
$ echo "hello" >> hello.txt
$ cat hello.txt
hello

$ reboot
$ mount -t efs -o tls $EFS-ID:/ /mnt/myefs
$ cat /mnt/myefs/hello.txt
hello

 

✅   Kubernetes nfs provisioner 실습                                                                  

 

  • Cloud formation 배포를 위해  AWS IAM이 등록된 곳에서 다음과 같이 접속합니다.
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/Ansible/a101-2w.yaml

# CloudFormation 스택 배포
aws cloudformation deploy --template-file a101-2w.yaml --stack-name mylab --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2 --capabilities CAPABILITY_NAMED_IAM

# Ansible Server EC2 SSH 접속
ssh -i ~/.ssh/kp-gasida.pem ubuntu@$(aws cloudformation describe-stacks --stack-name mylab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2)
  • Ansible-server에 접속합니다. ( 해당 서버에는 앤서블을 설치하기 위해 먼저 파이썬이 설치되어있는지 확인합니다.)
ssh -i koo-seoul.pem ubuntu@$(aws cloudformation describe-stacks --stack-name mylab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2)

# 접속 완료 

# /etc/hosts 확인
cat /etc/hosts

###
10.10.1.10 server
10.10.1.11 tnode1
10.10.1.12 tnode2
10.10.1.13 tnode3
###

# 노드간 통신 확인
for i in {1..3}; do ping -c 1 tnode$i; done


# sudo -i
pwd
# /root/my-ansible

python --version
# 3.10.12

# 확인 : 책 버전(파이썬 3.11.2, jinja 진자 3.1.2)
ansible --version
ansible [core 2.15.8]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True
  • ssh 접근을 위해 설정합니다.
  • ssh-keygen 명령어를 통해 SSH키를 생성합니다. 그리고 공유키를 node 3대에 각각 전송합니다.
# 앤서블 접근을 위한 SSH 인증 구성 및 확인
ssh-keygen -t rsa -N "" -f /home/ubuntu/.ssh/id_rsa
tree ~/.ssh

# 공개 키를 관리 노드에 복사 : yes -> 암호(qwe123) 입력
for i in {1..3}; do ssh-copy-id ubuntu@tnode$i; done

# 복사 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i cat ~/.ssh/authorized_keys; echo; done
  • ansible-kubespray는 네이티브 쿠버네티스를 설치 자동화 하는 ansible의 모듈입니다.
  • Kubespray란? kubernetes를 쉽게 설치하게 도와주는 자동화 도구로 ansible을 통해 구축하고자하는 설정 값만 맞게 변경해주어 실행하면 kubernetes cluster 구축을 자동으로 해주는 편리한 도구입니다.
# kubespray을 통해 native k8s를 설치하겠습니다.
git clone https://github.com/kubernetes-sigs/kubespray

# 경로를 kubespray로 바꿔줍니다.
cd kubespray

# Copy ``inventory/sample`` as ``inventory/mycluster``
cp -rfp inventory/sample inventory/mycluster

# Update Ansible inventory file with inventory builder
declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)

# pip install && ruamel.yml 
sudo apt install python3-pip
pip install ruamel.yaml
pip install netaddr

# Update Ansible inventory file with inventory builder
CONFIG_FILE=inventory/mycluster/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
  • 플레이북 실행 ( 쿠버네티스 설치 시작)
# Deploy Kubespray with Ansible Playbook 플레이북을 루트 계정으로 실행함

ansible-playbook -i inventory/mycluster/hosts.yaml  --become --become-user=root cluster.yml
  • 설치완료 후 확인, node1에 ssh접속후 확인
root@node1:~# kubectl get nodes 
NAME    STATUS   ROLES           AGE   VERSION
node1   Ready    control-plane   26m   v1.28.5
node2   Ready    control-plane   26m   v1.28.5
node3   Ready    <none>          25m   v1.28.5

우선 여기까지 실습을 하기 위한 환경을 구성했습니다. 수고 많으셨습니다. 

이제 nfs를 준비해보겠습니다. nfs는 앤서블 서버로 쓰고 있는 서버에 구축하도록 하겠습니다.

# tnode1서버에서 ssh key를 만듭니다.

ssh-keygen -t rsa -N "" -f /home/ubuntu/.ssh/id_rsa
tree ~/.ssh

# 공개 키를 관리 노드에 복사 : yes -> 암호(qwe123) 입력
ssh-copy-id 10.10.1.10 

# 이제 관리서버를 nfs 서버로 사용할것 입니다. 관리서버와 node1간에는 ssh-key를 이용해서 패스워드 없이 서로 접근이 가능합니다.
# 관리 서버에 접속해서 nfs를 설치합니다.
# 편의상 nfs 서버로 hostnamectl로 호스트네임을 변경하겠습니다.

ubuntu@nfs:~$ sudo apt install nfs-kernel-server
ubuntu@nfs:~$ mkdir /data

/data 10.10.1.11(rw,sync,no_subtree_check,no_root_squash)
/data 10.10.1.12(rw,sync,no_subtree_check,no_root_squash)
/data 10.10.1.13(rw,sync,no_subtree_check,no_root_squash)

ubuntu@nfs# systemctl enable nfs-server.service --now

ubuntu@nfs:~$ showmount -e 10.10.1.10
Export list for 10.10.1.10:
/data 10.10.1.13,10.10.1.12,10.10.1.11


# 클라이언트 서버에서도 설치해줘야 하는게 있음
# 각노드에 들어가서 nfs client install
sudo apt update
sudo apt install nfs-common

 

여기까지 nfs 서버에서 필요한 작업은 끝났습니다. 

컨트롤플레인 노드와 워커노드를 nfs 클라이언트로 사용할수 있습니다. 

이제 nfs-provisioner을 설치합시다. ( 벤더 별 네트워크 파일시스템 마다 provisioner을 다 제공함 ) - 즉, 쉽게 말해서 

내가 weka 스토리지 , nfs 스토리지, ebs 스토리지를 쓰고싶으면 각 provisioner을 설치하고 버전 업을 계속 해줘야 하는 엄청 끔찍한 

공수가 든다는 말임.

 

AWS와의 차이점이 EKS는 이러한 각기 다른 provisioner을 안쓰고 CSI driver을 통해 별도의 controller Pod을 통해 제약 사항을 

해소했음.

 

  • 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 입니다
# node1번에 접속합니다. 쿠버네티스 컨트롤 플레인 노드입니다.
# EKS에서 우리가 알고 있는 컨트롤 플레인 영역이랑 k8s의 컨트롤 플레인 노드는 약간 개념자체가 다릅니다.
# EKS에서는 etcd,api서버,스케쥴러등을 컨트롤 플레인 영역에 빼서 관리하지만 
# native k8s은 모든 노드에 해당 요소들이 같이 설치가 됩니다.

$ mkdir -p /nfsprovider
$ cd /nfsprovider
$ git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
$ cd nfs-subdir-external-provisioner/deploy

$ vim deployment.yaml
#
# NFS 서버의 IP로 아래에서 2번째줄, 8번째줄 바꾸고
# NFS 공유 디렉토리로 맨 아래줄, 아래에서 7번째줄 바꾸고 배포


kubectl apply -f class.yaml
kubectl apply -f deployment.yaml
kubectl apply -f rbac.yaml

root@node1:~/nfs/nfs-subdir-external-provisioner/deploy# kubectl get all
NAME                                          READY   STATUS    RESTARTS   AGE
pod/nfs-client-provisioner-6ff657c9cd-85g4r   1/1     Running   0          3m51s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.233.0.1   <none>        443/TCP   98m

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nfs-client-provisioner   1/1     1            1           3m51s

NAME                                                DESIRED   CURRENT   READY   AGE
replicaset.apps/nfs-client-provisioner-6ff657c9cd   1         1         1       3m51s

 

정확한 개념을 이해하기 위해서 nfs-client-provisioner과 CSI-driver의 차이점을 비교하면서 학습하는것이 좋다.

우리는 스터디 시간에 Amazon EBS CSI driver을 배우기 때문에 나중에 비교하면서 보면 좋을거 같다.

# nfs-provisioner 설치하면 storageclass가 생성된다.
# 추가로 sc를 더 만들수도 있다.

root@node1:~# kubectl get sc
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  4h54m

 

지금까지 nfs-provisioner을 배포했으니까 1,2번 순서까지는 끝난거다.

pvc만 사용자가 만들면 pv는 provisioner가 자동으로 만들어주고

pod를  pv와 pvc를 기술해서 만들면 동적 프로비저닝이 된다.

 

https://happycloud-lee.tistory.com/256

 

  • pvc 생성 : 위의 그림을 보면 알겠지만 pvc에는 스토리지 클래스 이름이 종속성으로 들어가야한다.
root@node1:~/yaml# vi pvc.yaml


kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi
# pvc를 만드는 순간 
# nfs 서버의 /data 디렉토리를 보면 다음과 같이 디렉토리가 생성되있다.

ubuntu@nfs:/data$ ls
default-test-claim-pvc-675143a6-e45b-4342-9dc0-e8ea53dadb53

cd default-test-claim-pvc-675143a6-e45b-4342-9dc0-e8ea53dadb53/
ls

# 아무것도 없다.
  • 파드 생성 
cat <<EOT > nfs-pod.yaml
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: test-claim
EOT
# nfs서버에 아까 만들어졌던 볼륨을 확인해보자
# out.txt가 생성되어있어야한다.



ubuntu@nfs:/data/default-test-claim-pvc-675143a6-e45b-4342-9dc0-e8ea53dadb53$ ls
out.txt

ubuntu@nfs:/data/default-test-claim-pvc-675143a6-e45b-4342-9dc0-e8ea53dadb53$ cat out.txt
Thu Mar 21 14:44:45 UTC 2024
Thu Mar 21 14:44:50 UTC 2024
Thu Mar 21 14:44:55 UTC 2024

 

여기까지 nfs-provisioner에 대해서 실습해보았다.사실상 온프렘에서 쿠버네티스를 쓰는 고객들 대부분이 nfs-provisioner을 굉장히 많이 쓴다.

 

장점:  굉장히 쉽게 사용할수 있다, 쿠버네티스 공용만을 이용하기 때문에 벤더 락인이 없다

단점:  업그레이드 버전이 나올때마다 각 벤더사마다 provisioner을 손수 업그레이드 해야함

✅   EBS CSI Controller 소개                                                                                                                

  • NFS Provisoner과 비교했을때 역할에서는 별다른 차이점은 없다.
  • CSI-Controller와 CSI-node가 각각의 역할을 하는걸 그림으로 확인하자.
  • StatefulSet 또는 Deployment로 배포된 controller Pod이 AWS API를 사용하여 실제 EBS volume을 생성하는 역할
  • DaemonSet으로 배포된 node Pod은 AWS API를 사용하여 Kubernetes node (EC2 instance)에 EBS volume을 attach

✅   Amazon EBS CSI driver 실습                                                                                   

  • 설치 방법 
# 아래는 aws-ebs-csi-driver 전체 버전 정보와 기본 설치 버전(True) 정보 확인
aws eks describe-addon-versions \
    --addon-name aws-ebs-csi-driver \
    --kubernetes-version 1.28 \
    --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 myeks
NAMESPACE	    NAME				            ROLE ARN
kube-system 	ebs-csi-controller-sa		arn:aws:iam::911283464785:role/AmazonEKS_EBS_CSI_DriverRole
...

# 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
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

# ebs-csi-controller 파드에 6개 컨테이너 확인
kubectl get pod -n kube-system -l app=ebs-csi-controller -o jsonpath='{.items[0].spec.containers[*].name}' ; echo
ebs-plugin csi-provisioner csi-attacher csi-snapshotter csi-resizer liveness-probe

# csinodes 확인
kubectl get csinodes
  • 설치 완료 후 gp2(defulat) 스토리지 클래스만 만들어져 있는 상태

  • gp3 storageclass 만들어보기

gp2는 기존 SSD gp2 볼륨을 사용하여 스토리지 용량에 맞춰 성능이 확장된다. 
하지만 gp3는 볼륨 크기와 관계없이 3000IOPS 기준 성능과 125Mib/s를 제공한다.
gp3의 최고성능은 gp2 볼륨의 최대 처리량보다 4배 빠르지만, gp2 볼륨보다 GiB당 20% 저렴하다.

 

# 스토리지 클래스 생성
cat <<EOT > gp3-sc.yaml
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
EOT

# 배포
kubectl apply -f gp3-sc.yaml

# 확인

kubectl get sc
kubectl describe sc gp3 | grep Parameters

 

  • 배포는 pvc를 먼저 배포한 후에 pod를 배포해야 합니다. pod가 배포 되어야 pvc는 바인딩으로 바뀝니다.
cat <<EOT > awsebs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  storageClassName: gp3
EOT
  • 배포 후 pvc의 정보를 확인해보면 (describe)
  •  ‘첫번째 사용자가 연결하기를 기다린다(waiting for first consumer to be created before binding)’입니다. ebs-sc 스토리지 클래스의 속성을 확인하면 ‘VOLUMEBINDINGMODE – WaitForFirstConsumer’ 입니다.
  • 파드가 아직 해당 PVC를 연결하지 않아 PVC가 아직 생성되지 않고 지연(‘Pending’) 상태입니다.

  • pod를 배포해봅시다.
# 파드 생성
cat <<EOT > awsebs-pod.yaml
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
EOT
kubectl apply -f awsebs-pod.yaml

# PVC, 파드 확인
kubectl get pvc,pv,pod
kubectl get VolumeAttachment
kubectl get pv -o yaml | yh
...
    nodeAffinity:
      required:
        nodeSelectorTerms:
        - matchExpressions:
          - key: topology.ebs.csi.aws.com/zone
            operator: In
            values:
            - ap-northeast-2b
...

  • 볼륨 증가 - 링크늘릴수는 있어도 줄일수는 없단다! - 링크
# 현재 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 patch pvc ebs-claim -p '{"status":{"capacity":{"storage":"10Gi"}}}' # status 는 바로 위 커멘드 적용 후 EBS 10Gi 확장 후 알아서 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
  • gp3 의 특징은 IOPS 증가가 볼륨의 프로비저닝 없이 가능하다 
  • 하지만 csi driver 버전 차이인지 현재는 적용이 안된다. 하지만 명령어는 알아두자 추후에 되겠지.
#
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq
kubectl annotate pvc ebs-claim ebs.csi.aws.com/iops=5000
...

#
kubectl get pvc ebs-claim -o yaml | kubectl neat | yh
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq
  • 볼륨 스냅샷 컨트롤러 설치
# (참고) EBS CSI Driver에 snapshots 기능 포함 될 것으로 보임
kubectl describe pod -n kube-system -l app=ebs-csi-controller

# Install 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
kubectl get crd | grep snapshot
kubectl api-resources  | grep snapshot

# Install Common 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
kubectl get deploy -n kube-system snapshot-controller
kubectl get pod -n kube-system -l app=snapshot-controller

# Install 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
kubectl get vsclass # 혹은 volumesnapshotclasses
  • pvc/pod 생성 테스트
# PVC 생성
kubectl apply -f awsebs-pvc.yaml

# 파드 생성
kubectl apply -f awsebs-pod.yaml

# 파일 내용 추가 저장 확인
kubectl exec app -- tail -f /data/out.txt

# VolumeSnapshot 생성 : Create a VolumeSnapshot referencing the PersistentVolumeClaim name >> EBS 스냅샷 확인
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/ebs-volume-snapshot.yaml
cat ebs-volume-snapshot.yaml | yh
kubectl apply -f ebs-volume-snapshot.yaml

# 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
  • 스냅샷으로 복원
# 스냅샷에서 PVC 로 복원
kubectl get pvc,pv
cat <<EOT > ebs-snapshot-restored-claim.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
EOT
cat ebs-snapshot-restored-claim.yaml | yh
kubectl apply -f ebs-snapshot-restored-claim.yaml

# 확인
kubectl get pvc,pv

# 파드 생성
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/ebs-snapshot-restored-pod.yaml
cat ebs-snapshot-restored-pod.yaml | yh
kubectl apply -f ebs-snapshot-restored-pod.yaml

# 파일 내용 저장 확인 : 파드 삭제 전까지의 저장 기록이 남아 있다. 이후 파드 재생성 후 기록도 잘 저장되고 있다
kubectl exec app -- cat /data/out.txt
...
Sat Mar 23 08:31:32 UTC 2024
Sat Mar 23 08:31:37 UTC 2024
Sat Mar 23 08:31:42 UTC 2024
Sat Mar 23 08:31:47 UTC 2024
...

# 삭제
kubectl delete pod app && kubectl delete pvc ebs-snapshot-restored-claim && kubectl delete volumesnapshots ebs-volume-snapshot