kubernetes CKA study (25) - Container Storage Interface(CSI), Volumes, Persistent Volumes, Persistent Volume Claims, Storage Class

이동명·2024년 1월 2일
0

kubernetes CKA study

목록 보기
25/37
post-thumbnail

Container Runtime Interface

과거 쿠버네티스는 컨테이너 런타임 엔진으로 도커만 사용했고, 도커와 연동되는 모든 코드는 쿠버네티스 소스 코드에 builtin되어 있었습니다. Rocket 및 CRI-O와 같은 다른 컨테이너 런타임이 등장함에 따라 Kubernetes 소스 코드에 의존하지 않고 다른 컨테이너 런타임으로 작업할 수 있도록 지원을 개방하고 확장하는 것이 중요했습니다. 이것이 컨테이너 런타임 인터페이스가 탄생한 배경입니다.

Container Storage Interface

컨테이너 스토리지 인터페이스는 Kubernetes와 같은 오케스트레이션 솔루션이 Docker와 같은 컨테이너 런타임과 통신하는 방법을 정의하는 표준입니다. 따라서 미래에 새로운 컨테이너 런타임 인터페이스가 개발되면 CRI 표준을 따를 수 있으며 새로운 컨테이너 런타임은 Kubernetes 개발자 팀과 실제로 작업하거나 Kubernetes 소스 코드를 만질 필요 없이 Kubernetes에서 작동합니다.

짐작할 수 있듯이 Container Storage Interface는 여러 스토리지 솔루션을 지원하도록 개발되었습니다. CSI를 사용하면 이제 자체 스토리지용 드라이버를 작성하여 Kubernetes와 함께 사용할 수 있습니다. Port Works, Amazon EBS, Azure Desk, Dell EMC Isilon, PowerMax Unity, XtremIO, NetApp, Nutanix, HPE, Hitachi, Pure Storage. 누구나 자신만의 CSI 드라이버를 가지고 있습니다. CSI는 Kubernetes 특정 표준이 아닙니다. 이것은 보편적인 표준을 의미하며 구현된 경우 모든 컨테이너 오케스트레이션 도구가 지원되는 플러그인이 있는 모든 스토리지 공급업체와 작동할 수 있습니다. 현재 Kubernetes Cloud Foundry와 Mesos는 CSI에 탑재되어 있습니다. 이것이 CSI의 모습입니다.

이것은 컨테이너 오케스트레이터에 의해 호출될 RPC 또는 원격 프로시저 호출 세트를 정의하며 스토리지 드라이버에 의해 구현되어야 합니다. 예를 들어 CSI는 파드가 생성되고 볼륨이 필요할 때 컨테이너 오케스트레이터(이 경우 Kubernetes)가 볼륨 생성 RPC를 호출하고 볼륨 이름과 같은 세부 정보 집합을 전달해야 한다고 말합니다. 스토리지 드라이버는 이 RPC를 구현하고 해당 요청을 처리하고 스토리지 어레이에서 새 항목을 프로비저닝하고 작업 결과를 반환해야 합니다. 마찬가지로 컨테이너 오케스트레이터는 볼륨이 삭제될 때 볼륨 삭제 RPC를 호출해야 하며 스토리지 드라이버는 해당 호출이 이루어질 때 어레이에서 볼륨을 폐기하는 코드를 구현해야 합니다. 그리고 사양에는 색상이 전송해야 하는 파라미터, 솔루션에서 수신해야 하는 파라미터, 교환해야 하는 오류 코드가 정확히 무엇인지 자세히 설명되어 있습니다. 관심이 있는 경우 이 URL의 GitHub에 있는 CSI 사양에서 이러한 모든 세부 정보를 볼 수 있습니다.

https://github.com/container-storage-interface/spec

Container Networking Interface

마찬가지로 네트워킹 강의에서 다양한 네트워킹 솔루션에 대한 지원을 확장하기 위해 본 것처럼 컨테이너 네트워킹 인터페이스가 도입되었습니다. 이제 새로운 네트워킹 공급업체는 CNI 표준을 기반으로 플러그인을 개발하고 솔루션이 Kubernetes와 함께 작동하도록 만들 수 있습니다.

Volumes

persistent volume으로 이동하기 전에 Kubernetes의 볼륨부터 살펴보겠습니다.

먼저 Docker의 볼륨을 살펴보겠습니다. Docker 컨테이너는 본질적으로 임시적이므로 짧은 시간 동안만 지속됩니다. 데이터 처리가 필요할 때 호출되고 완료되면 폐기됩니다. 컨테이너 내의 데이터도 마찬가지입니다. 데이터는 컨테이너와 함께 파괴됩니다. 컨테이너에서 처리한 데이터를 유지하기 위해 컨테이너가 생성될 때 컨테이너에 볼륨을 연결합니다. 컨테이너에서 처리한 데이터는 이제 이 볼륨에 배치되어 영구적으로 유지됩니다. 컨테이너가 삭제되더라도 컨테이너에서 생성되거나 처리된 데이터는 그대로 유지됩니다.

그렇다면 쿠버네티스 세계에서는 어떻게 작동할까요? Docker에서와 마찬가지로 Kubernetes에서 생성된 파드는 본질적으로 일시적입니다. 데이터를 처리하기 위해 Pod를 생성한 후 삭제하면 Pod에서 처리한 데이터도 함께 삭제됩니다. 이를 위해 파드에 볼륨을 연결합니다. 파드에서 생성된 데이터는 이제 볼륨에 저장되며, 파드이 삭제된 후에도 데이터가 그대로 유지됩니다. 간단한 볼륨 구현을 살펴보겠습니다.

단일 노드 Kubernetes 클러스터가 있습니다. 우리는 1에서 100 사이의 임의의 숫자를 생성하고 /opt/number.out 으로 파일을 작성하는 간단한 파드를 만듭니다. 그런 다음 그 임의의 숫자와 함께 삭제됩니다.

Volume Storage Options

파드에서 생성된 번호를 유지하기 위해 볼륨을 생성합니다. 볼륨에는 스토리지가 필요합니다. 볼륨을 생성할 때 다양한 방식으로 스토리지를 구성하도록 선택할 수 있습니다. 다양한 옵션을 잠시 살펴보겠지만 지금은 간단히 호스트의 디렉토리를 사용하도록 구성하겠습니다.

이 경우 hostPath에 /data 를 지정합니다. 이렇게 하면 볼륨에 생성된 모든 파일이 내 노드의 디렉토리 데이터에 저장됩니다. 볼륨이 생성되면 컨테이너에서 볼륨에 액세스하기 위해 컨테이너 내부의 디렉토리에 볼륨을 마운트합니다. 각 컨테이너의 볼륨 마운트 필드를 사용하여 데이터 볼륨을 /opt 디렉토리에 마운트합니다. 난수는 이제 데이터 볼륨에 있는 컨테이너 내부의 /opt 마운트에 기록되며 실제로는 호스트의 데이터 디렉토리입니다. 파드가 삭제되더라도 난수를 가진 파일은 여전히 호스트에 있습니다.

한 걸음 물러서서 볼륨 스토리지 옵션을 살펴보겠습니다. 호스트 경로 옵션을 사용하여 호스트에서 볼륨의 저장 공간으로 직접 구성했습니다. 이제는 단일 노드에서 제대로 작동하지만 다중 노드 클러스터에서는 사용하지 않는 것이 좋습니다. Pod가 모든 노드에서 /data 디렉토리를 사용하고 모든 노드가 동일하고 동일한 데이터를 가질 것으로 예상하기 때문입니다. 서로 다른 서버에 있기 때문에 실제로는 동일하지 않습니다. 일종의 외부 복제 클러스터 스토리지 솔루션을 구성하지 않는 한. Kubernetes는 NFS, 클러스터 문제, Flocker, 파이버 채널, Ceph FS, scale io 또는 AWS, EBS, Azure 데스크 또는 파일과 같은 퍼블릭 클라우드 솔루션 또는 Google의 Persistent Desk와 같은 여러 유형의 다양한 스토리지 솔루션을 지원합니다. 예를 들어 AWS Elastic Block Store 볼륨을 볼륨의 스토리지 옵션으로 구성하기 위해 볼륨의 호스트 경로 필드를 볼륨 ID 및 파일 시스템 유형과 함께 AWS Elastic Block Store 필드로 교체했습니다.

volumes:
- name: data-volume
  awsElasticBlockStore:
    volumeID: <volume-id>
    fsType: ext4

볼륨 스토리지는 이제 AWS EBS에 있습니다. 이것이 Kubernetes의 볼륨에 관한 것입니다. 이제 이후 강의에서 persistent volume에 대해 논의하겠습니다.

Persistent Volumes

지난 강의에서 우리는 volume에 대해 배웠습니다. 이제 Kubernetes의 persistent volume에 대해 설명하겠습니다. 이전 섹션에서 볼륨을 생성할 때 파드 definition 파일 내에서 볼륨을 구성했으므로 볼륨에 대한 스토리지를 구성하는 데 필요한 모든 configuration 정보는 파드 definition 파일 내에 있습니다.

유저가 많고, 많은 파드를 배포하는 대규모 환경의 경우에는 각 파드에 대해 매번 스토리지를 구성해야 합니다. 어떤 스토리지 솔루션을 사용하든 파드를 배포하는 사용자는 자신의 환경에 있는 모든 파드 definition 파일에서 이를 구성해야 합니다. 변경 사항이 있을 때마다 사용자는 자신의 모든 파드에 변경 사항을 적용해야 합니다. 따라서 스토리지를 보다 중앙에서 관리하고 싶을 것입니다. 관리자가 대규모 스토리지 풀을 생성한 다음 사용자가 필요에 따라 풀을 분할하도록 구성할 수 있습니다. 이것이 persistent volume이 나타난 이유입니다.

persistent volume은 클러스터에 애플리케이션을 배포하는 사용자가 사용하도록 관리자가 구성한 cluster-wide 스토리지 볼륨 풀입니다. 이제 사용자는 persistent volume claims을 사용하여 이 풀에서 스토리지를 선택할 수 있습니다.

이제 persistent volume을 생성해 보겠습니다. default 템플릿으로 시작합니다.

kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-vol1
spec:
  accessModes: [ "ReadWriteOnce" ]
  capacity:
   storage: 1Gi
  hostPath:
   path: /tmp/data

API 버전을 업데이트합니다.

kind를 persistent volume으로 설정하고

metadata>name을 pv-vol1로 지정합니다.

spec 섹션에서 accessModes를 지정합니다. 액세스 모드는 읽기 전용 모드인지 읽기/쓰기 모드인지 등 호스트에 볼륨을 마운트하는 방법을 정의합니다. 지원되는 값은 ReadOnlyMany, ReadWriteOnce, ReadWriteMany 모드입니다.

다음은 storage입니다. 이 persistent volume에 대해 스케쥴링할 스토리지 양을 지정합니다. 여기서는 1GB로 설정됩니다. 다음은 볼륨 유형입니다. 노드의 로컬 디렉토리에서 저장소를 사용하는 hostPath 옵션부터 시작하겠습니다. 이 옵션은 프로덕션 환경에서 사용되지 않습니다.

$ kubectl create -f pv-definition.yaml
persistentvolume/pv-vol1 created

$ kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-vol1   1Gi        RWO            Retain           Available                                   3min

$ kubectl delete pv pv-vol1
persistentvolume "pv-vol1" deleted

Persistent Volume Claims

이전 강의에서 persistent volume을 만들었습니다. 이제 노드에서 스토리지를 사용할 수 있도록 persistent volume claims을 생성하려고 합니다. persistent volume 및 persistent volume claims은 Kubernetes 네임스페이스에서 두 개의 개별 오브젝트입니다. 관리자는 persistent volume 세트를 생성하고 사용자는 스토리지를 사용하기 위해 persistent volume claims을 생성합니다. persistent volume claims이 생성되면 Kubernetes는 request와 volume에 설정된 속성을 기반으로 persistent volume을 claims에 바인딩합니다.

모든 persistent volume claims은 단일 persistent volume에 바인딩됩니다. 바인딩 프로세스 중에 Kubernetes는 claims에서 요청한 대로 용량이 충분한 persistent volume을 찾으려고 합니다. 여기에는 액세스 모드, volume 모드, 스토리지 클래스 등과 같은 기타 모든 요청 속성도 반영이 됩니다. 그러나 단일 claims에 대해 가능한 볼륨이 여러 개 있고 특히 특정 volume을 사용하려는 경우엔 레이블과 selector를 사용하여 올바른 volume에 바인딩할 수 있습니다. 마지막으로, 다른 모든 기준이 일치하고 더 나은 옵션이 없는 경우 더 작은 claims이 더 큰 volume에 바인딩될 수 있습니다.

claims과 volume 사이에는 일대일 관계가 있으므로 다른 claims은 volume의 나머지 용량을 사용할 수 없습니다. 사용 가능한 volume이 없는 경우 persistent volume claims은 클러스터에서 새 volume을 사용할 수 있을 때까지 보류 상태로 유지됩니다. 최신 volume을 사용할 수 있게 되면 claims은 자동으로 새로 사용 가능한 volume에 바인딩됩니다.

이제 persistent volume claims을 생성하겠습니다. 빈 템플릿으로 시작합니다.

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes: [ "ReadWriteOnce" ]
  resources:
   requests:
     storage: 500Mi

API 버전을 v1로 설정하고 kind를 PersistentVolumeClaims으로 설정합니다.

metadata>name에는 "myclaim"이라고 이름을 지정합니다.

아래 spec을 작성하겠습니다. accessModes를 "ReadWriteOnce"로 설정합니다. 그리고 500MB의 저장소를 요청하도록 리소스를 설정합니다.

kubectl create 커맨드를 사용하여 claims을 만듭니다. 생성된 claims을 보려면 kubectl get persistent volume claims 커맨드를 실행합니다. claim이 pending상태인 것을 확인할 수 있습니다. claims이 생성되면 Kubernetes는 이전에 생성된 volume을 확인합니다.

kind: PersistentVolume
apiVersion: v1
metadata:
    name: pv-vol1
spec:
    accessModes: [ "ReadWriteOnce" ]
    capacity:
     storage: 1Gi
    hostPath:
     path: /tmp/data

액세스 모드가 일치하고, 요청된 용량은 500MB이지만 volume은 1GB의 스토리지로 구성됩니다. 사용할 수 있는 다른 volume이 없으므로 persistent volume claims은 persistent volume에 바인딩됩니다.

$ kubectl create -f pvc-definition.yaml
persistentvolumeclaim/myclaim created

$ kubectl get pvc
NAME      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Pending                                                     35s

$ kubectl get pvc
NAME      STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound    pv-vol1   1Gi        RWO                           1min

kubectl get persistent volume claims 커맨드를 실행하면 claims이 우리가 생성한 persistent volume에 바인딩된 것을 다시 볼 수 있습니다. pvc를 삭제하려면 kubectl delete pvc 커맨드를 실행하십시오. 하지만 claims이 삭제되면 default persistent volume은 어떻게 되나요? 이 때 volume에 일어날 일을 선택할 수 있습니다. default로는 볼륨을 유지하도록 설정되어 있습니다. persistentVolumeReclaimPolicy: Retain은 관리자가 수동으로 삭제할 때까지 남아 있음을 의미합니다. 다른 claims에서 재사용할 수 없습니다. 또는 persistentVolumeReclaimPolicy: Delete 로 설정하면 claims이 삭제되는 즉시 volume도 삭제됩니다. 따라서 최종 저장 장치의 저장 공간을 확보합니다. 세 번째 옵션은 재활용하는 것입니다. persistentVolumeReclaimPolicy: Recycle로 설정하면, 데이터 volume의 데이터는 다른 claims에서 사용하기 전에 삭제됩니다.

Using PVCs in PODs

PVC를 생성하면 다음과 같이 볼륨 섹션의 persistenceVolumeClaim 섹션 아래에 PVC 클레임 이름을 지정하여 POD 정의 파일에서 PVC를 사용합니다.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

ReplicaSet 또는 Deployment의 경우에도 마찬가지입니다.


테스트 문제 기록

Configure a volume to store these logs at /var/log/webapp on the host. ( node랑 pod 내 container랑 Volume Mount 하기)

apiVersion: v1
kind: Pod
metadata:
  name: webapp
spec:
  containers:
  - name: event-simulator
    image: kodekloud/event-simulator
    env:
    - name: LOG_HANDLERS
      value: file
    volumeMounts:
    - mountPath: /log
      name: log-volume

  volumes:
  - name: log-volume
    hostPath:
      path: /var/log/webapp
      type: Directory

Create a Persistent Volume with the given specification. (Persistent Volume 생성)

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-log
spec:
  persistentVolumeReclaimPolicy: Retain
  accessModes:
    - ReadWriteMany
  capacity:
    storage: 100Mi
  hostPath:
    path: /pv/log

Let us claim some of that storage for our application. Create a Persistent Volume Claim with the given specification. (Persistent Volume Claim 생성)

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: claim-log-1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Mi

Update the webapp pod to use the persistent volume claim as its storage. ( pod 에 pvc 추가 )

apiVersion: v1
kind: Pod
metadata:
  name: webapp
spec:
  containers:
  - name: event-simulator
    image: kodekloud/event-simulator
    env:
    - name: LOG_HANDLERS
      value: file
    volumeMounts:
    - mountPath: /log
      name: log-volume

  volumes:
  - name: log-volume
    persistentVolumeClaim:
      claimName: claim-log-1

테스트 통과 완료

Storage Class

이번 강의에서는 스토리지 클래스에 대해 알아보겠습니다. 이전 강의에서는 PV를 생성하고, PVC를 생성하여 해당 스토리지를 요청한 다음 Pod definition 파일의 PVC를 volume으로 사용하는 방법에 대해 얘기했습니다.

이 경우 Google Cloud persistent disk에서 PVC를 만듭니다.

Static Provisioning

여기서 문제는 이 PV가 생성되기 전에 Google Cloud에 디스크를 생성해야 한다는 것입니다. 애플리케이션에 스토리지가 필요할 때마다 먼저 Google Cloud에서 디스크를 수동으로 프로비저닝한 다음 생성한 디스크와 동일한 이름을 사용하여 persistent volume definition 파일을 수동으로 생성해야 합니다. 이를 static provisioning volume이라고 합니다.

Dynamic Provisioning

애플리케이션이 필요로 할 때 volume이 자동으로 프로비저닝된다면 좋았을 것입니다. 여기서 스토리지 클래스가 필요합니다. 스토리지 클래스를 사용하면 Google Cloud에서 스토리지를 자동으로 프로비저닝하고 claims이 있을 때 파드에 연결할 수 있는 프로비저너(예: Google Storage)를 정의할 수 있습니다. 이를 volume의 동적 프로비저닝이라고 합니다.

API 버전이 storage.k8s.io/v1으로 설정된 스토리지 클래스 오브젝트를 생성하면 됩니다. 이름을 지정하고 프로비저너를 Kubernetes.io/gce-pd로 사용합니다. 저장을 위해 PVC를 사용하는 파드가 있고 PVC가 PV에 바인딩된 원래 상태로 돌아가서 이제 스토리지 클래스가 있으므로 더 이상 PV 정의가 필요하지 않습니다. 스토리지는 스토리지 클래스가 생성될 때 자동으로 생성됩니다. PVC가 우리가 정의한 스토리지 클래스를 사용하려면 PVC 정의에 스토리지 클래스 이름을 지정합니다. 이것이 PVC가 사용할 스토리지 클래스를 아는 방법입니다. 다음에 PVC가 생성되면 이와 연결된 스토리지 클래스는 정의된 프로비저너를 사용하여 GCP에서 필요한 크기의 새 디스크를 프로비저닝한 다음 persistent volume을 생성하고 PVC를 해당 volume에 바인딩합니다. 따라서 여전히 PV를 생성한다는 점을 기억하세요. 더 이상 수동으로 PV를 생성할 필요가 없다는 것입니다. 스토리지 클래스에 의해 자동으로 생성됩니다.

Storage Class

GCE 제공자를 사용하여 GCP에서 volume을 생성했습니다. AWS EBS, Azure File, Azure Disk, CephFS, Portworx, ScaleIO 등과 같은 다른 프로비저너도 많이 있습니다. 이러한 프로비저너 각각을 사용하여 프로비저닝할 디스크 유형, replication 유형 등과 같은 추가 파라미터를 전달할 수 있습니다. 이러한 파라미터는 사용 중인 제공자에 따라 매우 다릅니다. Google Persistent Disk의 경우 표준 또는 SSD일 수 있는 유형을 지정할 수 있습니다. none 혹은 regional PD인 replication 모드를 지정할 수 있습니다. 보시다시피 각각 다른 유형의 디스크를 사용하는 다양한 스토리지 클래스를 생성할 수 있습니다. 예를 들어 표준 디스크가 포함된 실버 스토리지 클래스, SSD 드라이브가 포함된 골드 클래스, SSD 드라이브 및 replication가 포함된 플래티넘 클래스입니다.

이것이 스토리지 클래스라고 불리는 이유입니다. 다양한 서비스 클래스를 생성할 수 있습니다. 다음에 PVC를 생성할 때 volume에 필요한 스토리지 클래스를 간단히 지정할 수 있습니다.


테스트 문제 기록

Let's fix that. Create a new PersistentVolumeClaim by the name of local-pvc that should bind to the volume local-pv.(PersistentVolumeClaim 생성)

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: local-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: local-storage
  resources:
    requests:
      storage: 500Mi

Why is the PVC in a pending state despite making a valid request to claim the volume called local-pv? ( 현재 생성한 pvc가 pending 상태인 이유 )

A Pod consuming the volume is not scheduled
(WaitForFirstConsumer - 볼륨을 사용하는 pod가 없음)

Create a new pod called nginx with the image nginx:alpine. The Pod should make use of the PVC local-pvc and mount the volume at the path /var/www/html. ( 볼륨 사용하는 pod 생성 )

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    volumeMounts:
      - name: local-persistent-storage
        mountPath: /var/www/html
  volumes:
    - name: local-persistent-storage
      persistentVolumeClaim:
        claimName: local-pvc

Create a new Storage Class called delayed-volume-sc that makes use of the below specs:provisioner: kubernetes.io/no-provisioner, volumeBindingMode: WaitForFirstConsumer ( 스토리지 클래스 만들기)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: delayed-volume-sc
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

테스트 통과 완료

업로드중..

profile
Web Developer

0개의 댓글