home..

CSI 표준 알아보기

Kubernetes CSI ContainerStorageInterface EBS EFS PV PVC

Container Storage Interface 톺아보기

출처 : https://www.alibabacloud.com/blog/get-to-know-container-storage-interface-csi_598094

번역본입니다.

CSI 주요 흐름

CSI 및 해당 구성 요소에 대해 자세히 알아보기 전에 먼저 Kubernetes의 CSI Driver의 프로세스를 살펴보겠습니다. 이 글에서는  Kubernetes 영구 스토리지 프로세스 를 알아보기 위해 Kubernetes에 볼륨을 마운트할 때 포드가 거치는 세 가지 단계(프로비저닝 및 삭제, 연결 및 분리, 마운트/마운트 해제)를 설명합니다. 이 섹션에서는 Kubernetes가 세 단계에서 CSI를 사용하는 방법을 설명합니다.

배경

Kubernetes는 iSCSI, NFS, CephFS와 같은 일부 유형의 지속적인 볼륨 (PV)을 원래 저장소로 지원합니다. 여기에는 다음과 같은 문제가 있습니다:

  1. 사용자가 인트리(in-tree) 저장소 코드를 수정하려면 Kubernetes 구성 요소를 업데이트해야 하며, 이는 비용이 많이 듭니다.
  2. 인트리 저장소 코드의 버그는 Kubernetes 구성 요소의 불안정성을 초래할 수 있습니다.
  3. Kubernetes 커뮤니티가 인트리 저장소 코드의 기능을 유지 관리하고 테스트해야 합니다.
  4. 인트리 스토리지 플러그인은 코어 Kubernetes 구성 요소와 동일한 권한을 가지므로 보안 문제가 발생할 수 있습니다.
  5. 제3자 저장소 개발자는 인트리 저장소 코드를 개발하기 위해 Kubernetes 커뮤니티의 규칙을 따라야 합니다.

Container Storage Interface 표준은 이러한 문제를 해결하여 제3자 저장소 개발자가 컨테이너 플랫폼에 신경 쓸 필요 없게 했습니다.

CSI Driver는 쿠버네티스(Kubernetes)의 스토리지 인프라를 표준화하기 위한 플러그인으로, Container Storage Interface(CSI)에 기반을 둡니다. 이를 사용하면 다양한 스토리지 솔루션을 쿠버네티스에 쉽게 통합할 수 있습니다.

  • CSI-Plugin : 이 부분은 볼륨을 마운트(mount)하거나 언마운트(unmount)하는 역할을 합니다 디스크, NAS 파일 시스템과 같은 다양한 타입의 스토리지 미디어를 CSI-Plugin을 통해 마운트할 수 있게 지원합니다.
  • CSI-Provisioner : 이 부분은 자동으로 디스크 볼륨이나 NAS 볼륨을 생성합니다. 즉, 스토리지 요구사항이 있는 쿠버네티스의 워크로드를 실행할 때 필요한 스토리지를 자동으로 준비해줍니다.

쿠버네티스 커뮤니티는 CSI 플러그인을 권장하며, CSI 플러그인은 커뮤니티 버전의 기능과 호환됩니다. 이로 인해 사용자는 다양한 스토리지 옵션을 쉽게 활용할 수 있게 됩니다.

구성요소 설명

다음 과정들을 설명함에 있어 사용되는 단어들이 존재하는 위치와 구성요소(구체적인 컨테이너 위치)에 대한 설명입니다.

(CSI Driver중 NetApp의 Trident CSI Driver 기준으로 작성했습니다)

API Server : Kube Api Server

AD Controller(Attach Detach controller) : kube-controller-manager 내의 attach detach controller

  • csiAttacher또한 AD Controller 내부에서 선언되는 기능

Volume Controller : kube-controller-manager 내의 volume controller

External Attacher : Trident Deployment의 csi-attacher 컨테이너

CSI Plugin :  

  • Trident Daemonset에 있는 CSI Driver 영역. 구체적인 정보는 CSI Sidecar 영역에서 설명을 보충

  • in-tree CSI Plugin : kube-controller-manager의 AttachDetach Controller에 선언된 csi Attacher.

External Provisioner: Trident Daemonset의 csi-provisioner 컨테이너

Untitled

1. Provisioning Volumes

Untitled

  1. 클러스터 관리자는  CSI 플러그인 이름과 필수 label(프로비저닝 볼륨 유형)이 포함된 StorageClass를 생성합니다. 
  2. 사용자는 PersistentVolumeClaim 생성할 때, 스토리지 크기와 StorageClass를 PVC에 지정합니다.
  3. PersistentVolumeController는 out-of-tree(CSI) 스토리지 유형에 대응하는 새로운 PVC를 찾지 못하므로, PVC에 volume.beta.kubernetes.io/storage-provisioner=[외부 CSI 플러그인 이름] 주석을 추가 해줍니다.
  4. External Provisioner는 PVC의 주석을 검사해 ‘volume.beta.kubernetes.io/storage-provisioner’ 항목이 있는지 확인합니다. 이 항목이 있다면 볼륨을 프로비저닝합니다.”
    • 해당 StorageClass와 설정 값(label)을 참조합니다.
    • CSI 플러그인의 ‘CreateVolume’ 함수를 Unix 도메인 소켓을 통해 호출합니다.
  5. CSI 플러그인의 호출이 성공적으로 완료되면, 볼륨이 생성됩니다. 이후 External Provisioner는 클러스터 내에 PersistentVolume을 생성합니다.
  6. PersistentVolumeController 는  PV와 PVC를 바인딩합니다.

2. Attaching Volumes

Untitled

  1. AttachDetachController는 Pod가 CSI 유형의 PersistentVolume을 사용하여 노드에 스케링된 것을 확인하여 Attach 함수를 호출합니다.
  2. AD Controller(csiAttacher)는 클러스터 내에 VolumeAttachment 오브젝트를 생성합니다.
  3. External Attacher는 VolumeAttachment 오브젝트를 확인하고 CSI 플러그인의 ControllerPublish 함수를 호출하여 볼륨을 해당 노드에 연결합니다. 연결이 성공하면, External Attacher는 VolumeAttachment의 상태(Status.Attached)를 ‘true’로 변경합니다.
  4. AD Controller의 CSI 플러그인(csiAttacher)은 VolumeAttachment의 상태가 ‘true’로 설정되면, 이를 바탕으로 Node의 상태 정보를 업데이트합니다

3. Mounting Volumes

Untitled

1) Volume Manager (Kubelet 컴포넌트)는 현재 노드에 스케쥴된 새로운 Pod가 CSI 볼륨을 사용하는 것을 인지하고, AttachDetach Controller(csiAttacher)의 WaitForAttach 함수를 호출합니다.

2) AD Controller(csiAttacher)은 클러스터 내의 VolumeAttachment 객체의 .Status.Attached 상태가 true로 변경될 때까지 대기합니다.

3) AD Controller(csiAttacher)은 MountDevice 함수를 호출하며, 이 함수는 UNIX 도메인 소켓을 통해 CSI 플러그인의 NodeStageVolume 함수를 호출합니다.

그 후, AD Controller(csiAttacher)은 AD Controller(csiMountMgr)의 SetUp 함수를 호출합니다. 이 SetUp 함수는 UNIX 도메인 소켓을 통해 CSI 플러그인의 NodePublishVolume 함수를 호출합니다.

4. Unmounting Volume

Untitled

  1. 사용자가 Pod를 삭제합니다.
  2. Volume Manager(Kubelet)가 CSI 스토리지 볼륨을 사용하는 Pod의 삭제를 감지하고, AD Controller의 TearDown 함수를 호출하여 Unix 도메인 소켓을 통해 CSI 플러그인의 NodeUnpublishVolume 함수를 실행합니다
  3. Volume Manager(Kubelet)는 AD Controller의 UnmountDevice 함수를 호출하여, 이를 통해 Unix 도메인 소켓을 통해 CSI 플러그인의 NodeUnpublishVolume 함수를 실행합니다

5. Detaching Volumes

Untitled

  1. AttachDetachController는 CSI 스토리지 볼륨을 포함된 Pod가 삭제되었다는 것을 인지하고, Detach 함수를 호출합니다.
  2. AD Controller(csiAttacher)는 클러스터 내의 VolumeAttachment 객체를 삭제합니다. 하지만 finalizer 때문에 바로 삭제되지 않습니다.
  3. External Attacher는 클러스터 내의 VolumeAttachment 객체의 DeletionTimestamp 필드가 비어있지 않다는 것을 인지하여 CSI 플러그인의 ControllerUnpublish 함수를 호출하여 해당 볼륨을 노드에서 제거합니다.
  4. 볼륨이 CSI 플러그인에 의해 제거된 후, External Attacher는 VolumeAttachment 객체의 finalizer 필드를 제거합니다. 이 때 VolumeAttachment 객체는 완전히 삭제됩니다.
  5. AD Controller의 csiAttacher는 VolumeAttachment 객체가 삭제되었다는 것을 인지하고 AD Controller의 내부 상태를 업데이트합니다.
  6. 동시에, AD Controller는 노드를 업데이트합니다. 이제 노드의 .Status.VolumesAttached 에는 마운트된 볼륨이 표시되지 않습니다.

6. Deleting Volumes

Untitled

  1. 사용자는 관련된 PVC를 삭제합니다.
  2. External Provisioner 컴포넌트는 PVC가 삭제되었다는 것을 확인하여 PVC의 회수 정책에 따라 다른 작업을 수행합니다:

    • 삭제(Delete): CSI 플러그인의 DeleteVolume 함수를 호출하여 볼륨을 삭제합니다. 볼륨이 성공적으로 삭제되면 Provisioner는 클러스터 내의 해당 PV를 삭제합니다.

    • 유지(Retain): Provisioner는 볼륨을 삭제하지 않습니다.

CSI 사이드카 구성요소

Kubernetes가 CSI 표준에 적응할 수 있도록 커뮤니티에서는 Kubernetes와 관련된 스토리지 로직을 CSI Sidecar 구성 요소에 통합했습니다.

1) Node-Driver-Registrar

1.1) 기능

Node-Driver-Registrar 는 CSI 플러그인을 Kubelet에 등록하여 Kubelet은 특정 Unix 도메인 소켓을 통해 CSI 플러그인 함수(여기에는 NodeGetInfo, NodeStageVolume, NodePublishVolume, NodeGetVolumeStats가 포함됩니다)를 호출할 수 있습니다.

1.2) 원리

Node-Driver-Registrar가  CSI 플러그인을 Kubelet에 성공적으로 등록한 후 :

  • 노드에 주석 달기: Kubelet은 CSI 플러그인의 NodeGetInfo 함수를 호출합니다. 이 함수의 반환 값인 [nodeID]와 [driverName]은 “csi.volume.kubernetes.io/nodeid” 키에 사용됩니다.
  • 노드 라벨 업데이트: NodeGetInfo 함수가 반환한 [AccessibleTopology] 값을 노드의 라벨(Label)로 사용합니다.
  • 노드 상태 업데이트: NodeGetInfo 함수가 반환한 maxAttachLimit(마운트할 수 있는 볼륨의 최대 수)을 노드의 Status.Allocatable에 업데이트합니다. 이 매개변수의 값은 attachable-volumes-csi-[driverName]=[maxAttachLimit]입니다.
  • CSINode 업데이트(없을 경우 생성): Kubelet은 [driverName], [nodeID], [maxAttachLimit], [AccessibleTopology]와 같은 정보를 CSINode의 Spec에 업데이트합니다. 이때, 토폴로지에 대한 키 값만을 유지합니다.

2) External Provisioner

2.1) 기능

실제 볼륨과 볼륨을 나타내는 PV를 생성하거나 삭제합니다.

2.2) 원리

External-Provisioner를 활성화하기 위해 provisioner 파라미터를 반드시 지정해야 합니다. 이 이름은 StorageClass의 provisioner 필드와 일치해야 합니다.

활성화된 후에 External-Provisioner는 클러스터 내의 PVC와 PV를 모니터링합니다.

클러스터 내의 PVC에 대하여:

  • 다음 기준을 사용하여 PVC가 동적으로 볼륨을 생성해야 하는지 결정합니다:
    1. PVC의 어노테이션에 volume.beta.kubernetes.io/storage-provisioner 키가 있는지 (PersistentVolumeController에 의해 생성됨) 그리고 그 값이 Provisioner 이름과 같은지 확인합니다.
    2. PVC에 대응하는 StorageClass의 VolumeBindingMode 필드가 WaitForFirstConsumer 인 경우, PVC의 어노테이션은 volume.kubernetes.io/selected-node 키를 포함해야 하며 그 값이 null이 아니어야 합니다. 만약 값이 Immediate 라면, Provisioner는 즉시 동적 스토리지 볼륨을 제공해야 합니다.
  • 특정 UNIX 도메인 소켓을 통해 CSI 플러그인의 CreateVolume 함수를 호출합니다.
  • PV를 생성합니다. PV의 이름은 [Provisioner가 지정한 PV 접두사] - [PVC uuid] 로 설정됩니다.

클러스터 내의 PV에 대하여:

  • 다음 기준을 사용하여 PV가 삭제되어야 하는지 결정합니다:
    1. .Status.PhaseRelease 인지 확인합니다.
    2. .Spec.PersistentVolumeReclaimPolicyDelete 인지 확인합니다.
    3. PV에 어노테이션 ( pv.kubernetes.io/provisioned-by )이 포함되어 있고 그 값이 자기 자신인지 확인합니다.
  • 특정 UNIX 도메인 소켓을 통해 CSI 플러그인의 DeleteVolume 인터페이스를 호출합니다.
  • 클러스터 내에서 PV를 삭제합니다.

3) External Attacher

3.1) 기능

주로 볼륨을 연결하거나 분리하는 데 사용됩니다.

3.2) 원리

External-Attacher는 클러스터 내의 VolumeAttachment와 PersistentVolume을 항상 내부적으로 모니터링합니다.

VolumeAttachment에 대해서:

  • VolumeAttachment에서 모든 PV 정보를 얻습니다. 이에는 볼륨 ID, 노드 ID, 그리고 마운트 시크릿이 포함됩니다.
  • VolumeAttachment의 DeletionTimestamp 필드를 기준으로 볼륨이 연결되는 중인지 또는 분리되는 중인지 결정합니다. 볼륨이 연결 중이라면 특정 유닉스 도메인 소켓을 통해 CSI 플러그인의 ControllerPublishVolume 인터페이스를 호출합니다; 볼륨이 분리 중이라면 ControllerUnpublishVolume 인터페이스를 호출합니다.

PersistentVolume에 대해서:

  • 연결 중인 상태에서 관련 PV에 Finalizer 라벨을 붙입니다: external-attacher/[드라이버 이름] .
  • PV가 삭제된 경우 (즉, DeletionTimestamp 필드가 null이 아니면), Finalizer를 삭제합니다: external-attacher/[드라이버 이름] .

4) External Resizer

4.1) 기능

주로 저장 볼륨의 크기를 조정하는 데 사용됩니다.

4.2) 원리

External-Resizer는 클러스터 내의 PersistentVolumeClaim을 내부적으로 모니터링합니다.

PersistentVolumeClaim의 경우

  • PersistentVolumeClaim이 확장되어야 하는지 확인합니다: PVC의 상태는 Bound.Status.Capacity이어야 하며, .Spec.Resources.Requests 는 서로 동일하지 않아야 합니다.
  • PVC의 .Status.Conditions 을 업데이트하여 리사이즈 상태를 표시합니다.
  • 특정 UNIX 도메인 소켓을 통해 CSI 플러그인의 ControllerExpandVolume 인터페이스를 호출합니다.
  • PV의 .Spec.Capacity 를 업데이트합니다.
  • 만약 CSI가 파일 시스템의 온라인 리사이징을 지원한다면, ControllerExpandVolume 인터페이스의 반환 값에서 NodeExpansionRequired 필드는 true입니다. 그러면 External-Resizer는 PVC의 .Status.ConditionsFileSystemResizePending 상태로 업데이트합니다. 그렇지 않다면, 리사이징 작업은 성공적으로 완료됩니다. 그 후, External-Resizer는 PVC의 .Status.Conditions 을 null로 설정하고 동시에 .Status.Capacity 를 업데이트합니다.

Volume Manager (Kubelet 컴포넌트)는 볼륨이 온라인으로 크기를 조정해야 한다고 인식합니다. 특정 UNIX 도메인 소켓을 통해 CSI 플러그인의 NodeExpandVolume 인터페이스를 호출하여 파일 시스템의 리사이징을 진행합니다.

요약

Container Storage Interface의 핵심 프로세스에 대한 일반적인 소개와 함께 사이드카의 구성요소, API 의 관점에서 CSI의 표준 인터페이스를 분석해 각 CSI Driver들이 어떤 방식으로 동작하는지 이해하는데 도움이 되었으면 합니다.

출처:

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

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

https://github.com/kubernetes/kubernetes/blob/master/pkg/volume/csi/csi_attacher.go#L48

https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/volume-attachment-v1/

https://kubernetes.io/ko/docs/concepts/storage/persistent-volumes/

https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/

Introduction - Kubernetes CSI Developer Documentation

© 2024 mont kim   •  Powered by Soopr   •  Theme  Moonwalk