github编辑

csi-provisioner源码分析

本文主要分析csi-provisioner的源码,关于开发一个Dynamic Provisioner,具体可参考nfs-client-provisioner的源码分析arrow-up-right

1. Dynamic Provisioner

1.1. Provisioner Interface

开发Dynamic Provisioner需要实现Provisionerarrow-up-right接口,该接口有两个方法,分别是:

  • Provision:创建存储资源,并且返回一个PV对象。

  • Delete:移除对应的存储资源,但并没有删除PV对象。

1.2. 开发provisioner的步骤

  1. 写一个provisioner实现Provisioner接口(包含ProvisionDelete的方法)。

  2. 通过该provisioner构建ProvisionController

  3. 执行ProvisionControllerRun方法。

2. CSI Provisioner

CSI Provisioner的源码可参考:https://github.com/kubernetes-csi/external-provisioner。

2.1.1. 读取环境变量

源码如下:

通过init函数解析相关参数,其实provisioner指明为PVC提供PV的provisioner的名字,需要和StorageClass对象中的provisioner字段一致。

2.1.2. 获取clientset对象

源码如下:

通过读取对应的k8s的配置,创建clientset对象,用来执行k8s对应的API,其中主要包括对PV和PVC等对象的创建删除等操作。

2.1.3. k8s版本校验

获取了k8s的版本信息,因为provisioners的功能在k8s 1.5及以上版本才支持。

2.1.4. 连接 csi socket

Provisioner会停留在初始化状态,直到csi socket连接成功才正常运行。如果连接失败,会暂停10秒后重试,其中涉及以下2个参数:

  • csiEndpoint:CSI Volume的gRPC地址,默认通过为/run/csi/socket

  • connectionTimeout:连接CSI driver socket的超时时间,默认为10秒。

2.1.5. 构造csi-Provisioner对象

通过参数clientset, csiAPIClient, csiEndpoint, connectionTimeout, identity, volumeNamePrefix, volumeNameUUIDLength, grpcClient, snapClient构造csi-Provisioner对象。

通过csiProvisioner构造ProvisionController对象。

2.1.6. 运行ProvisionController

ProvisionController实现了具体的PV和PVC的相关逻辑,Run方法以常驻进程的方式运行。

2.2.1. Provision方法

csiProvisionerProvision方法具体源码参考:https://github.com/kubernetes-csi/external-provisioner/blob/master/pkg/controller/controller.go#L336

Provision方法用来创建存储资源,并且返回一个PV对象。其中入参是VolumeOptions,用来指定PV对象的相关属性。

1、构造PV相关属性

2、构造CSIPersistentVolumeSource相关属性

3、创建CSI CreateVolumeRequest

Provison方法核心功能是调用p.csiClient.CreateVolume(ctx, &req)

4、构造PV对象

Provision方法只是通过VolumeOptions参数来构建PV对象,并没有执行具体PV的创建或删除的操作。

不同类型的Provisioner的,一般是PersistentVolumeSource类型和参数不同,例如csi-provisioner对应的PersistentVolumeSourceCSI,并且需要传入CSI相关的参数:

  • Driver

  • VolumeHandle

  • FSType

  • VolumeAttributes

  • ControllerPublishSecretRef

  • NodeStageSecretRef

  • NodePublishSecretRef

2.2.2. Delete方法

csiProvisionerdelete方法具体源码参考:https://github.com/kubernetes-csi/external-provisioner/blob/master/pkg/controller/controller.go#L606

Delete方法主要是调用了p.csiClient.DeleteVolume(ctx, &req)方法。

2.3. 总结

csi provisioner实现了Provisioner接口,其中包含ProvisonDelete两个方法:

  • Provision:调用csiClient.CreateVolume方法,同时构造并返回PV对象。

  • Delete:调用csiClient.DeleteVolume方法。

csi provisioner的核心方法都调用了csi-client相关方法。

3. csi-client

csi client的相关代码参考:https://github.com/container-storage-interface/spec/blob/master/lib/go/csi/v0/csi.pb.go

3.1. 构造csi-client

3.1.1. 构造grpcClient

通过连接csi socket,连接成功才构造可用的grpcClient

3.1.2. 构造csi-client

通过grpcClient构造csi-client

NewCSIProvisioner

NewControllerClientarrow-up-right

3.2. csiClient.CreateVolume

csi provisoner中调用csiClient.CreateVolume代码如下:

CreateVolumeRequest的构造:

具体的Create实现方法如下:

其中csiClient是个接口类型

具体代码参考controllerClient.CreateVolumearrow-up-right

3.3. csiClient.DeleteVolume

csi provisoner中调用csiClient.DeleteVolume代码如下:

DeleteVolumeRequest的构造:

将构造的DeleteVolumeRequest传给DeleteVolume方法。

具体的Delete实现方法如下:

具体代码参考:controllerClient.DeleteVolumearrow-up-right

自定义的provisioner实现了Provisoner接口ProvisionDelete方法,这两个方法主要对后端存储做创建和删除操作,并没有对PV对象进行创建和删除操作。

PV对象的相关操作具体由ProvisionController中的provisionClaimOperationdeleteVolumeOperation具体执行,同时调用了具体provisionerProvisionDelete两个方法来对存储数据做处理。

这块代码逻辑可参考:nfs-client-provisioner 源码分析arrow-up-right

参考文章:

  • https://github.com/kubernetes-csi/external-provisioner

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

  • https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md

  • https://github.com/container-storage-interface/spec/blob/master/spec.md

最后更新于

这有帮助吗?