이번주에는 스토리지와 관련된 부분을 배웠습니다. 순서는 EKS 배포 환경, LB, External DNS 등 2주차 내용에 이어 추가적으로 진행하는 부분, 스토리지에 대한 이해와 각 방식에 대한 실습을 진행한 뒤 EBS, EFS 를 적용해보는 것으로 마무리됩니다.
환경배포파일이 저번주와 달라졌습니다. 기존에 것에서 저번주차와 이번주차 진행할 내용들이 추가되었습니다.
앞으로 실습내용을 작업용 EC2에서도 확인하기 위해 EFS를 마운트합니다.
mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ***<자신의 EFS FS ID>***.efs.ap-northeast-2.amazonaws.com:/ /mnt/myefs
kubectl config rename-context admin@myeks.ap-northeast-2.eksctl.io [원하는 이름]@myeks
실습환경에서 AWS LB/ExternalDNS, kube-ops-view를 추가적으로 설치합니다. 설치과정은 아래에서 확인할 수 있습니다.
먼저, 기본적인 환경세팅을 진행합니다. 아까 위에서 나왔던 context 변경부터 진행합니다.
context 변경
# context 변경
(EKS-study@myeks:N/A) [root@myeks-bastion-EC2 ~] # kubectl config rename-context EKS-study@myeks.ap-northeast-2.eksctl.io $NICK@myeks
Context "EKS-study@myeks.ap-northeast-2.eksctl.io" renamed to "kane@myeks".
(kane@myeks:N/A) [root@myeks-bastion-EC2 ~] #
storage class 확인
kubectl get sc gp2 -o yaml | yh
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
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"
creationTimestamp: "2023-05-07T14:02:40Z"
name: gp2
resourceVersion: "266"
uid: b8040117-dce8-4173-b8d4-2a77d7a8124f
parameters:
fsType: ext4
type: gp2
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
이제 eks의 모든 노드들이 csinode인지 확인합니다.
csinodes
"kubectl get csinodes" 명령은 Kubernetes 클러스터에서 사용 가능한 모든 CSINode(CSI Node)을 나열합니다. CSINode은 Container Storage Interface(CSI) 스펙을 준수하는 노드입니다. CSI 스펙은 Kubernetes 클러스터에서 다양한 스토리지 시스템과의 통합을 위한 표준 인터페이스를 제공합니다.
$k get csinodes
NAME DRIVERS AGE
ip-192-168-1-137.ap-northeast-2.compute.internal 0 26m
ip-192-168-2-116.ap-northeast-2.compute.internal 0 26m
ip-192-168-3-151.ap-northeast-2.compute.internal 0 26m
--label-columns
옵션을 통해 eks node를 조회한 모습입니다.
$kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
NAME STATUS ROLES AGE VERSION INSTANCE-TYPE CAPACITYTYPE ZONE
ip-192-168-1-137.ap-northeast-2.compute.internal Ready <none> 29m v1.24.11-eks-a59e1f0 t3.medium ON_DEMAND ap-northeast-2a
ip-192-168-2-116.ap-northeast-2.compute.internal Ready <none> 29m v1.24.11-eks-a59e1f0 t3.medium ON_DEMAND ap-northeast-2b
ip-192-168-3-151.ap-northeast-2.compute.internal Ready <none> 29m v1.24.11-eks-a59e1f0 t3.medium ON_DEMAND ap-northeast-2c
$eksctl get iamidentitymapping --cluster myeks
ARN USERNAME GROUPS ACCOUNT
arn:aws:iam::871103481195:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-WBR1ZJTQNHTR system:node:{{EC2PrivateDNSName}} system:bootstrappers,system:nodes
보안그룹 추가
"--protocol '-1'"은 모든 프로토콜을 허용하도록 설정하는 것을 의미합니다. 이 플래그를 사용하여 TCP, UDP 및 ICMP를 비롯한 모든 프로토콜에 대한 트래픽을 허용할 수 있습니다.
"--cidr"은 허용할 IP 대역을 지정합니다. 여기서는 "192.168.1.100/32"라는 단일 IP 주소를 허용하도록 설정하였습니다.
$aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32
{
"Return": true,
"SecurityGroupRules": [
{
"SecurityGroupRuleId": "sgr-0bb4b08586cfb50c5",
"GroupId": "sg-0c78cd151603fbd80",
"GroupOwnerId": "871103481195",
"IsEgress": false,
"IpProtocol": "-1",
"FromPort": -1,
"ToPort": -1,
"CidrIpv4": "192.168.1.100/32"
}
]
}
aws-load-balancer-controller 설치한다.
$helm repo add eks https://aws.github.io/eks-charts
"eks" has been added to your repositories
$helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "eks" chart repository
Update Complete. ⎈Happy Helming!⎈
$helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME \
> --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller
NAME: aws-load-balancer-controller
LAST DEPLOYED: Sun May 7 23:47:07 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
AWS Load Balancer controller installed!
External DNS 적용 : 개인 도메인은 사전에 준비필요!
$echo $MyDomain, $MyDnzHostedZoneId
kaneawsdns.com, /hostedzone/Z06702063E7RRITLLMJRM
#사전에 관련 매니패스트 파일을 준비해주셨다.
$curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml
# External DNS 배포
$MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -
위의 envsubst
명령어에 대한 간단한 설명
envsubst
: 현재 환경변수를 수레에서 사용가능한 변수로 치한 → 앞의 MyDomain, MyDnzHostedZoneId를 알맞게 externaldns.yaml 파일에 적용킨 후 해당 yaml 파일을 kubectl apply
합니다.
매니패스트 파일은 service account, cluster role, cluster role binding, deployment, service, configmap 등이 포함되어 있습니다. 토글에는 자세한 내용이 담겨있습니다. 자세한 내용은 링크를 통해서 확인할 수 있습니다.
이제 UI 툴인 kube-ops-view를 설치해보겠습니다.
kubeops 설치
#repo 추가
$helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
"geek-cookbook" has been added to your repositories
#kube-ops-view 설치
$helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
NAME: kube-ops-view
LAST DEPLOYED: Sun May 7 23:53:13 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace kube-system -l "app.kubernetes.io/name=kube-ops-view,app.kubernetes.io/instance=kube-ops-view" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:8080
#kube-ops-view 서비스의 타입을 "loadBalancer"로 변경하는 모습, patch는 수정할 때 쓰는 명령어
#`-p` 옵션은 json 형태로 수정할 때
$kubectl patch svc -n kube-system kube-ops-view -p '{"spec":{"type":"LoadBalancer"}}'
service/kube-ops-view patched
#서비스에 대한 외부 도메인을 주석으로 달아줌(annotate 주석)
$kubectl annotate service kube-ops-view -n kube-system "external-dns.alpha.kubernetes.io/hostname=kubeopsview.$MyDomain"
service/kube-ops-view annotated
$echo -e "Kube Ops View URL = http://kubeopsview.$MyDomain:8080/#scale=1.5"
Kube Ops View URL = http://kubeopsview.kaneawsdns.com:8080/#scale=1.5
아래는 kubeops 실제 화면입니다. 큰 클러스터안에 노드별로 구분되어있는 것을 확인할 수 있습니다.
위의 DEFAULT
로 나와있는 부분은 출력형식을 지정하는 것입니다.
파드는 네임스페이스에 따라 구분됩니다.
이제 이번주차의 핵심인 스터리지에 대해서 실습을 진행합니다. 파드 내부의 데이터는 파드와 생명주기가 동일하여 파드가 삭제되면 데이터도 사라집니다. 만약, DB 애플리케이션과 같은 경우 데이터는 보존이 필요합니다. 이럴 경우 persistent volume 을 연결하여 사용합니다.
PV와 PVC에 대한 내용은 AWS Blog 문서를 참고했습니다.
Persistent Volume(PV)은 실제 스토리지 볼륨을 나타냅니다. 쿠버네티스는 PV 위에 추가 추상화 계층인 PersistentVolumeClaim(PVC)을 가지고 있습니다. 구분하는 이유는 아래의 문서에서 확인할 수 있습니다.
PV와 PVC의 구분은 Kubernetes 환경에서 두 가지 유형의 사용자가 있다는 개념과 관련이 있습니다.
- Kubernetes 관리자: 이 사용자는 클러스터를 유지 관리하고 운영하며 영구 스토리지와 같은 계산 리소스를 추가합니다.
- Kubernetes 애플리케이션 개발자: 이 사용자는 애플리케이션을 개발하고 배포합니다.
CSI는 Container Storage Interface로 다양한 스토리지 솔류션에 대한 인터페이스입니다. CSI를 통해 다음과 같은 2가지 방법으로 스토리지를 연결할 수 있습니다.
정적 프로비저닝(Static provisioning)
먼저 관리자가 하나 이상의 PV를 생성하고 애플리케이션 개발자는 PVC를 생성합니다.
동적 프로비저닝(Dynamic provisioning)
동적 프로비저닝을 사용하면 PV객체를 생성할 필요가 없습니다. 대신에, PVC를 생성할 때 내부적으로 자동으로 생성됩니다. Kubernetes는 Storage Class라는 다른 객체를 사용하여 이를 수행합니다.
방식은 위의 그림과 같이 3가지가 있습니다. 첫번째 방식은 파드의 생명주기와 데이터의 생명주기가 같습니다. 데이터를 보존해야할 경우 2~3번째 방식을 이용해야 합니다. 2번째 방식은 아래의 local-path에서 설명할 예정입니다.
먼저, 가시다님의 이미지를 통해 파드의 생명주기와 데이터의 보존주기가 같은 것을 확인한 결과입니다.
$curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/date-busybox-pod.yaml
# 10초 마다 /home/pod-out.txt 에 로그를 남기는 파드 생성
$cat date-busybox-pod.yaml | yh
apiVersion: v1
kind: Pod
metadata:
name: busybox
spec:
terminationGracePeriodSeconds: 3
containers:
- name: busybox
image: busybox
command:
- "/bin/sh"
- "-c"
- "while true; do date >> /home/pod-out.txt; cd /home; sync; sync; sleep 10; done"
$kubectl apply -f date-busybox-pod.yaml
pod/busybox created
# 로그 확인
$kubectl get pod
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 11s
kubectl exec busybox -- tail -f /home/pod-out.txt
Sun May 7 15:26:19 UTC 2023
Sun May 7 15:26:29 UTC 2023
^C
$kubectl delete pod busybox
pod "busybox" deleted
$kubectl apply -f date-busybox-pod.yaml
pod/busybox created
# 삭제 후 실행하니, 기존의 로그는 사라진 것을 확인할 수 있음 -> 파드와 데이터의 생명주기가 같음을 확인
$kubectl exec busybox -- tail -f /home/pod-out.txt
Sun May 7 15:26:45 UTC 2023
Sun May 7 15:26:55 UTC 2023
Sun May 7 15:27:05 UTC 2023
Sun May 7 15:27:15 UTC 2023
$kubectl delete pod busybox
pod "busybox" deleted
HostPath는 Kubernetes 노드의 호스트 파일 시스템에 볼륨을 프로비저닝하는 방법입니다. 이것은 가장 간단한 방법이지만 제한적입니다. hostPath 볼륨은 단일 노드에서만 사용할 수 있으며 노드가 중단되면 데이터가 손실됩니다.
Local Path는 노드의 로컬 파일 시스템에 볼륨을 프로비저닝하는 방법입니다. HostPath와 유사하지만 더 유연합니다. 프로비저닝 볼륨은 여러 노드에서 사용할 수 있으며 노드가 중단되어도 데이터가 손실되지 않습니다. local-path에 대한 자세한 내용은 GitHub에서 확인할 수 있습니다.
아래는 Local-Path 방식을 이용하는 PV,PVC에 대한 실습입니다.
local path 관련 백업은 한승호님이 Velero blog에 올려주셨다.
# strage class 다운로드
$curl -s -O https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
# 배포
$kubectl apply -f local-path-storage.yaml
namespace/local-path-storage created
serviceaccount/local-path-provisioner-service-account created
clusterrole.rbac.authorization.k8s.io/local-path-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/local-path-provisioner-bind created
deployment.apps/local-path-provisioner created
storageclass.storage.k8s.io/local-path created
configmap/local-path-config created
$kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-path rancher.io/local-path Delete WaitForFirstConsumer false 25s
Local Path를 통한 동적 프로비저닝에 대한 실습내용입니다.
$cat localpath1.yaml | yh
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: localpath-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: "local-path"
#PVC 생성
$kubectl apply -f localpath1.yaml
persistentvolumeclaim/localpath-claim created
$kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
localpath-claim Pending local-path 4s
# [data -u]로그를 남기는 파드 생성
$kubectl apply -f localpath2.yaml
pod/app created
# 자동으로 PV가 생성되는 모습
$kubectl get pod,pv,pvc
NAME READY STATUS RESTARTS AGE
pod/app 0/1 ContainerCreating 0 6s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-88293146-ce9b-4dd0-b473-1ceb489301f3 1Gi RWO Delete Bound default/localpath-claim local-path 2s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/localpath-claim Bound pvc-88293146-ce9b-4dd0-b473-1ceb489301f3 1Gi RWO local-path 48s
위의 내용을 통해 동적프로비저닝을 확인했습니다. 현재와 같은 방식은 노드의 볼륨을 사용하기에, PV는 파드가 존재하는 노드에 생성됩니다.
$kubectl describe pv # Node Affinity 확인 -> 자신의 워커노드에서만 생성하도록
Name: pvc-88293146-ce9b-4dd0-b473-1ceb489301f3
...
Node Affinity:
Required Terms:
Term 0: kubernetes.io/hostname in [ip-192-168-2-116.ap-northeast-2.compute.internal]
...
# 파드가 동작중인 노드 확인
$k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app 1/1 Running 0 42s 192.168.2.185 ip-192-168-2-116.ap-northeast-2.compute.internal <none> <none>
# 접속해서 파드가 남긴 로그 확인
ssh ec2-user@$N2 tree /opt/local-path-provisioner
/opt/local-path-provisioner
└── pvc-88293146-ce9b-4dd0-b473-1ceb489301f3_default_localpath-claim
└── out.txt
ssh ec2-user@$N2 tail -f /opt/local-path-provisioner/pvc-88293146-ce9b-4dd0-b473-1ceb489301f3_default_localpath-claim/out.txt
Sun May 7 15:30:47 UTC 2023
Sun May 7 15:30:52 UTC 2023
Sun May 7 15:30:57 UTC 2023
Sun May 7 15:31:02 UTC 2023
Sun May 7 15:31:07 UTC 2023
Sun May 7 15:31:12 UTC 2023
# 파드 삭제
$kubectl delete pod app
pod "app" deleted
# 파드가 삭제되어도 데이터는 유지됨
$ssh ec2-user@$N2 tree /opt/local-path-provisioner
/opt/local-path-provisioner
└── pvc-88293146-ce9b-4dd0-b473-1ceb489301f3_default_localpath-claim
└── out.txt
1 directory, 1 file
# 파드를 재생성하여 데이터 보존을 한번 더 확인
$kubectl apply -f localpath2.yaml
pod/app created
$kubectl exec -it app -- head /data/out.txt
...
Sun May 7 15:30:02 UTC 2023
Sun May 7 15:30:07 UTC 2023
# 이전과는 다르게 로그가 그대로 유지됨
# 중간에 시간이 짤리는 것은 파드가 삭제 후 재시작하는 사이 시간
$kubectl exec -it app -- tail -f /data/out.txt
..
Sun May 7 15:31:27 UTC 2023
Sun May 7 15:31:32 UTC 2023
Sun May 7 15:31:37 UTC 2023
**Sun May 7 15:31:42 UTC 2023
Sun May 7 15:32:01 UTC 2023**
# 자원을 모두 제거
$kubectl delete pod app
pod "app" deleted
$kubectl delete pvc localpath-claim
persistentvolumeclaim "localpath-claim" deleted
# pv 삭제 후, 관련 볼륨이 사라진 것을 확인할 수 있음.
$ssh ec2-user@$N2 tree /opt/local-path-provisioner
/opt/local-path-provisioner
0 directories, 0 files
EBS-CSI를 사용하기 위한 절차입니다.
EBS는 동적 프로비저닝이 가능하기에, PVC 와 파드를 생성하면 자동적으로 PV가 할당됩니다.
ISRA 설정 : AWS관리형 정책 AmazonEBSCSIDriverPolicy 사용
add-on 추가: eksctl
이용
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
ebs-csi-driver 설정과정
# 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
2023-05-11 09:37:52 [ℹ] building iamserviceaccount stack "eksctl-myeks-addon-iamserviceaccount-kube-system-ebs-csi-controller-sa"
2023-05-11 09:37:53 [ℹ] deploying stack "eksctl-myeks-addon-iamserviceaccount-kube-system-ebs-csi-controller-sa"
$eksctl get iamserviceaccount --cluster myeks
NAMESPACE NAME ROLE ARN
kube-system aws-load-balancer-controller arn:aws:iam::871103481195:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-RK7A5DTQNNSW
kube-system ebs-csi-controller-sa arn:aws:iam::871103481195:role/AmazonEKS_EBS_CSI_DriverRole
# eksctl을 이용해서 ebs-csi-driver 를 설치
$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
2023-05-11 09:41:40 [ℹ] Kubernetes version "1.24" in use by cluster "myeks"
2023-05-11 09:41:40 [ℹ] using provided ServiceAccountRoleARN "arn:aws:iam::871103481195:role/AmazonEKS_EBS_CSI_DriverRole"
2023-05-11 09:41:40 [ℹ] creating addon
$eksctl get addon --cluster ${CLUSTER_NAME}
NAME VERSION STATUS ISSUES IAMROLE UPDATE AVAILABLE CONFIGURATION VALUES
aws-ebs-csi-driver v1.18.0-eksbuild.1 CREATING 0 arn:aws:iam::871103481195:role/AmazonEKS_EBS_CSI_DriverRole
$k get sa -n kube-system | grep ebs
ebs-csi-controller-sa 0 33s
ebs-csi-node-sa 0 33s
# 스토리지 클래스 배포
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
> allowAutoIOPSPerGBIncrease: 'true'
> encrypted: 'true'
> EOT
$kubectl apply -f gp3-sc.yaml
storageclass.storage.k8s.io/gp3 created
$kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp2 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 27m
gp3 ebs.csi.aws.com Delete WaitForFirstConsumer true 5s
$kubectl describe sc gp3 | grep Parameters
Parameters: allowAutoIOPSPerGBIncrease=true,encrypted=true,type=gp3
$kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp2 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 28m
gp3 ebs.csi.aws.com Delete WaitForFirstConsumer true
PV와 PVC, 파드를 생성하여 동적 프로비저닝을 확인하는 과정입니다.
$cat <<EOT > awsebs-pvc.yaml
> apiVersion: v1
> kind: PersistentVolumeClaim
> metadata:
> name: ebs-claim
> spec:
> accessModes:
> - ReadWriteOnce #### EBS는 여러 노드와 동시에 연결이 가능하기에, Once로 세팅
> resources:
> requests:
> storage: 4Gi
> storageClassName: gp3
> EOT
$kubectl apply -f awsebs-pvc.yaml
persistentvolumeclaim/ebs-claim created
$kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/ebs-claim Pending gp3 2s
$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
pod/app created
$kubectl get pvc,pv,pod
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/ebs-claim Bound pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7 4Gi RWO gp3 34s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7 4Gi RWO Delete Bound default/ebs-claim gp3 12s
NAME READY STATUS RESTARTS AGE
pod/app 0/1 ContainerCreating 0 16s
# 추가된 EBS Volume(PV) 확인
$kubectl get VolumeAttachment
NAME ATTACHER PV NODE ATTACHED AGE
csi-58bd6537e51d9961539e7d5eda35c6d08ab98b890c83e527325b84f7d562eba3 ebs.csi.aws.com pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7 ip-192-168-2-93.ap-northeast-2.compute.internal true 14s
# 추가된 EBS Volume(PV) 확인
$aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq
{
"Volumes": [
{
"Attachments": [
{
"AttachTime": "2023-05-11T00:48:04+00:00",
"Device": "/dev/xvdaa",
"InstanceId": "i-0039e023911746fbf",
"State": "attached",
"VolumeId": "vol-02735906e67899e1b",
"DeleteOnTermination": false
}
],
"AvailabilityZone": "ap-northeast-2b",
"CreateTime": "2023-05-11T00:48:00.023000+00:00",
"Encrypted": true,
"KmsKeyId": "arn:aws:kms:ap-northeast-2:871103481195:key/e92fb931-6368-48c5-9896-43acdaa5f663",
"Size": 4,
"SnapshotId": "",
"State": "in-use",
"VolumeId": "vol-02735906e67899e1b",
"Iops": 3000,
"Tags": [
{
"Key": "kubernetes.io/created-for/pvc/namespace",
"Value": "default"
},
{
"Key": "kubernetes.io/created-for/pvc/name",
"Value": "ebs-claim"
},
{
"Key": "Name",
"Value": "myeks-dynamic-pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7"
},
{
"Key": "KubernetesCluster",
"Value": "myeks"
},
{
"Key": "CSIVolumeName",
"Value": "pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7"
},
{
"Key": "kubernetes.io/cluster/myeks",
"Value": "owned"
},
{
"Key": "kubernetes.io/created-for/pv/name",
"Value": "pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7"
},
{
"Key": "ebs.csi.aws.com/cluster",
"Value": "true"
}
],
"VolumeType": "gp3",
"MultiAttachEnabled": false,
"Throughput": 125
}
]
}
PersistentVolumeClaim을 생성할 때, AWS EBS는 다중연결이 가능하기에 access모드를 ReadWriteOnce로 설정해야 합니다. EBS의 다중 연결은 GlusterFS와 같은 공유 볼륨을 사용하는 경우와 유사합니다.
EBS의 다중 연결을 사용하면 특정 볼륨을 여러 대의 EC2 인스턴스에 연결할 수 있습니다. 각 EBS 볼륨은 Multi-Attach 설정시 해당 볼륨이 위치한 가용영역에서 최대 16개의 EC2에 연결할 수 있게 됩니다.
또한, EBS는 같은 AZ에 있어야 접근이 가능하므로 nodeaffinity를 통해 같은 AZ로 PV를 생성합니다.
아래는 EBS 볼륨을 확장하는 실습입니다.
$kubectl exec app -- tail -f /data/out.txt
Thu May 11 00:48:40 UTC 2023
Thu May 11 00:48:45 UTC 2023
Thu May 11 00:48:50 UTC 2023
Thu May 11 00:48:55 UTC 2023
Thu May 11 00:49:00 UTC 2023
Thu May 11 00:49:05 UTC 2023
Thu May 11 00:49:10 UTC 2023
Thu May 11 00:49:15 UTC 2023
Thu May 11 00:49:20 UTC 2023
Thu May 11 00:49:25 UTC 2023
Thu May 11 00:49:30 UTC 2023
$kubectl df-pv
PV NAME PVC NAME NAMESPACE NODE NAME POD NAME VOLUME MOUNT NAME SIZE USED AVAILABLE %USED IUSED IFREE %IUSED
pvc-7fb5199c-d3d9-4648-a0d0-5f9b9bc006d7 ebs-claim default ip-192-168-2-93.ap-northeast-2.compute.internal app persistent-storage 3Gi 28Ki 3Gi 0.00 12 262132 0.00
$kubectl exec -it app -- sh -c 'df -hT --type=overlay'
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 30G 3.6G 27G 12% /
# ebs volume 확장
$kubectl patch pvc ebs-claim -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
persistentvolumeclaim/ebs-claim patched
# 자동으로 확장되는 모습
$kubectl exec -it app -- sh -c 'df -hT --type=ext4'
Filesystem Type Size Used Avail Use% Mounted on
/dev/nvme1n1 ext4 9.8G 28K 9.7G 1% /data
$kubectl delete pod app & kubectl delete pvc ebs-claim
[1] 7288
pod "app" deleted
persistentvolumeclaim "ebs-claim" deleted
[1]+ Done kubectl delete pod app
아래는 위와 동일하게, PVC, PV를 생성해서 파드와 연결합니다. 파드는 data -u
로그를 남기며 강제로 파드와 PVC를 삭제한 후, snapshots을 통해 복구하는 실습을 진행합니다.
snapshot 생성
$kubectl apply -f ebs-volume-snapshot.yaml
volumesnapshot.snapshot.storage.k8s.io/ebs-volume-snapshot created
$kubectl get volumesnapshot
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE
ebs-volume-snapshot false ebs-claim 4Gi csi-aws-vsc snapcontent-ff3a9b11-d8a5-4806-80eb-9c062c4062ad 3s 3s
#아래에 나와있는 snapshot id로 확인하면, 모두 잘 설정되어있다.
$kubectl get volumesnapshot ebs-volume-snapshot -o jsonpath={.status.boundVolumeSnapshotContentName} ; echo
snapcontent-ff3a9b11-d8a5-4806-80eb-9c062c4062ad
$kubectl describe volumesnapshot.snapshot.storage.k8s.io ebs-volume-snapshot
Name: ebs-volume-snapshot
Namespace: default
...
Metadata:
...
Time: 2023-05-13T05:58:36Z
Resource Version: 11187
UID: ff3a9b11-d8a5-4806-80eb-9c062c4062ad
Spec:
Source:
Persistent Volume Claim Name: ebs-claim
Volume Snapshot Class Name: csi-aws-vsc
Status:
Bound Volume Snapshot Content Name: snapcontent-ff3a9b11-d8a5-4806-80eb-9c062c4062ad
Creation Time: 2023-05-13T05:58:35Z
Ready To Use: false
Restore Size: 4Gi
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreatingSnapshot 19s snapshot-controller Waiting for a snapshot default/ebs-volume-snapshot to be created by the CSI driver.
Normal SnapshotCreated 18s snapshot-controller Snapshot default/ebs-volume-snapshot was successfully created by the CSI driver.
###
# 블로그에서는 중복된 조회 제거
$kubectl get volumesnapshotcontents
NAME READYTOUSE RESTORESIZE DELETIONPOLICY DRIVER VOLUMESNAPSHOTCLASS VOLUMESNAPSHOT VOLUMESNAPSHOTNAMESPACE AGE
snapcontent-ff3a9b11-d8a5-4806-80eb-9c062c4062ad false 4294967296 Delete ebs.csi.aws.com csi-aws-vsc ebs-volume-snapshot default 38s
# 파드와 pvc를 제거하여, pv가 제거된 모습
$kubectl delete pod app && kubectl delete pvc ebs-claim
pod "app" deleted
persistentvolumeclaim "ebs-claim" deleted
$kubectl get pvc,pv
No resources found
$k get volumesnapshot
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE
ebs-volume-snapshot true ebs-claim 4Gi csi-aws-vsc snapcontent-ff3a9b11-d8a5-4806-80eb-9c062c4062ad 7m13s 7m13s
$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
$kubectl apply -f ebs-snapshot-restored-claim.yaml
persistentvolumeclaim/ebs-snapshot-restored-claim created
$kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/ebs-snapshot-restored-claim Pending gp3 3s
## 블로그에서는 curl 또한 제거
$curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/ebs-snapshot-restored-pod.yaml
$cat ebs-snapshot-restored-pod.yaml | yh
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
$kubectl apply -f ebs-snapshot-restored-pod.yaml
pod/app created
$k get po
NAME READY STATUS RESTARTS AGE
app 1/1 Running 0 13s
#로그가 이어지는 것을 확인할 수 있다.
$k exec app -- cat /data/out.txt
...
Sat May 13 05:58:23 UTC 2023
Sat May 13 05:58:28 UTC 2023
Sat May 13 06:07:12 UTC 2023
Sat May 13 06:07:17 UTC 2023
$kubectl delete pod app && kubectl delete pvc ebs-snapshot-restored-claim && kubectl delete volumesnapshots ebs-volume-snapshot
pod "app" deleted
persistentvolumeclaim "ebs-snapshot-restored-claim" deleted
volumesnapshot.snapshot.storage.k8s.io "ebs-volume-snapshot" deleted
아래는 스냅샷을 AWS 콘솔을 통해 확인한 모습이다.
먼저 EFS(Amazon Elastic File System)는 그림과 같이 여러 가용영역과 호환가능한 파일시스템입니다.
아래는 EFS를 통해 PV,PVC를 생성하는 실습내용입니다.
먼저 작업용 EC2에도 efs mount를 진행합니다.
$mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport fs-0b2bc433bc72b5727.efs.ap-northeast-2.amazonaws.com:/ /mnt/myefs
$df -hT --type nfs4
Filesystem Type Size Used Avail Use% Mounted on
fs-0b2bc433bc72b5727.efs.ap-northeast-2.amazonaws.com:/ nfs4 8.0E 0 8.0E 0% /mnt/myefs
EFS-CSI 설치과정
# 정보 확인
$aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output textfs-0f70f92a10cc5af1a
# json 다운로드
$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
{
"Policy": {
"PolicyName": "AmazonEKS_EFS_CSI_Driver_Policy",
"PolicyId": "ANPA4VUOQIVV6AGY3ABHQ",
"Arn": "arn:aws:iam::871103481195:policy/AmazonEKS_EFS_CSI_Driver_Policy",
"Path": "/",
"DefaultVersionId": "v1",
"AttachmentCount": 0,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2023-05-13T06:21:41+00:00",
"UpdateDate": "2023-05-13T06:21:41+00:00"
}
}
# efs-csi 생성
$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
2023-05-13 15:22:26 [ℹ] created serviceaccount "kube-system/efs-csi-controller-sa"
## 불필요
$kubectl get sa -n kube-system efs-csi-controller-sa -o yaml | head -5
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::871103481195:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-183ANMNPO7E68
$eksctl get iamserviceaccount --cluster myeks
NAMESPACE NAME ROLE ARN
kube-system aws-load-balancer-controller arn:aws:iam::871103481195:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-1OWZIVWLLX9JM
kube-system ebs-csi-controller-sa arn:aws:iam::871103481195:role/AmazonEKS_EBS_CSI_DriverRole
kube-system efs-csi-controller-sa arn:aws:iam::871103481195:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-183ANMNPO7E68
#efs 구성요소를 helm을 통해 배포
$helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/
"aws-efs-csi-driver" has been added to your repositories
$helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "aws-efs-csi-driver" chart repository
Update Complete. ⎈Happy Helming!⎈
$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
Release "aws-efs-csi-driver" does not exist. Installing it now.
NAME: aws-efs-csi-driver
LAST DEPLOYED: Sat May 13 16:18:05 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
To verify that aws-efs-csi-driver has started, run:
$helm list -n kube-system
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
aws-efs-csi-driver kube-system 1 2023-05-13 16:18:05.885009102 +0900 KST deployed aws-efs-csi-driver-2.4.3 1.5.5
$kubectl get pod -n kube-system -l "app.kubernetes.io/name=aws-efs-csi-driver,app.kubernetes.io/instance=aws-efs-csi-driver"
NAME READY STATUS RESTARTS AGE
efs-csi-controller-6f64dcc5dc-6hbkc 0/3 ContainerCreating 0 9s
efs-csi-controller-6f64dcc5dc-wf4ks 0/3 ContainerCreating 0 9s
efs-csi-node-qs7sr 0/3 ContainerCreating 0 9s
efs-csi-node-xtvvm 0/3 ContainerCreating 0 9s
efs-csi-node-zvzcs 0/3 ContainerCreating 0 9s
이제 K8S에서 제공해준 샘플 코드를 다운받아, 실습을 진행합니다.
$git clone https://github.com/kubernetes-sigs/aws-efs- qq-driver.git /root/efs-csiCloning into '/root/efs-csi'...
remote: Enumerating objects: 16052, done.
remote: Counting objects: 100% (269/269), done.
remote: Compressing objects: 100% (185/185), done.
remote: Total 16052 (delta 65), reused 236 (delta 57), pack-reused 15783
Receiving objects: 100% (16052/16052), 16.90 MiB | 20.51 MiB/s, done.
Resolving deltas: 100% (7777/7777), done.
$cd /root/efs-csi/examples/kubernetes/multiple_pods/specs && tree
.
├── claim.yaml
├── pod1.yaml
├── pod2.yaml
├── pv.yaml
└── storageclass.yaml
0 directories, 5 files
$cat storageclass.yaml | yh
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
$kubectl apply -f storageclass.yaml
storageclass.storage.k8s.io/efs-sc created
$k get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
efs-sc efs.csi.aws.com Delete Immediate false 10s
gp2 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 139m
gp3 ebs.csi.aws.com Delete WaitForFirstConsumer true 109m
# 현재 EFS ID를 지정하는 모습
$EfsFsId=$(aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text)
$sed -i "s/fs-4af69aab/$EfsFsId/g" pv.yaml
$echo $EfsFsId
fs-0f70f92a10cc5af1a
$cat pv.yaml | yh
apiVersion: v1
kind: PersistentVolume
metadata:
name: efs-pv
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: efs-sc
csi:
driver: efs.csi.aws.com
volumeHandle: fs-0f70f92a10cc5af1a
# 정적 프로비저닝이라 pv를 먼저 생성하는 모습
$kubectl apply -f pv.yaml
persistentvolume/efs-pv created
$cat claim.yaml | yh
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: efs-claim
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 5Gi
$kubectl apply -f claim.yaml
persistentvolumeclaim/efs-claim created
$k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
efs-pv 5Gi RWX Retain Bound default/efs-claim efs-sc 57s
# 이전과 유사한 data -u 로그를 찍는 파드를 2개 생성
$kubectl apply -f pod1.yaml,pod2.yaml
pod/app1 created
pod/app2 created
$k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
efs-pv 5Gi RWX Retain Terminating default/efs-claim efs-sc 3m32s
$cat pod1.yaml pod2.yaml | yh
apiVersion: v1
kind: Pod
metadata:
name: app1
...
args: ["-c", "while true; do echo $(date -u) >> /data/out1.txt; sleep 5; done"]
volumeMounts:
- name: persistent-storage
mountPath: /data
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: efs-claim
apiVersion: v1
kind: Pod
metadata:
name: app2
..
args: ["-c", "while true; do echo $(date -u) >> /data/out2.txt; sleep 5; done"]
volumeMounts:
- name: persistent-storage
mountPath: /data
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: efs-claim
$k exec -it app1 -- sh -c "df -hT -t nfs4"
Filesystem Type Size Used Available Use% Mounted on
127.0.0.1:/ nfs4 8.0E 0 8.0E 0% /data
$k exec -it app1 -- cat /data/out1.txt
...
Sat May 13 07:25:50 UTC 2023
Sat May 13 07:25:55 UTC 2023
# 작업용 EC2에도 공유되는 모습.
$tree /mnt/myefs/
/mnt/myefs/
├── out1.txt
└── out2.txt
0 directories, 2 files
$kubectl delete pvc efs-claim && kubectl delete pv efs-pv && kubectl delete sc efs-sc
persistentvolumeclaim "efs-claim" deleted
persistentvolume "efs-pv" deleted
storageclass.storage.k8s.io "efs-sc" deleted
아래는 EFS의 네트워크 모습입니다. 현재 노드가 있는 3개의 가용영역이 모두 있는 것을 확인할 수 있습니다.
위에서는 정적 프로비저닝으로 테스트를 진행했지만, EFS에는 동적 프로비저닝 기능이 1.2
버전부터 지원하여 동적 프로비저닝도 진행해봤다. 위의 내용에서 동적프로비저닝을 테스트하면 다음과 같이 자동으로 PV가 할당되지 않아 PVC와 파드가 생성되지 못한다.
# 모니터링
Every 2.0s: kubectl get sc efs-sc; echo; kubectl get pv,pvc,pod Sat May 13 16:30:46 2023
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
efs-sc efs.csi.aws.com Delete Immediate false 10m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/efs-claim Pending efs-sc 42s
NAME READY STATUS RESTARTS AGE
pod/app1 0/1 Pending 0 33s
pod/app2 0/1 Pending 0 33s
파드의 로그
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 15s (x4 over 100s) default-scheduler 0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.
Normal Scheduled 7s default-scheduler Successfully assigned default/app1 to ip-192-168-2-52.ap-northeast-2.compute.internal
PVC 로그
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 96s (x7 over 2m39s) efs.csi.aws.com_ip-192-168-3-190.ap-northeast-2.compute.internal_d0fa0b24-c916-44ba-befc-922b6eb49470 External provisioner is provisioning volume for claim "default/efs-claim"
Warning ProvisioningFailed 96s (x7 over 2m39s) efs.csi.aws.com_ip-192-168-3-190.ap-northeast-2.compute.internal_d0fa0b24-c916-44ba-befc-922b6eb49470 failed to provision volume with StorageClass "efs-sc": rpc error: code = InvalidArgument desc = Missing provisioningMode parameter
Normal Provisioning 96s (x7 over 2m39s) efs.csi.aws.com_ip-192-168-1-203.ap-northeast-2.compute.internal_74db5f2e-b1e1-4f54-b9b2-cede890dddf7 External provisioner is provisioning volume for claim "default/efs-claim"
Warning ProvisioningFailed 96s (x7 over 2m39s) efs.csi.aws.com_ip-192-168-1-203.ap-northeast-2.compute.internal_74db5f2e-b1e1-4f54-b9b2-cede890dddf7 failed to provision volume with StorageClass "efs-sc": rpc error: code = InvalidArgument desc = Missing provisioningMode parameter
Normal ExternalProvisioning 80s (x8 over 2m39s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "efs.csi.aws.com" or manually created by system administrator
EFS에 대한 동적프로비저닝에 대한 설명은 AWS Blog과 GitHub에서 자세하게 확인할 수 있습니다.
다른 과정은 앞에서와 똑같고, 스토리지 클래스와 파드만 달라진다.
cat storageclass.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
fileSystemId: fs-0b2bc433bc72b5727 # 자신의 EFS ID
directoryPerms: "700"
cat pod.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: efs-claim
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: efs-app
spec:
containers:
- name: app
image: centos
command: ["/bin/sh"]
args: ["-c", "while true; do echo $(date -u) >> /data/out; sleep 5; done"]
volumeMounts:
- name: persistent-storage
mountPath: /data
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: efs-claim
이유를 모르겠으나, 동적프로비저닝은 오류가 발생했다. 문서 그대로 진행하고, 오류를 찾아봤으나 아직 해결하지 못했다.
Every 2.0s: kubectl get sc efs-sc; echo; kubectl get pv,pvc,pod Sat May 13 22:45:27 2023
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
efs-sc efs.csi.aws.com Delete Immediate false 7m39s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/efs-claim Pending efs-sc 7m18s
NAME READY STATUS RESTARTS AGE
pod/efs-app 0/1 Pending 0 7m18s
PVC에서 발생한 로그
Warning ProvisioningFailed 26s efs.csi.aws.com_ip-192-168-3-97.ap-northeast-2.compute.internal_6f23dce4-74d1-4453-b25c-013fcb47be73 failed to provision volume with StorageClass "efs-sc": rpc error: code = Internal desc = Failed to fetch File System info: Describe File System failed: WebIdentityErr: failed to retrieve credentials
caused by: AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
status code: 403, request id: 92132222-c11b-4a7c-b546-ddf80b933c1c
Normal ExternalProvisioning 14s (x5 over 57s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "efs.csi.aws.com" or manually created by system administrator
추가적으로 실습을 진행하다가, 에러가 났던 부분입니다.
아래와 같이 PV 삭제할 때, terminating 단계에서 멈추며 진행이 안된 적이 있다. 관련 자료를 찾아보니 파이널라이저에 의해 삭제가 안되는 것을 알 수 있었다.
k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
efs-pv 5Gi RWX Retain Available efs-sc 3m49s
pvc-5f762d6c-aff6-4a3a-8ff4-e947563c792a 5Gi RWX Delete Terminating default/efs-claim efs-sc 27m