容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力

容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力_第1张图片


容器化RDS系列文章:
  • 容器化RDS:计算存储分离架构下的“Split-Brain”

  • 容器化RDS:计算存储分离还是本地存储?

  • 容器化RDS:你需要了解数据是如何被写"坏"的

  • 容器化RDS:PersistentLocalVolumes和VolumeScheduling


RDS 并不是新生事物,新鲜的是通过容器技术和容器编排技术构建 RDS。对金融客户而言,他们有强烈拥抱 Docker 和 Kubernetes 的愿望,但可用性是尝试新技术的前提。存储是持久化应用的关键资源,它并不性感,却是 Monolithic 应用走向 Cloud-Native 架构的关键。Kubernetes 存储子系统已经非常强大,但是还欠缺一些基础功能,譬如支持 Expand Volume(部分 Storage Vendor 支持)和 SnapShot。本文尝试从我们的实现分享如下几个内容:
  • 现有 Kubernetes 存储插件系统问题

  • Container Storage Interface(CSI)

  • 基于CSI 和分布式文件系统实现在 MySQL 的 Volume 动态扩展

  • 对 CSI 的展望


名词说明:
原名 简称
容器编排系统 CO.
存储提供者 SP.
存储插件接口 Volume Plugin Interface
存储驱动 Volume Driver

容器存储接口

Container Storage Interface

CSI

如有遗漏,不吝赐教。

现有 Kubernetes 存储插件系统问题

640


可供选的容器编排系统(后面简称 CO.)不少,除去 Kubernetes 还有 Mesos、Swarm、Cloud Foundry。以 Kubernetes 为例,其通过 PersistentVolume 抽象对以下存储的支持:
  • GCEPersistentDisk

  • AWSElasticBlockStore

  • AzureFile

  • AzureDisk

  • FC(Fibre Channel)**

  • FlexVolume

  • Flocker

  • NFS

  • iSCSI

  • RBD(Ceph Block Device)

  • CephFS

  • Cinder(OpenStack block storage)

  • GlusterFS

  • VsphereVolume

  • Quobyte Volumes

  • HostPath

  • VMware Photon

  • Portworx Volumes

  • ScaleIO Volumes

  • StorageOS


不可谓不丰富。Kubernetes 以插件化的方式支持存储厂商(后面简称 SP.)。SP. 通过实现 Kubernetes 存储插件接口(后面简称 Volume Plugin Interface)的方式提供自己的存储驱动(后面简称 Volume Driver)。
  • VolumePlugin

  • PersistentVolumePlugin

  • DeletableVolumePlugin

  • ProvisionableVolumePlugin

  • ExpandableVolumePlugin

  • Provisioner

  • Deleter


以上接口并不需要全部实现,其中 VolumePlugin[1] 是必须实现的接口。
系统架构图如下:

容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力_第2张图片


这种方式为 Kubernetes 提供了丰富的存储支持列表,但是在具体实现上,SP. Volume Driver 代码也在 Kubernetes 代码仓库(又叫in-tree),它带来几个显著的问题。
从 Kubernetes 的角度看:
  • 需要在 Kubernetes 中给各个 SP. 赋权以便他们能够提交代码到仓库;

  • Volume Driver 由各个 SP. 提供,Kubernetes 的开发者并不了解每个细节,导致这些代码难于维护和测试;

  • Kubernetes 的发布节奏和各位 SP. Volume Driver 的节奏并不一致,随着支持的 SP. 增多,沟通、维护、测试成本会越来越高;

  • 这些 SP. Volume Driver 并不是 Kubernetes 本身需要的。


从 SP. 的角度看:
  • 提交一个新特性或者修复 bug,都需要提交代码到 Kubernetes 仓库,在本地编译 Kubernetes 的都知道,这个过程是很痛苦的,这对 SP. 而言是完全不必要的成本。


一个统一的,大家认可的容器存储接口越来越有必要。

Container Storage Interface(CSI)

640


基于这些问题和挑战,CO 厂商提出 Container Storage Interface 用来定义容器存储标准,它独立于 Kubernetes Storage SIG,由 Kubernetes、Mesos、Cloud Foundry 三家一起推动。个人理解它有如下2个核心目标:
  • 提供统一的 CO. 和 SP. 都遵循的容器存储接口。

  • 一旦 SP. 基于 CSI 实现了自身的 Volume Driver,即可在所有支持 CSI 的 CO 中平滑迁移。


Note:Container Storage Interface 定义[2]。
还有一个附带的好处是,一旦 CO. 和 SP. 都遵循 CSI,就便于将 Volume Driver 解耦到 Kubernetes 的外部(又叫 out-of-tree)。Kubernetes 只用维护 CSI 接口,不用再维护 SP. 的具体实现,维护成本大大降低。
CSI 优化下的架构图:

容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力_第3张图片


可以看到,Kubernetes 和 SP. 从此泾渭分明,但事情并没有那么简单,借用一位大神说的:The performance improvement does not materialize from the air, it comes with code complexity increase.和性能一样,扩展性和解耦也不是凭空出现。上图可进一步细化成下图:

容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力_第4张图片


明显的变化有:
  • Controller Plane、Kubelet 不再直接与 Volume Driver 交互,引入 external-provisioner 和 external-attacher 完成该工作;

  • SP. Volume Driver 会由独立的容器运行;

  • 为了实现 external-provisioner、external-attacher 和 SP. Volume Driver 的交互引入 gRPC 协议(标红箭头)。


还有一些其他的变化:
  • 在 Kubernetes 端 引入新的对象:


    CSIPersistentVolumeSource:该类型 PV 由 CSI Driver 提供

    VolumeAttachment:同步 Attach 和 Dettach 信息


  • 引入新的名称:


    mount/umount:NodePublishVolume/NodeUnpublishVolume

    attach/dettach:ControllerPublishVolume/ControllerUnpublishVolume


Note:Kubernetes 适配 CSI 设计文档[3]。
可见,为了达到这个目标,相比原来复杂不少,但收益巨大,Kubernetes 和 SP. 的开发者可以专注于自身的业务。
即便如此,在现有的 CSI 上做扩展有时也在所难免。

基于 CSI 和分布式文件系统实现在 MySQL 上的 Dynamically Expand Volume

640


Kubernetes 存储子系统已经非常强大,但是还欠缺一些基础功能,譬如支持 Expand Volume (部分 Storage Vendor 支持)和 SnapShot,尤其是 Expand Volume,这是必须的功能,因为随着业务的变化,容量的增加在所难免,一旦容量接近阈值,若以迁库的方式扩展存储容量,成本太高。
但现状并不乐观,Kubernetes 1.10.2 使用 CSI 0.2.0,其并不包含 Expand Volume 接口,这意味着即便底层的存储支持扩容,Kubernetes 也无法使用该功能,所以我们需要做点 hard code 实现该功能:
  • 扩展 CSI Spec

  • 扩展 CSI Plugin

  • 基于 CSI Spec 实现 Storage Driver

  • 演示

  • 其他


扩展 CSI Spec
前面提到,在 CSI 中引入了 gRPC,个人理解在 CSI 的场景有如下3个优点:
  • 基于 protobuf 定义强类型结构,便于阅读和理解

  • 通过 stub 实现远程调用,编程逻辑更清晰

  • 支持双工和流式,提供双向交互和实时交互


网络上介绍 gRPC 和 protobuf 的文章很多,这里不赘述。
通过 gRPC,实现 CSI 各个组件的交互。为支持 expand volume 接口,需要修改 csi.proto,在 CSI 0.2.0 的基础上添加需要的 rpc,重点如下:
service Controller {
rpc CreateVolume (CreateVolumeRequest)
  returns (CreateVolumeResponse)
{}
……
rpc RequiresFSResize (RequiresFSResizeRequest)
  returns (RequiresFSResizeResponse)
{}
rpc ControllerResizeVolume (ControllerResizeVolumeRequest)
  returns (ControllerResizeVolumeResponse)
{}
}
service Node { rpc NodeStageVolume (NodeStageVolumeRequest)
  returns (NodeStageVolumeResponse)
{}
……
rpc NodeResizeVolume (NodeResizeVolumeRequest)
  returns (NodeResizeVolumeResponse)
{}
}

原 csi.proto[4] 和设计文档[5]。
通过 CSI 提供的编译功能,用新编译出来的 csi.pb.go 替换 external-provisioner、external-attacher、csi-driver 和 kubernetes 中现有的 csi.pb.go。
Note:CSI 编译时默认使用最新版本的 protobuf 第三方包,这可能会导致 csi.pb.go 跟 Kubernetes 中依赖的 protobuf 第三方包不兼容,编译时需要切换到统一版本。
扩展 CSI Plugin
在现有 CSI Plugin 基础上,实现接口 ExpandableVolumePlugin:
type ExpandableVolumePlugin interface {
VolumePlugin
ExpandVolumeDevice(spec *Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error)
RequiresFSResize() bool
}

仿照 csiMountMgr 的方式调用 CSI Driver 中的 ControllerResizeVolume。
基于 CSI Spec 实现 Storage Driver
  • CSI Driver 实现如下所有接口:

  • CreateVolume

  • DeleteVolume

  • ControllerPublishVolume

  • ControllerUnpublishVolume

  • ValidateVolumeCapabilities

  • ListVolumes

  • GetCapacity

  • ControllerGetCapabilities

  • RequiresFSResize

  • ControllerResizeVolume


这里涉及到比较复杂的调试和适配工作,还有一些其他的工作:
  • 定义 CSI 对应的 StorageClass,并设置 allowVolumeExpansion 为 true

  • 启用 Feature Gates:ExpandPersistentVolumes

  • 新增 Admission Control:PersistentVolumeClaimResize

  • ……


演示

容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力_第5张图片


通过扩展 Container Storage Interface 0.2.0,我们在Kubernetes 1.10.2 上实现了在线扩容文件系统扩容。对 MySQL 实例制造两种类型工作负载:
  • 通过键值更新和查询

  • 批量数据加载数据


通过上图可以观察到:
  • 读数一:MySQL QPS 在正常波动范围内;

  • 读数二:持续批量加载数据,MySQL 文件系统容量不断变大;

  • 读数三:在20分钟内,在线动态扩容 Volume 和 Filesystem 2 次, 过程高效平滑。


其他
工作到这里基本结束,要改动的地方不少,客观上并不简单。如果没有 Kubernetes 和 CSI,难度会更大。
通过此方法可以完成对其他 Storage Vendor 的扩展,譬如 FCSan、iSCSI。

对 CSI 的展望

640


目前 CSI 已发展到 0.2.0,0.3.0 也发布在即。
0.3.0 中呼声最高的特性是 Snapshot。借助该功能,可以实现备份和异地容灾。但是为了实现该功能,在 Kubernetes 现有的 Control-Plane 上还要添加新的 Controller,客观上,复杂度会进一步提高。
同时,部分 in-tree Volume Driver 已通过 CSI 迁移到外部,考虑到 Kubernetes 整体的发布节奏和 API 的稳定性,个人觉得节奏不会太快。
除此之外,CSI 可能还有更多工作要做。以一个高可用的场景为例,当一个 Node 发生故障时,CO 触发 Unmount->Dettach->Attach->Mount 的流程,配合 Pod 的漂移,借助 CSI 定义的接口,Unmount、Dettach、Attach、Mount 由SP. 自身现实,但是 Unmount->Dettach->Attach->Mount 的流程还是有 CO 控制,这个流程并不标准,但是对 workload 又至关重要。

容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力_第6张图片


又想起<人月神话>中的那句 “No Silver Bullet”。
相关链接:
  1. https://github.com/kubernetes/kubernetes/blob/afa68cc28749c09f8655941b111e46d85689daf8/pkg/volume/plugins.go#L95

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

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

  4. https://github.com/container-storage-interface/spec/blob/master/csi.proto

  5. https://docs.google.com/document/d/1kVrNwA2f4ite8_9QvCy-JQA_00hxGGMdER3I84dUDqQ/edit?usp=sharing


作者:熊中哲,沃趣科技产品及研发负责人。曾就职于阿里巴巴和百度,超过10年关系型数据库工作经验,目前致力于将云原生技术引入到关系型数据库服务中。
Kubernetes入门与进阶实战培训

640


本次培训内容包括:Docker基础、容器技术、Docker镜像、数据共享与持久化、Docker三驾马车、Docker实践、Kubernetes基础、Pod基础与进阶、常用对象操作、服务发现、Helm、Kubernetes核心组件原理分析、Kubernetes服务质量保证、调度详解与应用场景、网络、基于Kubernetes的CI/CD、基于Kubernetes的配置管理等, 点击了解具体培训内容

640?

6月22日正式上课,点击阅读原文链接即可报名。

你可能感兴趣的:(容器化 RDS:借助 CSI 扩展 Kubernetes 存储能力)