KUBERNETES

6. 쿠버네티스 스토리지의 이해 및 EKS 환경 CSI Driver 스토리지 실습

이번 장은 쿠버네티스 스토리지를 알아봅니다.

주요 내용

  • 휘발성 볼륨(Ephemeral Volumes)의 이해
  • 쿠버네티스 CSI Driver와 EKS Addon의 이해
  • PV(Persistent Claim), PVC(Persistent Volume Claim), SC(Storage Class)의 이해
  • 온라인 PVC 볼륨 확장, 가용성 존(AZ, Availability Zone) 제약 사항, Reclaim Policy 이해

실습 과제

  • 파드의 임시 데이터 삭제 테스트
  • EKS CSI Driver 및 Addon 설치
  • ebs-sc 스토리지 클래스 생성
  • PVC를 사용하는 파드 생성

이번 장의 실습에서 사용하는 코드의 깃헙 디렉토리 입니다.

1. 쿠버네티스 휘발성 볼륨 제약 사항의 이해

쿠버네티스 환경에서는 기본 설정으로 별도로 스토리지 구성을 하지 않으면 파드가 재시작하면 같이 사용하던 데이터도 삭제됩니다. 기존 VM 환경에서는 VM을 강제로 삭제하지 않는 이상 애플리케이션이 생성한 데이터는 보관되는 것과 비교하면 큰 차이입니다. 쿠버네티스 환경에서는 파드가 실행 중인 노드가 삭제되지 않았지만 파드 재실행만으로 데이터도 같이 삭제됩니다. 영어 용어가 어려운데 이를 Ephemeral Volumes(휘발성 볼륨, 임시 볼륨)라고 합니다.

Ephemeral Volumes은 쿠버네티스에서 일시적인 데이터 스토리지를 제공하는 볼륨 유형입니다. “Ephemeral”이라는 용어는 일시적이거나 단기적인 것을 의미합니다. 휘발성 볼륨은 컨테이너의 생명 주기와 연동됩니다. 즉, 컨테이너가 생성되거나 재시작될 때마다 해당 볼륨도 같이 초기화되어, 컨테이너가 삭제되면 볼륨의 데이터도 같이 삭제됩니다.

간단한 실습으로 알아봅니다.

ephermeral-vol-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: date-pod
  namespace: default
  labels:
    app: date
spec:
  replicas: 1
  selector:
    matchLabels:
      app: date
  template:
    metadata:
      labels:
        app: date
    spec:
      containers:
      - name: date-pod
        image: busybox
        command:
        - "/bin/sh"
        - "-c"
        - "while true; do date >> /pod-out.txt; sleep 5; done"

간단하게 ‘busybox’ 이미지를 실행하는 Deployment YAML 파일입니다. ‘date’ 명령어를 사용하여 ‘/pod-out.txt’ 파일에 현재 시간 정보를 저장하는 설정입니다.

해당 파드를 실행하고 ‘/pod-out.txt’ 파일을 확인합니다.

[(jerry-test:default) pvc]$ k apply -f ephemeral-vol-deploy.yaml
deployment.apps/date-pod created

[(jerry-test:default) pvc]$ k exec -it date-pod-cd9968dbb-n4gbm -- cat /pod-out.txt
Thu Sep  7 17:29:52 UTC 2023
Thu Sep  7 17:29:57 UTC 2023
Thu Sep  7 17:30:02 UTC 2023

‘/pod-out.txt’ 파일에 현재 시간 정보가 저장되었습니다. 그럼 이전 데이터가 보관되는지 확인하기 위하여 파드를 재시작합니다.

[(jerry-test:default) pvc]$ k delete pod date-pod-cd9968dbb-n4gbm
pod "date-pod-cd9968dbb-n4gbm" deleted

[(jerry-test:default) argo-cd-app-of-apps-qa]$ k get pod --selector app=date
NAME                       READY   STATUS    RESTARTS   AGE
date-pod-cd9968dbb-8zlv9   1/1     Running   0          70s

파드를 재시작하였습니다. 디플로이먼트 리소스로 실행하여 파드를 삭제하면 이전 파드(date-pod-cd9968dbb-n4gbm)는 사라지고 새로운 파드(date-pod-cd9968dbb-8zlv9)가 실행됩니다. 

새로 실행된 파드에서 데이터를 확인합니다.

[(jerry-test:default) pvc]$ k exec -it date-pod-cd9968dbb-8zlv9 -- cat /pod-out.txt
Thu Sep  7 17:34:07 UTC 2023
Thu Sep  7 17:34:12 UTC 2023
Thu Sep  7 17:34:17 UTC 2023

이전 파드에서 저장된 시간 정보(Thu Sep  7 17:29:52 UTC 2023)는 사라지고 새로운 파드가 실행된 시간(Thu Sep  7 17:34:07 UTC 2023)부터 저장됩니다. 즉 이전 데이터가 사라졌습니다. (아마도 운영 경험을 하신 분들은 공감하실텐데 ‘데이터가 사라졌다’라는 엄청난 사고가 발생하였습니다. ^^) 

데이터 저장이 필수인 DB 등의 애플리케이션은 지금처럼 기본 휘발성 볼륨 설정을 사용할 수 없습니다. 따라서 쿠버네티스는 스토리지 시스템을 별도의 리소스로 제공합니다. PV(Persistent Volume), PVC(Persistent Volume Claim), SC(Storage Class)를 이용하여 스토리지 시스템을 구성합니다.

실습을 통하여 자세한 사항을 이해하기 전에 먼저 간단히 이름에서 유추할 수 있는 의미부터 알아보겠습니다. PV는 사라지지 않고 영구(Persistent)히 보관되는 볼륨을 의미하는 쿠버네티스 리소스입니다. 앞선 임시 볼륨과 반대되는 의미로 PV에 저장한 데이터는 사용자가 강제로 삭제하지 않으면 계속 보관됩니다.

PVC는 PV를 요청하는(Claim) 리소스입니다. 파드에서 PV를 사용하기 위해서 PV 이름을 직접 사용하지 않고 PVC 이름을 사용하여 연결합니다. 쿠버네티스에서 종종 사용하는 방식인데 이렇게 실제 리소스와 이를 호출하는 리소스를 서로 분리합니다. PV를 사용하기 위해서 PV를 직접 사용하지 않고 PVC를 이용해서 사용한다 정도로 이해하면 됩니다.

SC, 스토리지클래스는 동일한 성격의 스토리지를 묶은 클래스로 PV를 동적으로 프로비저닝하는 리소스입니다. 예를 들어 Block Storage, File System, Object Storage 등 서로 다른 성격의 스토리지를 구분하는 용도로 사용합니다. 사용자는 필요한 스토리지 클래스 이름을 간단하게 PVC YAML 파일에서 지정하여 사용합니다. 그러면 스토리지 클래스가 사용자 요청에 따라 동적으로 해당 클래스의 PV를 프로비저닝 합니다. 자세한 내용은 실습으로 알아보겠습니다.

2. EKS 환경 스토리지 실습

그럼, 실습으로 EKS 환경에서 쿠버네티스 스토리지 시스템을 구성하는 방법을 알아보겠습니다. PV, PVC, 스토리지 클래스를 사용하기 위해서는 먼저 사전 준비가 필요합니다.

온프레미스 환경의 네이티브 쿠버네티스는 기본 쿠버네티스 설치와 별개로 스토리지를 사용하기 위해서는 추가로 스토리지 시스템을 구성합니다. 이를 위하여 Longhorn, OpenEBS, Ceph 등 다양한 스토리지 서비스 중 각자 환경에 맞게 쿠버네티스 관리자가 선택하여 설치합니다.

이에 반하여 매니지드 쿠버네티스 서비스(EKS, AKS, GKE 등)는 기본 설치 시 스토리지 환경을 같이 제공합니다. EKS 역시 기본 설치 시 스토리지를 바로 사용할 수 있도록 ‘gp2’ 스토리지 클래스 환경을 아래와 같이 제공합니다.

[(jerry-test:default) pvc]$ k get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  16d

위와 같이 ‘k get sc(storage class)’를 명령어를 이용하면 기본으로 설치된 ‘gp2’ 스토리지 클래스를 확인할 수 있습니다. 사용자는 추가 작업없이 해당 스토리지클래스를 이용할 수 있습니다. 매니지드 쿠버네티스 서비스의 장점으로 쿠버네티스 서비스에 자사의 다양한 리소스를 미리 통합하여 제공합니다. 

그러나 기본으로 제공하는 ‘gp2’ 타입의 스토리지는 ‘gp3’에 비하여 성능과 가격이 떨어집니다. 따라서 기본으로 제공하는 gp2 타입의 스토리지를 사용하지 않고 gp3 타입의 스토리지를 사용하는 것을 권고합니다. (gp2 vs gp3 비교 참조)

gp3 타입의 스토리지를 사용하기 위해서 EKS는 CSI(Container Storage Interface) 드라이버를 사용합니다. CSI, 컨테이너 스토리지 인터페이스 드라이버는 쿠버네티스와 외부 스토리지 시스템 간에 표준화된 인터페이스입니다. CSI는 쿠버네티스 Core 컴포넌트에서 스토리지 관리 시스템을 분리하여 다양한 스토리지 벤더가 스냅샷 등 스토리지 추가 기능을 쿠버네티스 Core 컴포넌트 제약 없이 자유롭게 개발할 수 있도록 환경을 제공합니다. 다양한 스토리지 벤더는 CSI 기능을 이용하여 스토리지 추가 기능을 개발하고 있습니다.

2-1. IRSA 및 CSI 드라이버 설치

CSI 드라이버는 EKS 외부의 AWS EBS(Elastic Block Store) 서비스를 사용합니다. 쿠버네티스 외부의 리소스를 제어하므로 역시 IRSA 설정이 필요합니다. 이전 장과 동일하게 테라폼 모듈을 이용하여 CSI 용 IRSA를 설치합니다. (필자 깃헙 파일)

module "ebs_csi_irsa_role" {
  source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

  role_name             = "ebs-csi-jerry-test"
  attach_ebs_csi_policy = true

  oidc_providers = {
    ex = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
    }
  }

  tags = local.tags
}

. role_name
Role 이름은 각자 구분할 수 있게 임의로 지정합니다.

위와 같이 테라폼 파일을 생성하고 CSI 용 IRSA 모듈을 적용합니다.

$ (⎈ |switch-singapore-test:kube-system) tf init
$ (⎈ |switch-singapore-test:kube-system) tf plan -out planfile
$ (⎈ |switch-singapore-test:kube-system) tf apply planfile

적용이 완료되면 AWS 콘솔에서 ebs-csi Role을 확인할 수 있습니다. 참고로 Role 이름이 동일하면 서로 다른 EKS에 사용할 수 없으니 만약 복수의 EKS를 운영한다면 각 EKS마다 서로 다른 Role 이름을 적용합니다.

다음으로 해당 Role을 이용하여 CSI Driver 용 Add-on을 생성합니다. EKS Add-on이란 쿠버네티스 클러스터의 기능을 확장하거나 향상시키기 위해 EKS에 추가적으로 설치되는 컴포넌트입니다. 클러스터를 운영하면서 일반적으로 필요한 여러 기능을 간소화하거나 자동화할 수 있습니다.
저희는 이미 초기 EKS 설치 시 테라폼 코드에 이미 ‘coredns’, ‘kube-proxy’, ‘vpc-cni’가 포함되어 있어 해당 기능을 Add-on으로 관리하고 있습니다.

cluster_addons = {
    coredns = {
      preserve    = true
      most_recent = true

      timeouts = {
        create = "25m"
        delete = "10m"
      }
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
  }

EBS CSI 드라이버 역시 Add-on으로 관리할 수 있습니다. Add-on 리소스의 테라폼 코드는 아래와 같습니다.

eks-addon.tf

variable "aws_account_id" {
    type = string
}

resource "aws_eks_addon" "aws_ebs_csi_driver" {
  cluster_name             = module.eks.cluster_name
  addon_name               = "aws-ebs-csi-driver"
  service_account_role_arn = "arn:aws:iam::${var.aws_account_id}:role/ebs-csi-jerry-test"
  addon_version            = "v1.20.0-eksbuild.1"
  resolve_conflicts        = "OVERWRITE"

  lifecycle {
    ignore_changes = [
      service_account_role_arn
    ]
  }
}

 . service_account_role_arn

앞에서 추가한 EBS CSI Driver Role_Arn을 입력합니다. 각자 AWS Account ID 정보를 수정하여 입력합니다. 

 . addon_version
필자의 버전과 동일하게 사용해도 되고 설치하는 시점의 최신 버전도 사용할 수 있습니다.

테라폼 리소스를 적용합니다.

$ (⎈ |switch-singapore-test:kube-system) tf plan -out planfile
$ (⎈ |switch-singapore-test:kube-system) tf apply planfile

정상으로 설치되면 AWS EKS 콘솔의 Addon 메뉴에 아래와 같이 ‘EBS CSI Driver’를 확인할 수 있습니다.

Add-on이 설치되면 아래와 같이 ebs-csi-controller 디플로이먼트와 ebs-csi-node 데몬셋 리소스가 설치됩니다.

$ (⎈ |switch-singapore-test:kube-system) k get deployments.apps ebs-csi-controller -n kube-system
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
ebs-csi-controller   2/2     2            2           8h

$ (⎈ |switch-singapore-test:kube-system) k get ds ebs-csi-node -n kube-system
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
ebs-csi-node   2         2         2       2            2           kubernetes.io/os=linux   8h

데몬셋(DaemonSet)이란 쿠버네티스 모든 노드에 자동으로 실행되는 컨트롤러 파드입니다. 주로 모니터링, 로그 수집, 스토리지 파드가 데몬셋을 이용합니다. 노드의 특정 디렉토리를 사용하거나 특정 컴포넌트를 실행하는 용도이며 노드가 추가되면 추가 설정없이 자동으로 데몬셋 파드가 실행되어 편리합니다.

EBS CSI Controller 파드는 클러스터에서 PV 생성을 요청하면 해당 요청을 받아서 쿠버네티스 외부의 EBS에 볼륨을 생성하고 연결하는 기능을 담당합니다. 만약 볼륨 구성에 문제가 있으면 ‘ebs-csi-controller’ 파드의 로그를 확인하여 트러블슈팅을 진행합니다.

2-2. SC(Storage Class) 생성

준비한 CSI Driver 기준으로 스토리지클래스(SC)를 생성합니다. SC 역시 쿠버네티스 리소스로 매니페스트 파일로 만들 수 있습니다. (필자 깃헙 파일)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3

. metadata.name: ebs-sc
스토리지클래스 이름입니다. 임의로 지정할 수 있으나 기본으로 제공하는 ‘ebs-sc’ 그대로 사용하는 것을 권고합니다. 앞으로 해당 스토리지 클래스 이름을 PVC에 지정하여 스토리지를 생성합니다.

. metadata.annotations.storageclass.kubernetes.io/is-default-class: “true”
기존 gp2 타입의 스토리지를 클래스를 대체하여 CSI Driver로 만든 스토리지클래스를 기본 스토리지클래스로 지정합니다. PVC 생성 시 별도로 스토리지클래스 이름을 지정하지 않으면 디폴트로 지정한 ‘ebs-sc’ 기준으로 볼륨을 생성합니다.

. allowVolumeExpansion: true
운영 환경에서 볼륨을 확장해야 하는 경우가 종종 발생합니다. 스토리지클래스가 ‘allowVolumeExpansion’ 기능을 지원하면 기존 볼륨을 삭제하거나 Snapshot으로 복제하지 않고 온라인으로 볼륨 확장이 가능합니다. ebs-sc 스토리지 클래스는 온라인 볼륨 확장을 지원합니다.

. provisioner: ebs.csi.aws.com
CSI Driver를 이용하여 볼륨을 생성하도록 명시합니다.

. parameters.type: gp3
비용과 성능에서 우월한 gp3 타입의 스토리지를 사용합니다.

해당 매니페스트를 적용하여 스토리지클래스 리소스를 생성합니다.

$ (⎈ |switch-singapore-test:kube-system) k apply -f ebs-default-storageclass.yaml 
storageclass.storage.k8s.io/ebs-sc created

새롭게 생성한 스토리지클래스를 확인할 수 있습니다.

[(jerry-test:default) aws-ebs-csi]$ k get sc
NAME               PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ebs-sc (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   3s
gp2 (default)      kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  19d

ebs-sc 이름으로 새로운 스토리지 클래스가 생성되었습니다. 그런데 확인하면 ‘default’ 스토리지 클래스가 2개입니다. 기존 gp2 스토리지 클래스의 ‘default’ 스토리지 클래스 설정을 제거합니다. 2개의 default 스토리지 클래스를 사용하면 원하는 설정대로 동작하지 않습니다. ‘kubectl patch’ 명령어를 사용하면 기존 리소스의 속성을 변경할 수 있습니다.

kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

다시 확인하면 의도한대로 ebs-sc만 default 스토리지 클래스로 지정되었습니다.

[(jerry-test:default) aws-ebs-csi]$ k get sc
NAME               PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ebs-sc (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   3m8s
gp2                kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  19d

2-3. PVC(Persistent Volume Claim) 생성

이제 새롭게 만든 CSI Driver 기반의  ‘ebs-sc’ 스토리지클래스를 사용하는 PVC와 PVC를 이용한 파드를 생성합니다. 방법은 PVC 리소스를 먼저 만들고 해당 PVC를 파드에서 마운트하는 형식입니다.

간단히 그림으로 표현하면 아래와 같습니다.

스토리지 클래스를 먼저 만들고 해당 스토리지 클래스의 이름을 PVC YAML 파일에 명시합니다. 그리고 POD YAML 파일에는 PVC 이름을 명시하면 스토리지 관련 설정이 완료됩니다.

먼저, PVC 매니페스트입니다.

ebs-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi

. metadata.name: ebs-claim
임의로 PVC 이름을 지정합니다. 해당 이름을 파드의 매니페스트에 명시하여 파드에서 볼륨을 연결합니다.

. metadata.namespace: default
PVC는 네임스페이스 단위로 리소스를 할당합니다. 해당 네임스페이스의 파드가 PVC를 사용할 수 있습니다.

. spec.accessModes: ReadWriteOnce
EBS 블록 스토리지는 하나의 노드(파드)만 Read, Write가 가능합니다. 만약 여러 파드가 동시에 읽고 쓰기가 가능한 환경이 필요하면 EBS 블록 스토리지가 아닌 EFS 파일 시스템을 사용합니다. EFS 파일 시스템은 ReadWriteMany 엑세스모드를 지원합니다.

. spec.storageClassName: ebs-sc
PVC는 스토리지 클래스 이름을 지정하여 동적으로 볼륨을 할당할 수 있습니다.합니다. 스토리지 클래스를 사용하지 않으면 매번 수동으로 PV를 먼저 지정하고 생성해야 하는데 이는 매우 번거롭습니다. PVC 매니페스트에서 스토리지 클래스를 지정하고 용량과 accessModes만 지정하면 해당 스펙에 따라 파드가 생성되면 볼륨도 같이 생성되는 ‘동적’ 볼륨이 가능합니다.

. spec.resources.requests.storage: 4Gi
파드에서 필요한 볼륨 용량을 지정합니다.

해당 매니페스트를 적용하여 PVC를 생성합니다.

$ (⎈ |switch-singapore-test:default) k apply -f ebs-pvc.yaml 
persistentvolumeclaim/ebs-claim created

생성된 PVC를 확인합니다.

$ (⎈ |switch-singapore-test:default) k get pvc
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ebs-claim   Pending                                      ebs-sc         24s

주의할 것은 STATUS(상태)가 아직 ‘Pending’입니다. 상세한 내용을 확인하기 위하여 ‘describe’ 명령어를 이용합니다. 예상하지 않은 문제가 발생하면 쿠버네티스는 먼저 ‘k describe’ 명령어로 확인합니다.

$ (⎈ |switch-singapore-test:default) k describe pvc ebs-claim
(생략)
Events:
  Type    Reason                Age                From                         Message
  —-    ——                —-               —-                         ——-
  Normal  WaitForFirstConsumer  11s (x3 over 30s)  persistentvolume-controller  waiting for first consumer to be created before binding

내용을 확인하면 ‘첫번째 사용자가 연결하기를 기다린다(waiting for first consumer to be created before binding)’입니다. ebs-sc 스토리지 클래스의 속성을 확인하면 ‘VOLUMEBINDINGMODE – WaitForFirstConsumer’ 입니다. 간단히 해석을 하면 ‘첫번째 사용자를 기다린다’는 의미입니다. 첫번째 사용자 즉, 첫번째 파드가 아직 해당 PVC를 연결하지 않아 PVC가 아직 생성되지 않고 지연(‘Pending’) 상태입니다.

$ (⎈ |switch-singapore-test:default) k get sc
NAME               PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ebs-sc (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   5h10m

그럼 생성한 PVC를 파드에서 사용합니다.

pvc-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pvc-pod
  namespace: default
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: date-vol
      mountPath: /data
  volumes:
  - name: date-vol
    persistentVolumeClaim:
      claimName: ebs-claim

. spec.containers.volumeMounts:-name: date-vol
volumeMounts 이름입니다. 임의의 이름을 지정할 수 있습니다. 여러 개의 볼륨 마운트 이름을 지정할 수 있는데, 이름을 기준으로 구분하여 PVC(또는 ConfigMap)와 연결합니다.

. spec.volumes.-name: date-vol
위에서 지정한 volumeMounts 이름을 지정합니다.

. spec.volumes.persistentVolumeClaim:claimName: ebs-claim
volumeMonuts가 사용할 PVC 이름입니다. 저희는 앞에서 생성한 PVC 이름을 claimName으로 지정합니다. 이 설정에 PVC 이름을 명시하여 파드와 PVC를 서로 연결할 수 있습니다.

파드에서 영구 볼륨을 사용하려면 위와 같이 파드가 볼륨을 사용할 마운트 포인트를 지정하고 해당 마운트 포인트를 외부 PVC와 연결하기 위한 PVC 이름을 명시합니다. 간단히 마운트 포인트와 PVC 이름만 지정하면 모든 설정이 완료됩니다. 어렵거나 복잡하지 않습니다. 

서로 다른 성격의 스토리지를 사용하기 위하여 여러 개의 스토리지 클래스를 설정해도 동일한 매니페스트를 활용할 수 있어 매우 편리합니다. 쿠버네티스는 이렇게 스토리지 사용 방법을 추상화하여 사용자 편의를 높였습니다

해당 매니페스트를 적용하여 파드를 생성합니다.

$ (⎈ |switch-singapore-test:default) k apply -f pvc-pod.yaml 
pod/pvc-pod created

$ (⎈ |switch-singapore-test:default) k get pod pvc-pod 
NAME      READY   STATUS    RESTARTS   AGE
pvc-pod   1/1     Running   0          97s

파드가 정상적으로 생성되고 스토리지가 할당되었는지 확인합니다.

$ (⎈ |switch-singapore-test:default) k exec -it pvc-pod -- cat /data/out.txt 
Wed Jul 19 15:12:10 UTC 2023
Wed Jul 19 15:12:15 UTC 2023
(생략)

VolumeMounts로 지정한 /data/out.txt 파일이 생성되고 해당 파일에 현재 시간 정보(date)가 정상으로 입력되고 있습니다. 그럼 기존 파드를 삭제하고 다시 생성하여 기존 데이터가 보존되는지 확인합니다.

$ (⎈ |switch-singapore-test:default) k delete -f pvc-pod.yaml 
pod "pvc-pod" deleted

쿠버네티스 리소스를 삭제하는 방법에는 위와 같이 -f(file) 옵션을 사용하여 매니페스트 파일로 삭제할 수도 있습니다. pvc-pod 파드가 삭제되었습니다.

$ (⎈ |switch-singapore-test:default) k get pod pvc-pod
Error from server (NotFound): pods "pvc-pod" not found

기존 PVC(ebs-claim)를 사용하는 파드를 다시 생성합니다. 이번에는 기존 데이터가 삭제되지 않고 그대로 보존되는지 확인합니다. 

$ (⎈ |switch-singapore-test:default) k apply -f pvc-pod.yaml 
pod/pvc-pod created

$ (⎈ |switch-singapore-test:default) k exec -it pvc-pod -- cat /data/out.txt
Wed Jul 19 15:12:10 UTC 2023
Wed Jul 19 15:12:15 UTC 2023
(생략)

확인하면 이전 데이터가 삭제되지 않고 그대로 있습니다. 이전 실습에서 PVC를 사용하지 않고 데이터를 저장하면 파드가 리스타트 되면 해당 데이터까지 같이 삭제되었습니다. 하지만 이제 PVC를 사용하면 기존 데이터가 삭제되지 않습니다. 

PVC를 이용하면 파드의 생명 주기(삭제, 생성)와 무관하게 별도로 데이터를 보존할 수 있습니다.

2-4. PV, PVC, SC 관계

그럼, 실습에 사용한 PV, PVC, SC의 관계를 알아보겠습니다. ‘k get pvc’ 명령어를 이용하여 PVC 정보를 확인하면 아래와 같이 PV 이름(pvc-5f4f2824-adb9-452d-969b-f9c127d2eb29)과 스토리지 클래스 ebs-sc가 있습니다.

$ (⎈ |switch-singapore-test:default) k get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ebs-claim   Bound    pvc-5f4f2824-adb9-452d-969b-f9c127d2eb29   4Gi        RWO            ebs-sc         25m

매니페스트 파일을 이용하여 PVC를 생성하면 해당 PVC가 지정한 SC가 자동으로 PV를 생성합니다.

다음은 PV입니다.

$ (⎈ |switch-singapore-test:default) k get pv pvc-5f4f2824-adb9-452d-969b-f9c127d2eb29
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-5f4f2824-adb9-452d-969b-f9c127d2eb29   4Gi        RWO            Delete           Bound    default/ebs-claim   ebs-sc                  13m

PV를 확인하면 ‘CLAIM – default/ebs-claim’을 확인할 수 있습니다. 해당 PV를 요청하는(claim) PVC 이름이 ebs-claim임을 알 수 있습니다. 즉 해당 PV는 ‘default/ebs-claim’으로 생성한 PV임을 나타냅니다. 그리고 PVC와 동일하게 PV를 생성한 스토리지 클래스도 ‘ebs-sc’임을 ‘STORAGECLASS’에서 확인할 수 있습니다.

정리하면 PVC 매니페스트에 스토리지클래스를 지정하고 PVC를 생성하면 스토리지클래스가 자동으로 PV를 생성합니다. PV를 먼저 생성할 필요없이 매니페스트로 PVC를 생성하면 동적으로 PV를 생성합니다.

그림으로 표현하면 아래와 같습니다.

관리자가 사전에 서비스 요구 사항에 따라 필요한 스토리지 클래스를 미리 생성합니다. 그리고 개발자는 필요한 스토리지 클래스만 지정하면 동적으로 볼륨을 할당하여 애플리케이션에서 사용할 수 있습니다. 스토리지 종류에 따라 애플리케이션 코드를 변경하지 않고 단순히 PVC 이름만 변경할 수 있어 매우 편리합니다.

3. 스토리지 운영 팁

원활한 스토리지 시스템 운영을 위한 1) Volume Expansion 2) 가용성 존(AZ, Availability Zone) 제약 사항 3) Reclaim Policy을 알아봅니다.

시스템 운영 시 볼륨을 확장해야 하는 경우가 종종 발생합니다. 볼륨이 부족하여 확장해야 하는데, 기존 볼륨을 백업하고 새로운 볼륨에 기존 데이터를 복원하는 것은 시간도 많이 걸리고 데이터 유실 염려도 있어 굉장히 부담스러운 작업입니다. 다행히 EKS CSI Driver로 생성한 볼륨은 온라인 볼륨 확장 기능을 지원합니다. 쿠버네티스에 사용 가능한 스토리지 중 온라인 볼륨 확장 기능을 지원하는 스토리지들이 있습니다. 볼륨 확장 지원 여부는 스토리지 클래스 속성에서 확인할 수 있습니다.

[(jerry-test:default) ~]$ k get sc
NAME               PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ebs-sc (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   2d21h
gp2                kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  22d

‘ALLOWVOLUMEEXPANSION’ 속성을 보면 새롭게 생성한 ‘ebs-s’c 스토리지 클래스는 ‘true’ 입니다. 이에 반하여 기본으로 제공하는 ‘gp2’ 스토리지 클래스는 ‘false’ 입니다. 즉 ‘ebs-sc’로 생성한 볼륨은 확장이 가능하지만 ‘gp2’로 생성한 볼륨은 볼륨 확장 기능을 제공하지 않습니다.

‘k edit pvc’ 명령어를 사용하여 간단히 볼륨을 확장해 보겠습니다. 기존에 만들어진 리소스의 속성을 변경하기 위해서 ‘k patch’ 명령어와 ‘k edit’ 명령어를 사용할 수 있습니다.

[(jerry-test:default) ~]$ k edit pvc ebs-claim
(생략)
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi # 4Gi to 10Gi
  storageClassName: ebs-sc
  volumeMode: Filesystem
  volumeName: pvc-8283283c-a2f3-4a59-bf84-9ac2ffbedbad
(생략)

기존 4Gi 용량을 10Gi로 변경하고 저장(:wq 이용)하고 빠져나옵니다. ‘k edit’ 명령어는 VI와 동일하게 ‘:wq’ 명령어를 사용하여 변경 사항을 저장할 수 있습니다.

[(jerry-test:default) ~]$ k edit pvc ebs-claim
persistentvolumeclaim/ebs-claim edited

용량을 변경하고 다시 PVC 속성을 확인하면 용량이 증가한 것을 확인할 수 있습니다.

[(jerry-test:default) ~]$ k get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ebs-claim   Bound    pvc-283283c-a2f3-a59-bf84-ac2ffbedbad   10Gi       RWO            ebs-sc         3h1m

실제 파드에서 확인하여도 볼륨이 확장된 것을 확인할 수 있습니다.

[(jerry-test:default) ~]$ k exec -it pvc-pod -- sh
sh-4.4# df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay         100G  7.8G   93G   8% /
tmpfs            64M     0   64M   0% /dev
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/nvme1n1    9.8G   84K  9.7G   1% /data
/dev/nvme0n1p1  100G  7.8G   93G   8% /etc/hosts
(생략)

위와 같이 볼륨 확장이 필요한 경우 간단한 작업으로 가능합니다. 위급한 상황에 사용할 수 있는 매우 유용한 기능입니다. 

다음으로 AWS EBS 볼륨의 가용성 존(Availability Zone, AZ) 제약 사항을 알아봅니다. EBS 볼륨은 가용성 존에 속하는 자원입니다. 따라서 EBS를 사용하려면 해당 AZ에 노드가 실행되어야 합니다. 다른 가용성 존에 있는 EBS를 사용할 수 없어 파드가 실행하지 못하는 에러가 가끔 발생합니다. 상세 메시지에서 파드가 EBS 볼륨을 마운트하지 못하면 먼저 가용성 존을 확인합니다.

PV의 상세 정보를 아래와 같이 확인하면 해당 PV가 배포된 AZ 정보를 확인할 수 있습니다.

$ (⎈ |switch-singapore-test:default) k get pv pvc-c84491be-5a51-464d-bc93-fdfaf199685c -ojson |jq '.spec.nodeAffinity.required.nodeSelectorTerms[].matchExpressions[]'
{
  "key": "topology.ebs.csi.aws.com/zone",
  "operator": "In",
  "values": [
    "ap-northeast-2c"
  ]
}

해당 PV는 위와 같이 ‘ap-northeast-2c’에 할당되어 다른 가용성 존에 있는 파드는 해당 PV를 사용할 수 없습니다. 실제 운영 환경에서 종종 파드에서 PV를 할당하지 못하는 에러가 발생하는데 이는 해당 AZ의 노드를 실행하지 못하여 발생하는 문제입니다. 노드가 해당 AZ에 실행하기까지 조금 기다리면 해결되는 경우가 많습니다.

다음은 ‘Reclaim Policy’입니다. Reclaim Policy는 회수, 재활용 정책으로 번역할 수 있는데 Delete(삭제), Retain(유지) 2가지 옵션이 있습니다. PVC를 삭제할 때 PV도 같이 삭제(Delete)할 것인지 아니면 유지(Retain)할 것인지 선택하는 옵션입니다.

일반적으로 Delete 옵션을 사용하여 PVC를 삭제하면 PV도 같이 삭제하여 관리 편의성을 고려합니다. 하지만 데이터를 특별히 보관해야 하는 경우 Delete 옵션이 아닌 Retain 정책을 사용하기도 합니다.

그럼, 파드와 PVC를 삭제하여 실제로 PV가 삭제되는지 확인하겠습니다.

$ (⎈ |switch-singapore-test:default) k delete pod pvc-pod 
pod "pvc-pod" deleted

$ (⎈ |switch-singapore-test:default) k delete pvc ebs-claim
persistentvolumeclaim "ebs-claim" deleted

파드와 PVC를 삭제하면 PVC에 연결된 PV까지 같이 삭제됩니다. Reclaim Policy로 Delete를 사용하면 이와 같이 PVC를 삭제하면 자동으로 PV까지 같이 삭제합니다.

$ (⎈ |switch-singapore-test:default) k get pv pvc-5f4f2824-adb9-452d-969b-f9c127d2eb29   
Error from server (NotFound): persistentvolumes "pvc-5f4f2824-adb9-452d-969b-f9c127d2eb29" not found

이상 쿠버네티스 환경의 스토리지 서비스를 알아보았습니다.

해당 기술 블로그에 질문이 있으시면 언제든지 문의해 주세요. 직접 답변해 드립니다.
k8sqna@jennifersoft.com

1. 쿠버네티스 휘발성 볼륨 추가 설명 https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/  
2.  gp2 vs gp3 비교 https://docs.aws.amazon.com/ko_kr/emr/latest/ManagementGuide/emr-plan-storage-compare-volume-types.html
3. EKS도 스토리지 구성을 위한 추가 작업이 필요하므로 네이티브 쿠버네티스와 유사합니다.
4.  테라폼 깃헙 IRSA for EKS  https://github.com/terraform-aws-modules/terraform-aws-iam/blob/master/examples/iam-role-for-service-accounts-eks/main.tf 

Next

Contact Us

안녕하세요? 제니퍼소프트입니다.
기술 문의의 경우 질문자의 회사/이름/연락처를 본문에 기술해 주셔야만 원할한 지원이 가능합니다.
보내주신 문의 사항을 검토하여 빠른 시일 내에 답변해 드리겠습니다.

  • Chris
  • Irene

메일을 보냈습니다.

메일 전송이 완료되었습니다.
빠른 시일 내에 답변드리겠습니다.
감사합니다.
제니퍼소프트 웹사이트는 쿠키를 사용합니다. 쿠키에 대한 자세한 정보 및 삭제 방법은 제니퍼소프트의 개인정보처리방침을 참고하시기 바라며 본 사이트를 계속해서 이용하는 것은 제니퍼소프트의 쿠키 사용에 동의함을 의미합니다.