如何接入 K8s 持久化存储?K8s CSI 实现机制浅析

王成,腾讯云研发工程师,Kubernetes contributor,从事数据库产品容器化、资源管控等工作,关注 Kubernetes、Go、云原生领域。

概述

进入 K8s 的世界,会发现有很多方便扩展的 Interface,包括 CSI, CNI, CRI 等,将这些接口抽象出来,是为了更好的提供开放、扩展、规范等能力。

K8s 持久化存储经历了从 in-tree Volume 到 CSI Plugin(out-of-tree) 的迁移,一方面是为了将 K8s 核心主干代码与 Volume 相关代码解耦,便于更好的维护;另一方面则是为了方便各大云厂商实现统一的接口,提供个性化的云存储能力,以期达到云存储生态圈的开放共赢。

本文将从持久卷 PV 的 创建(Create)、附着(Attach)、分离(Detach)、挂载(Mount)、卸载(Unmount)、删除(Delete) 等核心生命周期,对 CSI 实现机制进行了解析。

相关术语 Term Definition
CSI   Container Storage Interface.  
CNI   Container Network Interface.  
CRI   Container Runtime Interface.  
PV   Persistent Volume.  
PVC   Persistent Volume Claim.  
StorageClass   Defined by provisioner(i.e. Storage Provider), to assemble Volume parameters as a resource object.  
Volume   A unit of storage that will be made available inside of a CO-managed container, via the CSI.  
Block Volume   A volume that will appear as a block device inside the container.  
Mounted Volume   A volume that will be mounted using the specified file system and appear as a directory inside the container.  
CO   Container Orchestration system, communicates with Plugins using CSI service RPCs.  
SP   Storage Provider, the vendor of a CSI plugin implementation.  
RPC   Remote Procedure Call.  
Node   A host where the user workload will be running, uniquely identifiable from the perspective of a Plugin by a node ID.  
Plugin   Aka “plugin implementation”, a gRPC endpoint that implements the CSI Services.  
Plugin Supervisor   Process that governs the lifecycle of a Plugin, MAY be the CO.  
Workload   The atomic unit of "work" scheduled by a CO. This MAY be a container or a collection of containers.  

本文及后续相关文章都基于 K8s v1.22

流程概览

PV 创建核心流程:

apiserver 创建 Pod,根据 PodSpec.Volumes 创建 Volume;

PVController 监听到 PV informer,添加相关 Annotation(如 pv.kubernetes.io/provisioned-by),调谐实现 PVC/PV 的绑定(Bound);

判断 StorageClass.volumeBindingMode:WaitForFirstConsumer 则等待 Pod 调度到 Node 成功后再进行 PV 创建,Immediate 则立即调用 PV 创建逻辑,无需等待 Pod 调度;

external-provisioner 监听到 PV informer, 调用 RPC-CreateVolume 创建 Volume;

AttachDetachController 将已经绑定(Bound) 成功的 PVC/PV,经过 InTreeToCSITranslator 转换器,由 CSIPlugin 内部逻辑实现 VolumeAttachment 资源类型的创建;

external-attacher 监听到 VolumeAttachment informer,调用 RPC-ControllerPublishVolume 实现 AttachVolume;

kubelet reconcile 持续调谐:通过判断 controllerAttachDetachEnabled || PluginIsAttachable 及当前 Volume 状态进行 AttachVolume/MountVolume,最终实现将 Volume 挂载到 Pod 指定目录中,供 Container 使用;

如何接入 K8s 持久化存储?K8s CSI 实现机制浅析

从 CSI 说起

CSI(Container Storage Interface) 是由来自 Kubernetes、Mesos、Docker 等社区 member 联合制定的一个行业标准接口规范(https://github.com/container-storage-interface/spec),旨在将任意存储系统暴露给容器化应用程序。

CSI 规范定义了存储提供商实现 CSI 兼容的 Volume Plugin 的最小操作集和部署建议。CSI 规范的主要焦点是声明 Volume Plugin 必须实现的接口。

先看一下 Volume 的生命周期:

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 | +------------+ The lifecycle of a dynamically provisioned volume, from creation to destruction, when the Node Plugin advertises the STAGE_UNSTAGE_VOLUME capability.

从 Volume 生命周期可以看到,一块持久卷要达到 Pod 可使用状态,需要经历以下阶段:

CreateVolume -> ControllerPublishVolume -> NodeStageVolume -> NodePublishVolume

而当删除 Volume 的时候,会经过如下反向阶段:

NodeUnpublishVolume -> NodeUnstageVolume -> ControllerUnpublishVolume -> DeleteVolume

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgzjdg.html