본문 바로가기
Tech/Kubernetes

[AEWS_1기] 3주차 - Amazon EKS Storage (1/5) - 스토리지의 이해

by 구름_쟁이 2023. 5. 13.

본 시리즈는 가시다님의 AEWS(AWS EKS Workshop) 1기 진행 내용입니다. (가시다님 노션)

스터디에 사용되는 링크 (AWS EKS Workshop) 

 

목차

1. 스토리지의 이해
2. AWS EBS Controller
3. AWS Volume Snapshots Controller
4. AWS EFS Controller
5. AWS Persistent Volume for Instance Store & Add Node Group

 

 

     


    1. 스토리지의 이해

    https://aws.amazon.com/ko/blogs/tech/persistent-storage-for-kubernetes/

     

    Kubernetes를 위한 영구 스토리지 적용하기 | Amazon Web Services

    이 글은 AWS Storage Blog에 게시된 Persistent storage for Kubernetes by Suman Debnath, Daniel Rubinstein, Anjani Reddy, and Narayana Vemburaj을 한국어 번역 및 편집하였습니다. 상태 저장 애플리케이션이 올바르게 실행되기

    aws.amazon.com

    기본 설명

    • 파드 내부의 데이터는 파드가 정지되면 모두 삭제됨
    • 즉, 모두 상태가 없는(Stateless) 애플리케이션: Temporary filesystem, Volume - 링크

    https://aws.amazon.com/ko/blogs/tech/persistent-storage-for-kubernetes/

     

     

    • 데이터베이스(파드)처럼 데이터 보존이 필요 == 상태가 있는(Stateful) 애플리케이션 : PV & PVC
      • 로컬 볼륨(hostPath) ⇒ 퍼시스턴트 볼륨(Persistent Volume, PV) - 어느 노드에서도 연결하여 사용 가능, 예시) NFS, AWS EBS, Ceph 등

     

    https://aws.amazon.com/ko/blogs/tech/persistent-storage-for-kubernetes/

     

    • 파드가 생성될 때 자동으로 볼륨을 마운트하여 파드에 연결하는 기능을 동적 프로비저닝(Dynamic Provisioning)이라고 함(스토리지 클래스 사용)

    https://aws.amazon.com/ko/blogs/tech/persistent-storage-for-kubernetes/

    • Reclaim Policy
      • 퍼시스턴트 볼륨의 사용이 끝났을 때 해당 볼륨은 어떻게 초기화할 것인지 별도로 설정
      • Retain(보존), Delete(삭제, 즉 EBS 볼륨도 삭제됨), Recycle(deprecated) 방식

     

    스토리지 소개 : 출처 - 김태민 기술 블로그 - 링크

    • 볼륨 : emptyDir, hostPath, PV/PVC

     

    • 다양한 볼륨 사용 : K8S 자체 제공(hostPath, local), 온프렘 솔루션(ceph 등), NFS, 클라우드 스토리지(AWS EBS 등)

     

     

    • 동적 프로비저닝 & 볼륨 상태 , ReclaimPolicy

     

    CSI (Contaier Storage Interface) 소개

    • CSI Driver 배경
      • Kubernetes source code 내부에 존재하는 AWS EBS provisioner는 당연히 Kubernetes release lifecycle을 따라서 배포
      • provisioner 신규 기능을 사용하기 위해서는 Kubernetes version을 업그레이드해야 하는 제약 사항 존재
      • 따라서, Kubernetes 개발자는 Kubernetes 내부에 내장된 provisioner (in-tree)를 모두 삭제하고, 별도의 controller Pod을 통해 동적 provisioning을 사용
    • CSI 를 사용하면, K8S 의 공통화된 CSI 인터페이스를 통해 다양한 프로바이더를 사용 가능

    출처 : AWS 문서

    • 일반적인 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

     

    Node-specific Volume Limits - 링크

    AWS EC2 Type에 따라 볼륨 최대 제한 : 25개 ~ 39개

    # 확인
    kubectl describe node | grep Allocatable: -A1
    Allocatable:
      attachable-volumes-aws-ebs:  25
    • KUBE_MAX_PD_VOLS 환경 변수의 값을 설정한 후, 스케줄러를 재시작하여 이러한 한도를 변경 가능

    실습 환경에서 확인

     

     

    기본 컨테이너 환경의 임시 파일시스템 사용

    # 파드 배포
    # date 명령어로 현재 시간을 10초 간격으로 /home/pod-out.txt 파일에 저장
    curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/date-busybox-pod.yaml
    cat date-busybox-pod.yaml | yh
    kubectl apply -f date-busybox-pod.yaml
    
    # 파일 확인
    kubectl get pod
    kubectl exec busybox -- tail -f /home/pod-out.txt
    Sat Jan 28 15:33:11 UTC 2023
    Sat Jan 28 15:33:21 UTC 2023
    ...
    
    # 파드 삭제 후 다시 생성 후 파일 정보 확인 > 이전 기록이 보존되어 있는지?
    kubectl delete pod busybox
    kubectl apply -f date-busybox-pod.yaml
    kubectl exec busybox -- tail -f /home/pod-out.txt
    
    # 실습 완료 후 삭제
    kubectl delete pod busybox

    데이터가 없어지고 새로 쌓이는 것을 볼 수 있다

     

     

    호스트 Path 를 사용하는 PV/PVC : local-path-provisioner 스트리지 클래스 배포 - 링크

    # 배포
    curl -s -O https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
    kubectl apply -f local-path-storage.yaml
    
    # 확인
    kubectl get-all -n local-path-storage
    kubectl get pod -n local-path-storage -owide
    kubectl describe cm -n local-path-storage local-path-config
    kubectl get sc
    kubectl get sc local-path
    NAME         PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    local-path   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  34s
    • PV/PVC 를 사용하는 파드 생성
    # PVC 생성
    curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/localpath1.yaml
    cat localpath1.yaml | yh
    kubectl apply -f localpath1.yaml
    
    # PVC 확인
    kubectl get pvc
    kubectl describe pvc
    
    # 파드 생성
    curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/localpath2.yaml
    cat localpath2.yaml | yh
    kubectl apply -f localpath2.yaml
    
    # 파드 확인
    kubectl get pod,pv,pvc
    kubectl describe pv    # Node Affinity 확인
    kubectl exec -it app -- tail -f /data/out.txt
    Sun Jan 29 05:13:45 UTC 2023
    ... 
    
    # 워커노드 중 현재 파드가 배포되어 있다만, 아래 경로에 out.txt 파일 존재 확인
    ssh ec2-user@$N1 tree /opt/local-path-provisioner
    /opt/local-path-provisioner
    └── pvc-f1615862-e4cd-47d0-b89c-8d0e99270678_default_localpath-claim
        └── out.txt
    
    # 해당 워커노드 자체에서 out.txt 파일 확인 : 아래 굵은 부분은 각자 실습 환경에 따라 다름
    ssh ec2-user@$N1 tail -f /opt/local-path-provisioner/pvc-f1615862-e4cd-47d0-b89c-8d0e99270678_default_localpath-claim/out.txt
    Sun Jan 29 05:13:45 UTC 2023
    ...
    • 파드 삭제 후 파드 재생성해서 데이터 유지 되는지 확인다음 실습을 위해서 파드와 PVC 삭제
    # 파드와 PVC 삭제 
    kubectl delete pod app
    kubectl get pv,pvc
    kubectl delete pvc localpath-claim
    
    # 확인
    kubectl get pv
    ssh ec2-user@$N3 tree /opt/local-path-provisioner

    /data/out.txt 경로에 5초간격으로 로그를 쌓는 pod 배포
    pvc가 정상적으로 Bound

    ip-192-168-1-248.ap-northeast-2.compute.internal 노드에 배포됨

    • 당연히 node에 귀속된 디스크 자원을 쓰는 형태로 볼륨을 잡았기 때문에 데이터(볼륨)가 있는 node로 pod를 배포

     

    1차 배포 후 데이터 확인하고 pod 삭제
    1차 배포 때 쌓아진 데이터가 그대로 있음 확인

     

     

    복습 겸 퀴즈
    hostpath(local-path-provisioner)를 사용하는 Deployment를 배포하면 Pod는 어떤 node들에 배포될까?

    정답

    더보기

    노드 하나에 다 배포된다.

    다만, 기분이 나쁘니 단순히 pod가 노드마다 있었으면 좋겠다면 아래처럼 하면 된다.

    StatefulSet으로 만들면 이렇게 된다

    대신 데이터는 당연히 3개 파드가 각각 다른 영구적볼륨에 저장된다.

     

     

    번외편 (응용)

    아까 StoageClassName을 잘 기억해뒀다 쓰면 됨이라고 표기해둔 이유

    더보기

    Helm Chart를 통해 배포할 때 용이하게 사용 가능

    이건 local-path-provisioner 뿐만 아니라 모든 동적 프로비저닝 방식에서 지정한 StorageClassName을 사용하면 된다

     

    예시 Jenkins Helm Chart

    https://artifacthub.io/packages/helm/jenkinsci/jenkins

     

    우측 Default Values나 본문 아래로 내려보면 파라미터값에 대한 설명이 있다.
    storageClass로 검색하면 이와같이 찾을 수 있다

    단 헬름 차트마다 만드는 사람이 value의 파라미터 명을 조금씩 바꿔서 기입하니 반드시 확인할 것.

     

    values보다 정확하게 확인하려면 Templates 을 보자

     

    ## jenkins-values.yaml
    persistence:
      enabled: true
      storageClass: "local-path"
      annotations: {}
      labels: {}
      accessMode: "ReadWriteOnce"
      size: "8Gi"
      volumes:
      - name: nothing
        emptyDir: {}
      mounts:
      - mountPath: /var/nothing
        name: nothing
        readOnly: true

     

    ## helm repo add
    helm repo add jenkins https://charts.jenkins.io
    helm repo update
    
    ## jenkins-values.yaml 작성 후 실행
    helm install jenkins jenkins/jenkins -f jenkins-values.yaml

     

    다른 어플리케이션의 Helm Chart에서도 대부분 다 제공한다

     

     

    이렇게 간단하게 사용 가능하다

     

     

     

    결론

    로컬 스토리지를 단계별로 실습했다.

    1. 임시 스토리지 (휘발)

    2. hostPath (node 귀속)

    2-1. 수동 pvc

    2-2. 동적 프로비저닝

    번외. Helm Chart에서 StorageClass 사용

     

    HostPath 의 장점

    • Node의 컴퓨팅 리소스를 사용하여 빠르다(NFS나 외부 저장소를 마운트한 디렉토리 제외)
    • 간편한 설정
    • 비용 절감 (로컬 자원 사용)

    HostPath의 단점

    • Node에 Pod가 귀속된다.
    • 확장성
    • 데이터의 내구성
    • 보안 (데이터 격리 및 액세스 제어 어려움)

     

    • HostPath 동적 프로비저닝은 임시 데이터나 캐시 데이터와 같이 영구적인 스토리지가 필요하지 않은 경우에 적합
    • 그러나 주의해야 할 점은 HostPath 스토리지가 로컬 노드에 있으므로 Pod가 스케줄링되는 노드 간에 데이터가 이동할 수 없다는 것.
    • 따라서, 데이터의 내구성이 중요한 경우에는 클라우드 프로바이더의 외부 스토리지를 사용하는 것이 더 적합

     

     

     

    댓글