[CloudNet@] 쿠버네티스 실무 실습 스터디 2주차 (2) - 스토리지

s3ich4n·2023년 3월 18일
0
post-thumbnail

이 내용은 CloudNet@ 에서 진행하는 쿠버네티스 실무 실습 스터디에 대한 연재글입니다.

스터디에서 사용하는 교재는 24단계 실습으로 정복하는 쿠버네티스 입니다.

본 2주차에는 교재의 제 2부 전체 내용 중 상반기 부분을 살펴보고 있습니다. 전체 컨텍스트를 이해하시려면 교재를 참고하시기를 추천드립니다.

Prerequisites

쿠버네티스를 클라우드 환경에서 사용하고자 하는 것 자체가 이미 하기 사항들에 대한 기본적인 이해와 준비사항을 요합니다.

이번 연재글에서는 개념에 대한 상세한 추가설명은 가급적 없이 작성하려 합니다. 다만 제가 공부하며 기본적으로 알아야겠다 싶은 연재글에 대해 대신 소개드립니다.

이번 장의 핵심 개념 스크린샷 소개

쿠버네티스 스토리지를 이해하기 위해 볼륨 스토리지, 파일 스토리지, 오브젝트 스토리지에 대한 그림을 소개합니다. 이해에 도움이 되시길 바랍니다.

들어가며

사전 준비사항 (1)

  1. AWS Free Tier 계정(비용문제로 인해 필요합니다!)
  2. IAM User 생성 후 권한 부여
    1. 학습을 위해 자신의 작업환경 IP에서만 접근할 수 있도록 하고, 관리자 권한을 주는 식으로 해결해도 좋습니다.
  3. Route 53 퍼블릭 호스팅 영역
    1. 혹은 도메인 구매사이트에서 도메인 구매 후, Route 53 설정 지정하기

사전 준비사항 (2)

주의! 비용이 많이 발생할 수 있으니, 빠르게 실습 후 종료하시기를 권장드립니다.

  1. 마스터노드 t3.medium
  2. 워커노드 c5d.large
  3. kOps 커맨드를 수행할 인스턴스 t3.small

아래 커맨드를 통해 배포하여 주십시오.

사전 준비사항 (3)

주의! 비용이 많이 발생할 수 있으니, 빠르게 실습 후 종료하시기를 권장드립니다.

워커노드 (c5d.large) 의 EC2 인스턴스 스토어(임시 블록 스토리지) 설정작업이 필요합니다.

임시 블록 스토리지 내의 데이터는 관련 인스턴스의 수명기간 동안만 지속됩니다. 인스턴스 재부팅의 경우에는 데이터가 유지되지만, 아래의 경우 데이터가 사라집니다.

  • 기본 디스크 드라이브 오류
  • 인스턴스가 중지됨
  • 인스턴스가 최대 절전 모드로 전환됨
  • 인스턴스가 종료됨

이런 연유로 중요한 장기 데이터는 S3, Amazon EBS, Amazon EFS 와 같은 데이터 스토리지를 이용하는 것이 필요합니다. 대표적인 데이터 스토리지인 EBS 볼륨과 인스턴스 볼륨의 차이를 살펴봅시다[^1]:

  • EBS 볼륨은 인스턴스 중지 및 종료 시에도 데이터를 보존합니다.
  • EBS 스냅샷으로 EBS 볼륨을 백업할 수 있습니다.
  • 한 인스턴스에서 EBS 볼륨을 제거하고 다른 인스턴스에 다시 연결할 수 있습니다.
  • EBS 볼륨은 전체 볼륨 암호화를 지원합니다.

추가 참고사항: 인스턴스 볼륨 사용법

인스턴스 볼륨을 마운트하고 사용하는 방안에 대해 알아보겠습니다.

아래 예제에서는 인스턴스 스토어 볼륨을 설정하고, 이를 확인하는 방법을 소개합니다.

# default NS 진입
kubectl ns default

# 인스턴스 스토어 볼륨이 있는 c5 모든 타입의 스토리지 크기
aws ec2 describe-instance-types \
 --filters "Name=instance-type,Values=c5*" "Name=instance-storage-supported,Values=true" \
 --query "InstanceTypes[].[InstanceType, InstanceStorageInfo.TotalSizeInGB]" \
 --output table
--------------------------
|  DescribeInstanceTypes |
+---------------+--------+
|  c5d.large    |  50    |
|  c5d.12xlarge |  1800  |
...

# 워커 노드 Public IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value}" --filters Name=instance-state-name,Values=running --output table

# 워커 노드 Public IP 변수 지정
W1PIP=<워커 노드 1 Public IP>
W2PIP=<워커 노드 2 Public IP>
W1PIP=3.38.212.122
W2PIP=43.201.99.109
echo "export W1PIP=$W1PIP" >> /etc/profile
echo "export W2PIP=$W2PIP" >> /etc/profile

# 워커 노드 스토리지 확인 : NVMe SSD 인스턴스 스토어 볼륨 확인
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo apt install -y nvme-cli
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo apt install -y nvme-cli
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo nvme list
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo nvme list

ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP lsblk -e 7 -d
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP lsblk -e 7
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP df -hT -t ext4
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP df -hT -t ext4
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP lspci | grep Non-Volatile
00:04.0 Non-Volatile memory controller: Amazon.com, Inc. Device 8061
00:1f.0 Non-Volatile memory controller: Amazon.com, Inc. NVMe SSD Controller

# 파일시스템 생성 및 /data 마운트
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo mkfs -t xfs /dev/nvme1n1
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo mkfs -t xfs /dev/nvme1n1
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo mkdir /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo mkdir /data
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP sudo mount /dev/nvme1n1 /data
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP sudo mount /dev/nvme1n1 /data
ssh -i ~/.ssh/id_rsa ubuntu@$W1PIP df -hT -t ext4 -t xfs
ssh -i ~/.ssh/id_rsa ubuntu@$W2PIP df -hT -t ext4 -t xfs

참고 2 인스턴스 스토어는 스토리지 정보에 출력되지 않습니다.

쿠버네티스 스토리지 관리

컨테이너 환경에서는 별도의 설정을 하지 않으면, 데이터는 호스트 노드의 임시 디스크(Ephemeral disk)에 보관됩니다. 이는 컨테이너 삭제 시 사라집니다. 이를 Stateless 애플리케이션이라고도 합니다. 말 그대로 관리하고있는 상태(또는 데이터)가 없기 때문입니다. 이를 해결하려면 영구 볼륨 이라는 리소스로 관리해야 합니다. 관리를 진행하는 애플리케이션은 Stateful 애플리케이션입니다.

용어정리 - 볼륨 (1)

Ephemeral disk 및 Node의 특정 경로를 매핑하는 기능도 있습니다.
이는 각각 emptyDirhostPath 라고 일컫습니다.

이에 대한 간략한 예시는 해당 링크 를 참고하여 주십시오.

당연하겠지만, Ephemeral disk나 Node의 경로를 매핑한다면 특정 노드의 상태에 영속적인 데이터의 상태가 좌우됩니다. 그리고, 쿠버네티스의 모든 리소스는 cattle과 같아, 별도의 제약을 두지 않으면 항상 stateful하다곤 할 수 없습니다. 이를 통해 스토리지 HA 구성에 제약이 생깁니다.

용어정리 - 볼륨 (2)

스토리지의 보다 기민하고 상세한 관리를 위해, 용어를 정리하고 진행하도록 합시다. 쿠버네티스에서는 볼륨을 구성하는 주요 리소스로 아래 세 가지가 있습니다.

  1. PV (PersistentVolume, 영구 볼륨)
    1. 데이터가 영속적으로 저장되는 스토리지의 일부입니다.
    2. 후술할 스토리지 클래스를 통해 동적으로 영구 볼륨을 할당합니다.
  2. PVC (PersistentVolumeClaim, 영구 볼륨 요청자)
    1. PV의 스토리지 용량과 액세스 모드 등의 설정을 별도로 분리한 리소스입니다.
    2. 이는 마치 네트워크 장에서의 설정 관련 인그레스 와 실제 트래픽 처리용 인그레스 컨트롤러 분리 개념과 유사합니다.
    3. 즉, 아래와 같은 역할분배가 가능합니다.
      1. 관리자는 PV, 스토리지 클래스 생성합니다.
      2. 사용자는 PVC로 볼륨할당을 요청하여, 해당 스토리지 클래스에서 동적으로 PV를 할당받습니다.
  3. 스토리지 클래스 (StorageCla2s)
    1. 스토리지 솔루션(온프렘) 또는 클라우드 서비스 제공업체에서 제공하는 여러 스토리지 중 동일한 속성(IOPS, 레이턴시, 백업정책 등)을 가지는 스토리지의 집합 리소스입니다.
    2. 관리자는 사전에 클러스터에 필요한 스토리지 유형을 정하고 이를 스토리지 클래스로 생성합니다.
    3. 사용자는 원하는 스토리지 클래스를 지정해 PVC로 요청합니다.
    4. 스토리지 클래스에서 해당 볼륨을 동적으로 할당해줍니다.

상기 내용들은 아래와 같은 그림[^3]들으로 이루어집니다.

하기의 Status, Policy 및 외부 네트워크의 액세스 모드 등은
데이터 스토리지는 AWS를 사용한다면 블록 스토리지/파일 스토리지/객체 스토리지 를 사용할 수 있습니다.

용어정리 - 볼륨 (3)

  • 파드가 생성될 때 자동으로 볼륨을 마운트하여 파드에 연결하는 기능을 동적 프로비저닝(Dynamic Provisioning)이라고 합니다.
  • PV의 사용이 끝났을 때 해당 볼륨은 어떻게 초기화할 것인지 별도로 설정할 수 있습니다. 쿠버네티스에선 이를 Reclaim Policy 라고 부릅니다.
  • Reclaim Policy 에는 크게 Retain(보존), Delete(삭제, 즉 EBS 볼륨도 삭제됨), Recycle(deprecated) 방식이 있습니다.
    • Reclaim Policy에 대해서는 아래 그림으로 보다 상세히 살펴봅시다.

CSI(Container Storage Interface)에 대해

CSI는 CNI와 같이, 컨테이너의 스토리지를 관리하기 위한 일련의 인터페이스 입니다. 보다 상세히 말하자면, 쿠버네티스가 컨테이너화된 워크로드에 임의의 스토리지 시스템을 노출할 수 있게 해주는 개방형 표준 API입니다. 즉 CSI 를 사용함으로서 쿠버네티스 의 공통화된 CSI 인터페이스를 통해 다양한 프로바이더를 사용할 수 있게 됩니다.

아래 그림은 일반적인 CSI driver의 구조입니다. 일례로 AWS EBS CSI driver 역시 아래와 같은 구조를 가집니다.

  • 오른쪽 StatefulSet 또는 Deployment로 배포된 controller Pod이 AWS API를 사용하여 실제 EBS volume을 생성하는 역할을 합니다.
  • 왼쪽 DaemonSet으로 배포된 node Pod은 AWS API를 사용하여 Kubernetes node (EC2 instance)에 EBS volume을 attach 해줍니다.

AWS EBS Controller 알아보기

이번 절에서는 AWS의 EBS 컨트롤러에 대해 살펴보도록 하겠습니다. 기본적인 블록 스토리지를 쿠버네티스 클러스터에서 어떤 식으로 관리할 수 있을까요? 아래의 도식을 통해 살펴봅시다.

실습 01-1. 스토리지 클래스, PVC, 파드 확인을 통한 배포현황 살펴보기

kOps를 통해 배포한 클러스터의 스토리지 클래스, PVC, 파드 확인을 통한 배포현황을 살펴봅시다.

# kOps 설치 시 기본 배포됨
kubectl get pod -n kube-system -l app.kubernetes.io/instance=aws-ebs-csi-driver

# 스토리지 클래스 확인
kubectl get sc kops-csi-1-21 kops-ssd-1-17

kubectl describe sc kops-csi-1-21 | grep Parameters
Parameters:            encrypted=true,type=gp3
kubectl describe sc kops-ssd-1-17 | grep Parameters
Parameters:            encrypted=true,type=gp2

# 워커노드의 EBS 볼륨 확인 : tag(키/값) 필터링 - 링크
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --output table
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[*].State" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[*].State" --output text
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[].State" --output text
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[?State=='attached'].VolumeId[]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[?State=='attached'].VolumeId[]" --output text
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].Attachments[?State=='attached'].InstanceId[]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[*].{ID:VolumeId,Tag:Tags}" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].[VolumeId, VolumeType]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].[VolumeId, VolumeType, Attachments[].[InstanceId, State]]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].[VolumeId, VolumeType, Attachments[].[InstanceId, State][]][]" | jq
aws ec2 describe-volumes --filters Name=tag:k8s.io/role/node,Values=1 --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" | jq

# 워커노드에서 파드에 추가한 EBS 볼륨 확인
aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --output table
aws ec2 describe-volumes --filters Name=tag:ebs.csi.aws.com/cluster,Values=true --query "Volumes[*].{ID:VolumeId,Tag:Tags}" | jq
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}" | jq

# 워커노드에서 파드에 추가한 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 ~/pkos/3/awsebs-pvc.yaml | yh
kubectl apply -f ~/pkos/3/awsebs-pvc.yaml

# 파드 생성
cat ~/pkos/3/awsebs-pod.yaml | yh
kubectl apply -f ~/pkos/3/awsebs-pod.yaml

# PVC, 파드 확인
kubectl get pvc,pv,pod
kubectl df-pv

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

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

# 파드 내에서 볼륨 정보 확인
kubectl exec -it app -- sh -c 'df -hT --type=ext4'
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme1n1   ext4  3.9G   16M  3.8G   1% /data
/dev/root      ext4  124G  4.9G  120G   4% /etc/hosts

실습 01-2. 볼륨 증가(감소는 안됩니다!)

이어서, 볼륨을 증가하는 테스트를 진행해봅시다.

# 현재 pv 의 이름을 기준하여 4G > 10G 로 증가 : .spec.resources.requests.storage의 4Gi 를 10Gi로 변경
kubectl edit pvc ebs-claim
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=ext4'
kubectl df-pv
aws ec2 describe-volumes --volume-ids $(kubectl get pv -o jsonpath="{.items[0].spec.csi.volumeHandle}") | jq

실습 01 정리

아래 커맨드를 입력하여 실습 01 내용을 정리합시다.

kubectl delete pod app & kubectl delete pvc ebs-claim

AWS Volume SnapShots Controller 알아보기

영속적 데이터에 대해 스냅샷을 찍고 얼마든지 상태를 돌아갈 수 있다면 안전한 서비스를 운영함에 있어 큰 도움이 될 것입니다.

AWS에서는 VolumeSnapShot 컨트롤러를 사용하여 이를 수행할 수 있습니다.

실습 02-1. 스냅샷 컨트롤러 설치

아래 커맨드를 통해 스냅샷 컨트롤러를 설치해 봅시다.

# kOps 클러스터 편집
kops edit cluster
-----
spec:
  snapshotController:
    enabled: true
  certManager:  # 이미 설치됨
    enabled: true  # 이미 설치됨
-----

# 업데이트 적용
kops update cluster --yes && sleep 3 && kops rolling-update cluster

# 확인 >> 배포 시 3분 정도 소요됨
watch kubectl get pod -n kube-system
kubectl get crd | grep volumesnapshot
volumesnapshotclasses.snapshot.storage.k8s.io    2022-07-19T13:45:26Z
volumesnapshotcontents.snapshot.storage.k8s.io   2022-07-19T13:45:26Z
volumesnapshots.snapshot.storage.k8s.io          2022-07-19T13:45:26Z

# vsclass 생성
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/master/examples/kubernetes/snapshot/manifests/classes/snapshotclass.yaml
kubectl get volumesnapshotclass
NAME          DRIVER            DELETIONPOLICY   AGE
csi-aws-vsc   ebs.csi.aws.com   Delete           6s

실습 02-2. 테스트 PVC/파드 생성

그렇다면, PVC와 파드를 만들고 VolumeSnapShot을 만들어서 스냅샷 생성을 확인 후 장애를 내봅시다!!!!!

# PVC 생성
kubectl apply -f ~/pkos/3/awsebs-pvc.yaml

# 파드 생성
kubectl apply -f ~/pkos/3/awsebs-pod.yaml

# VolumeSnapshot 생성 : Create a VolumeSnapshot referencing the PersistentVolumeClaim name
cat ~/pkos/3/ebs-volume-snapshot.yaml | yh
kubectl apply -f ~/pkos/3/ebs-volume-snapshot.yaml

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

# VolumeSnapshot 확인
kubectl get volumesnapshot
NAME                  READYTOUSE   SOURCEPVC   SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS   SNAPSHOTCONTENT                                    CREATIONTIME   AGE
ebs-volume-snapshot   true         ebs-claim                           4Gi           csi-aws-vsc     snapcontent-5881b167-2375-4aa7-b0ad-c5d305cc0aaf   90s            91s

kubectl get volumesnapshot ebs-volume-snapshot -o jsonpath={.status.boundVolumeSnapshotContentName}
snapcontent-5881b167-2375-4aa7-b0ad-c5d305cc0aaf

kubectl describe volumesnapshot.snapshot.storage.k8s.io ebs-volume-snapshot

# 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

실습 02-3. 스냅샷을 통한 복원

하지만 필요한 서비스들을 구동한다면, 스냅샷을 통해 복구할 수 있습니다.

# 스냅샷에서 PVC 로 복원
cat ~/pkos/3/ebs-snapshot-restored-claim.yaml | yh
**kubectl apply -f ~/pkos/3/ebs-snapshot-restored-claim.yaml**

# 확인
kubectl get pvc,pv

# 파드 생성
cat ~/pkos/3/ebs-snapshot-restored-pod.yaml | yh
**kubectl apply -f ~/pkos/3/ebs-snapshot-restored-pod.yaml**

# 파일 내용 저장 확인 : 파드 삭제 전까지의 저장 기록이 남아 있다. 이후 파드 재생성 후 기록도 잘 저장되고 있다
**kubectl exec app -- cat /data/out.txt**
...
Sat Dec 24 15:12:24 UTC 2022
Sat Dec 24 15:12:24 UTC 2022
Sat Dec 24 15:24:23 UTC 2022
Sat Dec 24 15:24:23 UTC 2022
...

실습 02-4. 정리

아래 커맨드를 입력하여 실습 02 내용을 정리합시다.

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

AWS EFS Controller

그렇다면, 다수의 파드가 공유하는 파일 시스템은 어떻게 운영하면 좋을까요? 이럴 때 파일 스토리지를 사용합니다. 파일 스토리지의 대표적인 예로 NFS, SMB 등이 있겠습니다. 파일 스토리지를 쿠버네티스 클러스터에서 활용하기 위한 예시를 실행해봅시다.

실습 03-1. EFS 파일시스템 생성 및 EFS 컨트롤러 설치

EFS 확인 및 적절한 IAM 정책 생성 후 EFS 컨트롤러를 helm으로 설치해봅시다. (드라이버에 대한 설명

# EFS 정보 확인
aws efs describe-file-systems
while true; do aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text; date; sleep 1; done

# IAM 정책 생성
curl -s -o iam-policy-example.json 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

# EC2 instance profiles 에 IAM Policy 추가(attach)
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AmazonEKS_EFS_CSI_Driver_Policy --role-name masters.$KOPS_CLUSTER_NAME
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AmazonEKS_EFS_CSI_Driver_Policy --role-name nodes.$KOPS_CLUSTER_NAME

# EFS Controller 설치
helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/
helm repo update
helm install my-aws-efs-csi-driver aws-efs-csi-driver/aws-efs-csi-driver --version 2.4.0 --set replicaCount=1 --namespace kube-system

# 확인
helm list -n kube-system
kubectl get pod -n kube-system -l "app.kubernetes.io/name=aws-efs-csi-driver,app.kubernetes.io/instance=my-aws-efs-csi-driver"

실습 03-2. AWS EFS 파일시스템 생성

본격적으로 EFS 파일 시스템을 설치하고 마운트 타겟을 생성해봅시다. (참고링크)

# kops가 동작하는 vpc id 출력
aws ec2 describe-vpcs --query 'Vpcs[?Tags[?Key==`Name`]|[?Value==`<각자 자신의 클러스터 이름 직접 입력>`]].VpcId' --output text
aws ec2 describe-vpcs --query 'Vpcs[?Tags[?Key==`Name`]|[?Value==`gasida.link`]].VpcId' --output text
vpc-03f5bf92f0fa78a86

# kops가 동작하는 vpc id 출력 변수 입력
VPCID=$(aws ec2 describe-vpcs --query 'Vpcs[?Tags[?Key==`Name`]|[?Value==`gasida.link`]].VpcId' --output text)

# kops가 동작하는 vpc id의 CIDR 정보 변수 입력
CIDR=$(aws ec2 describe-vpcs --vpc-ids $VPCID --query "Vpcs[].CidrBlock" --output text)

# kops가 동작하는 vpc id의 CIDR 대역에서 EFS 통신(TCP 2049)을 허용하는 인바운드 보안 그룹 생성
SGID=$(aws ec2 create-security-group --group-name MyEfsSg --description "My EFS security group" --vpc-id $VPCID --output text)
aws ec2 authorize-security-group-ingress --group-id $SGID --protocol tcp --port 2049 --cidr $CIDR

# EFS 파일 시스템 생성
EfsFsId=$(aws efs create-file-system --performance-mode generalPurpose --query 'FileSystemId' --output text)
echo $EfsFsId
echo "export EfsFsId=$EfsFsId" >> /etc/profile

# kops가 동작하는 서브넷 정보 출력
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' --output text
ap-northeast-2c	172.30.64.0/19	subnet-06fab272fad989708
ap-northeast-2a	172.30.32.0/19	subnet-0aa58f0ab7856f391

# kops가 동작하는 서브넷ID를 변수에 지정
SUB1=<바로 위 서브넷 ID중 하나를 입력>
SUB2=<바로 위 서브넷 ID중 나머지 입력>
SUB1=subnet-0aa58f0ab7856f391
SUB2=subnet-06fab272fad989708

# efs mount target 생성
aws efs create-mount-target --file-system-id $EfsFsId --subnet-id $SUB1 --security-groups $SGID
aws efs create-mount-target --file-system-id $EfsFsId --subnet-id $SUB2 --security-groups $SGID

# EFS 확인
aws efs describe-file-systems --output text
aws efs describe-file-systems --output table
echo $EfsFsId

실습 03-3. EFS 파일시스템을 다수의 파드가 사용하게 설정

EFS 스토리지클래스와 PV생성 및 확인 후 PVC 생성을 확인하여 본격적인 EFS 파일시스템 공유를 실습해봅시다. (참고링크)

# 모니터링
watch 'kubectl get sc efs-sc; echo; kubectl get pv,pvc,pod'

# 실습 코드 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 | yh
kubectl apply -f storageclass.yaml
kubectl get sc efs-sc

# PV 생성 및 확인 : volumeHandle을 자신의 EFS 파일시스템ID로 변경
sed -i "s/fs-4af69aab/$EfsFsId/g" pv.yaml

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-05699d3c12ef609e2

kubectl apply -f pv.yaml
kubectl get pv

# PVC 생성 및 확인
cat claim.yaml | yh
kubectl apply -f claim.yaml
kubectl get pvc
NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
efs-claim   Bound    efs-pv   5Gi        RWX            efs-sc         2m14s

# 파드 생성 및 연동 : 파드 내에 /data 데이터는 EFS를 사용
cat pod1.yaml pod2.yaml | yh
kubectl apply -f pod1.yaml,pod2.yaml
kubectl df-pv

# 파드 정보 확인 : PV에 5Gi 와 파드 내에서 확인한 NFS4 볼륨 크리 8.0E의 차이는 무엇? 파드에 6Gi 이상 저장 가능한가?
kubectl get pods
kubectl exec -ti app1 -- sh -c "df -hT -t nfs4"
kubectl exec -ti app2 -- 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

# 공유 저장소 저장 동작 확인
kubectl exec -ti app1 -- tail -f /data/out1.txt
kubectl exec -ti app2 -- tail -f /data/out2.txt

실습 03-4. 실습 정리

실습 완료 후 쿠버네티스 리소스 및 EFS를 삭제합니다.

# 쿠버네티스 리소스 삭제
kubectl delete pod app1 app2
kubectl delete pvc efs-claim && kubectl delete pv efs-pv && kubectl delete sc efs-sc

# EFS 삭제
## efs mount target 삭제 : 아래 출력된 mount target id 값으로 삭제
aws efs describe-mount-targets --file-system-id $EfsFsId --query 'MountTargets[].MountTargetId' --output text
fsmt-0e9f23f8c90cf6b36	fsmt-077cc300899d131af

aws efs delete-mount-target --mount-target-id <value>
aws efs delete-mount-target --mount-target-id fsmt-0e9f23f8c90cf6b36
aws efs delete-mount-target --mount-target-id fsmt-077cc300899d131af

## EFS 파일 시스템 삭제 : 위 mlunt target 삭제(1~2분정도소요) 완료 후 삭제가 가능하다
aws efs delete-file-system --file-system-id $EfsFsId

추가 참고사항 - Dynamic Provisioning

앞서 마운트 시 살펴본 EFS Access point를 통해, Dynamic Provisioning 또한 가능합니다. (참고링크 GitHub)

스토리지 클래스의 YAML 파일을 살펴봅시다.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
mountOptions:
  - tls
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-92107410
  directoryPerms: "700"
  gidRangeStart: "1000"
  gidRangeEnd: "2000"
  basePath: "/dynamic_provisioning"
  • provisioningMode - The type of volume to be provisioned by efs. Currently, only access point based provisioning is supported efs-ap.
  • fileSystemId - The file system under which Access Point is created.
  • directoryPerms - Directory Permissions of the root directory created by Access Point.
  • gidRangeStart (Optional) - Starting range of Posix Group ID to be applied onto the root directory of the access point. Default value is 50000.
  • gidRangeEnd (Optional) - Ending range of Posix Group ID. Default value is 7000000.
  • basePath (Optional) - Path on the file system under which access point root directory is created. If path is not provided, access points root directory are created under the root of the file system.

프로비저닝 모드 값과, 기존의 옵션값 및 옵셔널값을 함께 수정한다면 필요에 따라 지속적으로 PV를 프로비저닝 요청할 수 있습니다.

추가로, 이 링크2.3.2 Dynamic Provisioning을 함께 읽어보십시오.

(실습 완료 후) 자원 삭제

  • 매우 중요 EFS가 사용했던 보안그룹 (이름: MyEfsSg)를 삭제 하여 주십시오. 미삭제시 kOps 클러스터가 삭제되지 않습니다.
aws ec2 delete-security-group --group-id <MyEfsSg의 보안그룹ID>
  • 이후 kOps 클러스터 삭제 및 AWS CloudFormation 스택을 삭제합니다.
kops delete cluster --yes && aws cloudformation delete-stack --stack-name mykops

마무리

제 2장 (2) 에서는 쿠버네티스 스토리지에 대해 살펴보았습니다.

이번 장에서는 아래 내용을 반드시 기억하셨으면 좋겠습니다.

  1. AWS CSI의 주요 기능 및 차이점에 대해 해제하였습니다.
    1. 먼저 쿠버네티스의 스토리지에 대해 핵심 내용을 알아보았습니다.
      1. 임시 데이터를 사용하거나, 특정 노드의 특정 경로를 영속적 데이터 저장소로 매핑할 수도 있지만, 이에 대한 한계를 이해했습니다.
      2. 쿠버네티스스럽게(?) 해결하기 위한 방안을 알아보았습니다. PV, PVC, 스토리지 클래스를 통해 영속적인 데이터를 보다 효율적으로 관리할 수 있게 되었습니다.
    2. 이를 가능하게 하는 CSI에 대해 알아보았습니다.
    3. AWS의 블록 스토리지, 파일 스토리지 매핑에 대해 알아보았습니다.
    4. AWS에서 볼륨 스냅샷을 사용 방안에 대해 알아보았습니다.

이것으로 제 2장 파트 2까지, 2장을 마칩니다. 긴 글 읽어주셔서 감사합니다.

[^1]: 출처 : https://cloud.google.com/blog/topics/developers-practitioners/map-storage-options-google-cloud
[^2]: 이 링크에 설명되어있습니다.
[^3]: 출처: https://blog.mayadata.io/kubernetes-storage-basics-pv-pvc-and-storageclass

profile
백엔드 프로그래머

0개의 댓글