K8s存储概述

一直想写一篇关于kubernetes存储的文章,但是细想来又包含了太多方面,索性今天就先聊聊k8s存储的梗概。

概念

从用法上来讲,k8s支持通过两种方式使用存储;这两种方式,各自有各自的优势,都不可或缺。

  • volume
    暂且就叫它“卷挂载”吧!有人把这种方式叫做“静态卷”。通过指定volume的类型,可以支持绝大多数的存储;这种方式的优点就是即挂即用,方便快捷。当然,弊端就是如果每次使用存储都需要去配置存储参数,比较繁琐。
  • pvc
    这种方式刚好克服了volume方式的弊端,本质上是对存储资源的一种抽象。首先,它将存储资源按照种类、介质或者性能等特征划分为不同的类别,每一个类别就是一种storageclass。在需要使用存储的时候,只需要提出要求(比如storageclass-A类型的存储100G),存储卷的创建、挂载等动作均由k8s在后台完成,极大的省去了配置的麻烦。

针对pvc方式使用存储,这里的几个概念,我简单介绍一下:

  • storageclass: 某一种类型的存储后端的抽象;
  • pvc: PV claim,即对存储卷的声明或者干脆叫做需求;
  • pv: 由pvc声明后,被k8s创建出来的存储卷;
  • provisioner: 将某种存储资源提供给k8s使用的适配组件,或者叫做k8s对某种存储的驱动程序(k8s内置了多种存储的provisioner)。

软件架构

先了解了k8s存储的使用方式和一些概念之后,我们再来看看源码的结构。

架构图

上图橙色部分为kube-controller-manager中存储相关的内容,这个部分重点包含两块功能:

  • pv/pvc controller: 主要负责监听pvc,并基于pvc创建出对应的persistent volume。
  • attach/dettach controller: 负责将远端的存储挂载到pod所在的宿主机对应目录,一般位于/var/lib/kubelet/pods/<pod-uid>/volumes/

图中下方蓝色部分为volume-manager, 主要位于kubelet中。volume-manager 主要是监听调度到本节点的pod的volume信息,整理出所有volume的挂载需求,然后执行reconcile函数来保障actual state满足desire state。

针对于某一种特定类型的存储,其创建pv、挂载到宿主机,以及在宿主机上将存储mount到容器目录的这一系列操作都是有专业性的。因此,k8s按照存储类型,以库的方式实现了一套存储的plugin;无论是controller-manager还是kubelet都可以通过源码import的方式来调用plugin库中的实现。因此,右侧绿色部分的plugins是贯穿到上下两部分的。

功能结构

总结一下,k8s的存储功能主要有四大部分(其中后两部分都运行在controller-manager上),各部分的功能如下:

  • volume plugin

    1. 对k8s存储接口的实现库, 包含了各类存储提供者的plugin实现;
    2. 实现自定义的Plugins可以通过FlexVolume;
    3. 支持CSI。
  • volume manager

    1. 在kubelet运行,使命是保障actual state满足desire state,主要是mount/unmount(attach/detach可选);
    2. 在pod创建的过程中,会等待volume-manager将volume mount完成,才会继续创建pod。
  • pv/pvc controller

    1. 运行在controller-manager中,主要实现provision/delete(当为out-tree实现时,也需要实现这两个接口);
    2. pv-controller和K8S其它组件一样监听api-server中的资源更新,对于卷管理主要是监听PV,PVC,SC三类资源,当监听到这些资源的创建、删除、修改时,pv-controller经过判断是需要做创建、删除动作。
  • attach/dettach controller

    1. 运行在controller-manager中,主要实现块设备的attach/detach(并非每种存储都需要该操作);
    2. 职责是当api-server中有卷声明的pod与node间的关系发生变化时,决定是通过调用存储插件将这个pod关联的卷attach到对应node的宿主机上,还是将卷从node上detach掉.

CSI

现在k8s已经逐步将存储都使用CSI来实现了,这里简单整理一下CSI的流程。

部署架构

k8s-csi

细节参考以下两篇文档:

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md
https://kubernetes-csi.github.io/docs/Home.html

标准接口

  • Controller Server

    CreateVolume => provision (external-provisioner)
    DeleteVolume => delete (external-provisioner)
    ControllerPublishVolume => attach (external-attacher)
    ControllerUnpublishVolume => detach (external-attacher)

  • Node Server

    NodeStageVolume => mount (kubelet)
    NodeUnstageVolume => umount (kubelet)
    NodePublishVolume => mount (kubelet)
    NodeUnpublishVolume => umount (kubelet)

操作

  • provision/delete

    CSI proxy通过监听API Server有PVC的Add/Delete操作后通过host与container的socket调用CSI接口,CSI Driver接收到调用后,调用存储设备实现卷的增删。

  • attach/dettach

    AD Controller监听API Server的pod,node状态判断是否进行attach/detach操作,如果需要进行,CSI Plugin则通过API Server创建/删除attachvolume(内部API对象). CSI Proxy Container中的attacher监听到API Server中attachvolume的增删后,通过本地socket调用另一个容器中的CSI Driver执行attach/detach操作(注意,CSI接口不是这个名称),CSI Driver再通过调用存储后端完成attach/detach操作。操作完成后,CSI Proxy Container更新attachvolume状态。

  • mount/unmount

    Kubelet判断需要做mount操作,通过Host到container的socket调用CSI Driver,CSI Driver在容器内部通过挂载到容器里的Mount Point卷进行bind mount操作。

0%