kubernetes CSI Driver
By Bys on July 30, 2024
Kubernetes Volume
Container Storage Interface(CSI)
Storage Provider가 플러그인을 한 번만 개발하면 여러 Container Orchestration에서 동작할 수 있도록 하는 표준 Container Storage Interface에 대한 정의
- 용어
- CO -
Container Orchestration
system. - SP -
Storage Provider
, the vendor of a CSI plugin implementation. - Plugin - Aka “plugin implementation”, a gRPC endpoint that
implements the CSI Services
. - Volume -
A unit of storage
that will be made available inside of a CO-managed container, via the CSI.
- CO -
- 목표
- CSI를 구현하는 모든 CO에서 “그냥 작동하는(just works)” 하나의 CSI 호환 플러그인을 SP 작성자가 작성할 수 있도록 합니다.
- Define API (RPCs) that enable
- Dynamic
provisioning
anddeprovisioning
of a volume Attaching
ordetaching
a volume from a nodeMounting/unmounting
a volume from a node- Consumption of both
block and mountable volumes
Local storage providers
(e.g., device mapper, lvm)- Creating and deleting a
snapshot
(source of the snapshot is a volume) Provisioning
a new volumefrom a snapshot
- Dynamic
A CO interacts with an Plugin through RPCs. Each SP MUST provide:
- Controller Plugin: 어디에서나 실행될 수 있는 CSI RPC를 제공하는 gRPC 엔드포인트. 즉, 컨트롤러는 쿠버네티스 컨테이너에서 사용할 볼륨을 스토리지 서버에서 생성 및 삭제하는 걸 담당한다.
A gRPC endpoint serving CSI RPCs that MAY be run anywhere.
- Node Plugin: SP 프로비저닝 볼륨이 publish 되는 노드에서 반드시 실행되어야 하는 CSI RPC를 제공하는 gRPC 엔드포인트. 즉, 노드서버는 파드가 배포될 노드에서 스토리지 볼륨에 마운트할 수 있게 환경을 만드는 걸 담당한다.
A gRPC endpoint serving CSI RPCs that MUST be run on the Node whereupon an SP-provisioned volume will be published.
How to work
- external-provisioner(csi-provisioner)
- CSI external-provisioner 컨테이너는 PersistentVolumeClaim 리소스를 Watch 한다.
- PersistentVolume 리소스가 생성되면 CreateVolume API를 호출한다.
- Volume이 정상적으로 생성되면 Kubernetes PersistentVolume 리소스를 생성한다.
- PV의 기본 ReclaimPolicy는 Delete이며 PersistentVolumeClaim 리소스를 삭제하면 csi-provisioner는 PV를 삭제한다.
- external-attacher(csi-attacher)
- CSI external-attacher 컨테이너는 VolumeAttachment 리소스를 Watch 한다.
- VolumeAttachment 리소스가 생성/삭제 되면
ControllerPublish
/ControllerUnpublish
API를 호출하여 노드에 대한 Volume Attach/Detach 를 수행한다.- 쿠버네티스에서 attach 용어는 3rd party 볼륨을 노드에 attachment 하는 것을 의미한다. 클라우드 환경에서 노드에서 코드를 실행하지 않고도 클라우드 API가 노드에 볼륨을 첨부할 수 있는 것은 일반적입니다. CSI 용어로 이것은
ControllerPublish
호출에 해당한다. - Detach는 역순으로 동작하며 노드에서 볼륨을 Detach 하는 것을 의미한다. CSI 용어로
ControllerUnpublish
호출에 해당한다. - 노드에서 실행되는 코드가 수행하는 Attach/Detach 작업(예: iSCSI 또는 파이버 채널 볼륨 연결)이 아니다. 이러한 작업은 일반적으로
NodeStage
및NodeUnstage
CSI 호출 중에 수행되며 external-attacher 가 수행하지 않는다.
- 쿠버네티스에서 attach 용어는 3rd party 볼륨을 노드에 attachment 하는 것을 의미한다. 클라우드 환경에서 노드에서 코드를 실행하지 않고도 클라우드 API가 노드에 볼륨을 첨부할 수 있는 것은 일반적입니다. CSI 용어로 이것은
- Attach/Deatch Controller
- 파드가 노드에 스케쥴링 되는 것을 Watch 한다.
- 볼륨이 필요한 파드가 노드에 스케쥴링 되면 VolumeAttachment 리소스를 생성한다.
- node-driver-registrar(csi-driver-registrar)
- CSI node-driver-registrar 는 NodeGetInfo API를 통해 CSI endpoint 로 부터 driver 정보를 가져와 노드의 kubelet에 등록하는 사이드카 컨테이너이며, kubelet 플러그인 등록 메커니즘을 사용하여 노드에 등록한다.
Device Plugins 장치 공급업체는 쿠버네티스 자체에 대한 코드를 사용자 정의하는 대신 수동으로 또는 데몬셋으로 배포하는 디바이스 플러그인을 구현할 수 있습니다. 대상 장치에는 GPU, 고성능 NIC, FPGA, InfiniBand 어댑터 및 공급업체별 초기화 및 설정이 필요할 수 있는 기타 유사한 컴퓨팅 리소스가 포함됩니다.
service Registration { rpc Register(RegisterRequest) returns (Empty) {} }
장치 플러그인은 이 gRPC 서비스를 통해 kubelet에 자신을 등록할 수 있습니다. 등록에 성공하면, 장치 플러그인은 관리하는 장치 목록을 kubelet에 전송하고, 그러면 kubelet은 kubelet 노드 상태 업데이트의 일부로 해당 리소스를 API 서버에 알리는 작업을 담당합니다.
- Kubelet은 CSI 드라이버에 대해 CSI
NodeGetInfo
,NodeStageVolume
,NodePublishVolume
호출을 직접 실행한다.- Kubelet directly issues CSI
NodeGetInfo
,NodeStageVolume
, andNodePublishVolume
calls against CSI drivers.
- Kubelet directly issues CSI
NodeStageVolume
은 디스크를 파티션 및 포맷하고 노드의 global directory에 마운트 하는 데 사용됩니다.NodePublishVolume
은 global directory를 컨테이너 디렉토리에 마운트하기 위해 사용합니다.NodePublishVolume
vsNodeStageVolume
- 결론적으로
ControllerPublishVolume
에 의해서 볼륨이 노드에 Attach 되고,NodeStageVolume
에 의해서 노드의 global directory에 의해 마운트되며(Mount a device to a path),NodePublishVolume
에 의해 global directory가 container directory로 마운트 된다(Bind mount: mount a path to a different path (instead of mounting a device to a path)).
CreateVolume +------------+ DeleteVolume +------------->| CREATED +--------------+ | +---+----^---+ | | Controller | | Controller v +++ Publish | | Unpublish +++ |X| Volume | | Volume | | +-+ +---v----+---+ +-+ | NODE_READY | +---+----^---+ Node | | Node Stage | | Unstage Volume | | Volume +---v----+---+ | VOL_READY | +---+----^---+ Node | | Node Publish | | Unpublish Volume | | Volume +---v----+---+ | PUBLISHED | +------------+ ####################################### $ mount ...... /dev/nvme1n1 on /var/lib/kubelet/plugins/kubernetes.io/csi/ebs.csi.aws.com/4db2ca9d899c4423fec9632a48d0b5e7eca83a3a8661f0603e466bf62e31f809/globalmount type ext4 (rw,relatime) /dev/nvme1n1 on /var/lib/kubelet/pods/46afeb2c-fcd8-4abc-837b-47e8cfbc64af/volumes/kubernetes.io~csi/pvc-666a79ae-5375-44cb-bc97-e6d9d6d2bdfe/mount type ext4 (rw,relatime)
- CSI node-driver-registrar 는 NodeGetInfo API를 통해 CSI endpoint 로 부터 driver 정보를 가져와 노드의 kubelet에 등록하는 사이드카 컨테이너이며, kubelet 플러그인 등록 메커니즘을 사용하여 노드에 등록한다.
- snapshot-controller, external-snapshotter(csi-snapshotter),
- Snapshot-controller 는 VolumeSnapshots 리소스를 Watch 한다.
- Snapshot-controller 는 VolumeSnapshots 리소스가 생성되면 VolumeSnapshotContents 리소스를 생성한다.
- csi-snapshotter는 VolumeSnapshotContents 리소스를 Watch 한다.
- csi-snapshotter는 VolumeSnapshotContents 리소스가 생성되면 CreateSnapshot API를 호출한다.
- 사용자는 PersistentVolumeClaim 리소스를 생성할 때 datasource로 Snapshot을 사용하여 PVC를 생성할 수 있다.
EBS/EFS CSI Driver의 구성요소
## EFS CSI Controller
- efs-plugin
- csi-provisioner
- liveness-probe
## EFS CSI Node
- efs-plugin
- csi-driver-registrar
- liveness-probe
## EBS CSI Controller
- ebs-plugin
- csi-provisioner
- csi-attacher
- csi-resizer
- liveness-probe
- csi-snapshotter (CSI Snapshot controller와 같이 사용, Addon 설치)
## EBS CSI Node
- ebs-plugin
- node-driver-registrar
- liveness-probe
CSI Volume Plugins in Kubernetes Design Doc
[Leader & Lease]
Leader 선출에 의해 동작하는 애플리케이션은 lease 오브젝트를 가지고 있다.
# Lease objects
$ kubectl get leases -A
NAMESPACE NAME HOLDER AGE
......
kube-system ebs-csi-aws-com 1725345475903-4152-ebs-csi-aws-com 664d
kube-system efs-csi-aws-com 1725345522671-8163-efs-csi-aws-com 648d
......
# Describe leases
$ kubectl describe lease ebs-csi-aws-com -n kube-system
Name: ebs-csi-aws-com
Namespace: kube-system
Labels: <none>
Annotations: <none>
API Version: coordination.k8s.io/v1
Kind: Lease
Metadata:
Creation Timestamp: 2022-11-09T02:12:09Z
Resource Version: 380944711
UID: e8e8f63a-8556-408b-a1f2-628bdd3e2ca6
Spec:
Acquire Time: 2024-09-03T06:39:03.304069Z
Holder Identity: 1725345475903-4152-ebs-csi-aws-com
Lease Duration Seconds: 15
Lease Transitions: 130
Renew Time: 2024-09-04T01:41:37.828660Z
Events: <none>
# Describe Rolebinding
$ kubectl describe rolebinding ebs-csi-leases-rolebinding -n kube-system
Name: ebs-csi-leases-rolebinding
Labels: app.kubernetes.io/component=csi-driver
app.kubernetes.io/managed-by=EKS
app.kubernetes.io/name=aws-ebs-csi-driver
app.kubernetes.io/version=1.34.0
Annotations: <none>
Role:
Kind: Role
Name: ebs-csi-leases-role
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount ebs-csi-controller-sa kube-system
# Describe Role
$ kubectl describe role ebs-csi-leases-role -n kube-system
Name: ebs-csi-leases-role
Labels: app.kubernetes.io/component=csi-driver
app.kubernetes.io/managed-by=EKS
app.kubernetes.io/name=aws-ebs-csi-driver
app.kubernetes.io/version=1.34.0
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
leases.coordination.k8s.io [] [] [get watch list delete update create]
Lease 오브젝트를 업데이트하는 주체는 리더다.
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "6b69f448-d54b-4c91-aee7-8adb4bca75ce",
"stage": "ResponseComplete",
"requestURI": "/apis/coordination.k8s.io/v1/namespaces/kube-system/leases/ebs-csi-aws-com",
"verb": "update",
"user": {
"username": "system:serviceaccount:kube-system:ebs-csi-controller-sa",
"uid": "04b51e47-d1db-4c65-a501-7a6eb6a6772a",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:kube-system",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"JTI=c5d82535-2f29-40ec-8b93-47b5d997ef41"
],
"authentication.kubernetes.io/node-name": [
"ip-10-20-129-248.ap-northeast-2.compute.internal"
],
"authentication.kubernetes.io/node-uid": [
"79f64dda-e2a8-4fa4-9ccf-b89c1d586f03"
],
"authentication.kubernetes.io/pod-name": [
"ebs-csi-controller-67988b76d8-f46gv"
],
"authentication.kubernetes.io/pod-uid": [
"d703f4ee-8654-416c-ad8d-73b918c2980f"
]
}
},
"sourceIPs": [
"10.20.130.198"
],
"userAgent": "csi-provisioner/v0.0.0 (linux/amd64) kubernetes/$Format",
}
Lease 오브젝트를 주기적으로 업데이트하여 리더의 health를 확인하고 만약 리더가 health 체크를 하지 못하는 경우 새로운 리더를 선출한다.
Leader가 아닌 파드의 로그
$ kubectl logs -f ebs-csi-controller-67988b76d8-ptmzv -c ebs-plugin -n kube-system
I0903 06:38:44.006320 1 leaderelection.go:250] attempting to acquire leader lease kube-system/ebs-csi-aws-com...
References
- CSI Spec - https://github.com/container-storage-interface/spec/blob/master/spec.md#rpc-interface
- CSI external-provisioner - https://kubernetes-csi.github.io/docs/external-provisioner.html#csi-external-provisioner
- CSI external-attacher - https://kubernetes-csi.github.io/docs/external-attacher.html#csi-external-attacher
- Plugin Registration Service - https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/pluginmanager/pluginwatcher/README.md
- device-plugin-registration - https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/#device-plugin-registration
- Plugin Registration Service - https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/pluginmanager/pluginwatcher/README.md
- How to write a Container Storage Interface (CSI) plugin - https://arslan.io/2018/06/21/how-to-write-a-container-storage-interface-csi-plugin/
- Leader - https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/design.md#restarts
kubernetes
node
]