Volume、PV、PVC、StorageClass由来

先思考一个问题,为什么会引入Volume这样一个概念?

答案很简单,为了实现数据持久化,数据的生命周期不随着容器的消亡而消亡。

在没有介绍Kubernetes Volume之前,先来回顾下Docker VolumeDocker Volume常用使用方式有两种,

  • volumes通过这种方式,Docker管理宿主机文件系统的一部分,默认位于/var/lib/docker/volumes目录中,由于在创建时没有创建指定数据卷,docker自身会创建默认数据卷;

  • bind mounts通过这种方式,可以把容器内文件挂载到宿主机任意目录。

既然有了Docker Volume,为啥Kubernetes又搞出了自己的Volume?谷歌的标新立异?

答案是否定的,Kubernetes VolumeDocker Volume概念相似,但是又有不同的地方,Kubernetes VolumePod的生命周期相同,但与容器的生命周期不相关。当容器终止或重启时,Volume中的数据也不会丢失。当Pod被删除时,Volume才会被清理。并且数据是否丢失取决于Volume的具体类型,比如emptyDir类型的Volume数据会丢失,而持久化类型的数据则不会丢失。另外Kubernetes提供了将近20Volume类型。

现在有了KubernetesVolume,我们就可以完全可以在Yaml编排文件中填写上Volume是字段,如下nfs所示:

....
volumes:
    - name: static-nfs
      nfs:
          server: 12.18.17.240
          path: /nfs/data/static

如果你使用ceph作为存储插件,你可以在编排文件中这样定义:

volumes:
    - name: ceph-vol
      cephfs:
        monitors:
        - 12.18.17.241:6789
        - 12.18.17.242:6789
        user: admin
        secretRef:
          name: ceph-secret
        readOnly: true

当然只要是Kubernetes已经实现的数据卷类型,你都可以按照如上方式进行直接在Yaml编排文件中定义使用。

看到这里其实已经完成了80%的工作,那么为什么还要设计多此一举的PV呢?这个问题先搁置下,后面会有说明。

在没有说明为什么要设计多此一举的PV PVC之前,先来看看什么是PV PVC

PV是对持久化存储数据卷的一种描述。

PV通常是由运维人员提前在集群里面创建等待使用的一种数据卷。如下所示:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 10.244.1.4
    path: "/nfs"

PVC描述的是持久化存储的属性,比如大小、读写权限等。

PVC通常由开发人员创建,如下所示:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

而用户创建的PV PVC必须绑定完成之后才能被利用起来。而PV PVC绑定起来的前提是PVspec中声明字段大小、权限等必须满足PVC的要求。

成功绑定之后,就可以在Pod Yaml编排文件中定义和使用。如下所示:

apiVersion: v1
kind: Pod
metadata:
  labels:
    role: web
spec:
  containers:
  - name: web
    image: nginx
    ports:
      - name: web
        containerPort: 80
    volumeMounts:
        - name: nfs
          mountPath: "/usr/share/nginx/html"
  volumes:
  - name: nfs
    persistentVolumeClaim:
      claimName: nfs

看到这里,我们还会认为仅仅是PVVolume多了一层抽象,并不见得比直接在Yaml中声明Volume高明多少。仔细思考下,我们为什么能够直接在Yaml中直接定义Volume?因为Kubernetes已经帮助我们实现了这种Volume类型,如果我们有自己的存储类型,而Kubernetes中并没有实现,这种是没有办法直接在Yaml编排文件中直接定义Volume的。这个时候PV PVC面向对象的设计就体现出其价值了。这也是在软件开发领域经常碰到的问题,开源软件无法满足要求,但也没有提供出可扩展的接口,没办法,只能重新造轮子。

我们在开发过程中经常碰到这样一个问题,在Pod中声明一个PVC之后,发现Pod不能被调度成功,原因是因为PVC没有绑定到合适的PV,这个时候要求运维人员创建一个PV,紧接着Pod调度成功。刚才上在介绍PV PVC,它们的创建过程都是手动,如果集群中需要成千上万的PV,那么运维人员岂不累死?在实际操作中,这种方式根本行不通。所以Kubernetes给我们提供了一套自动创建PV的机制Dynamic Provisioning.在没有介绍这套自动创建机制之前,先看看Static Provisioning,什么是Static Provisioning?刚才人工创建PV PVC的方式就是Static Provisioning。你可以在PV PVC编排文件中声明StorageClass,如果没有声明,那么默认为"".具体交互流程如下所示:

静态分配流程

首先由集群管理员事先去规划这个集群中的用户会怎样使用存储,它会先预分配一些存储,也就是预先创建一些 PV;然后用户在提交自己的存储需求(PVC)的时候,Kubernetes内部相关组件会帮助它把PVC PV 做绑定;最后pod使用存储的时候,就可以通过PVC找到相应的PV,它就可以使用了。不足之处也非常清楚,首先繁琐,然后运维人员无法预知开发人员的真实存储需求,比如运维人员创建了多个100GiPV存储,但是在实际开发过程中,开发人员只能使用10Gi,这就造成了资源的浪费。当然Kubernetes也为我们提供更好的使用方式,即Dynamic Provisioning它是什么呢?

Dynamic Provisioning包含了创建某种PV所需要的参数信息,类似于一个创建PV的模板。具体交互流程如下所示:

Kubernetes集群中的控制器,会结合PVCStorageClass的信息动态生成用户所需要的PV,将PVC PV进行绑定后,pod就可以使用PV了。通过 StorageClass配置生成存储所需要的存储模板,再结合用户的需求动态创建PV对象,做到按需分配,在没有增加用户使用难度的同时也解放了集群管理员的运维工作。

动态PV使用

Dynamic Provisioning上面提到过,运维人员不再预分配PV,而只是创建一个模板文件,这个模板文件正是StorageClass。下面以NFS为例进行说明,动态PV的整个使用过程。

  • 安装NFS服务

#安装nfs
yum -y install nfs-utils rpcbind
#开机自启动
systemctl enable rpcbind nfs-server
#配置nfs 文件
echo "/nfs/data *(rw,no_root_squash,sync)" >/etc/exports
  • 部署置备程序

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
   name: nfs-provisioner-runner
rules:
   -  apiGroups: [""]
      resources: ["persistentvolumes"]
      verbs: ["get", "list", "watch", "create", "delete"]
   -  apiGroups: [""]
      resources: ["persistentvolumeclaims"]
      verbs: ["get", "list", "watch", "update"]
   -  apiGroups: ["storage.k8s.io"]
      resources: ["storageclasses"]
      verbs: ["get", "list", "watch"]
   -  apiGroups: [""]
      resources: ["events"]
      verbs: ["watch", "create", "update", "patch"]
   -  apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get","create","list", "watch","update"]
   -  apiGroups: ["extensions"]
      resources: ["podsecuritypolicies"]
      resourceNames: ["nfs-provisioner"]
      verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: logging
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
spec:
  selector:
    matchLabels:
      app: nfs-client-provisioner
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-client
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 12.18.7.20
            - name: NFS_PATH
              value: /nfs/data
      volumes:
        - name: nfs-client
          nfs:
            server: 12.18.7.20
            path: /nfs/data
  • 创建StorageClass模板

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
provisioner: fuseim.pri/ifs
reclaimPolicy: Retain

这些参数是通过Kubernetes创建存储的时候,需要指定的一些细节参数。对于这些参数,用户是不需要关心的,像这里provisioner指的是使用nfs的置备程序。ReclaimPolicy就是说动态创建出来的PV,当使用方使用结束、PodPVC被删除后,这块PV应该怎么处理,我们这个地方写的是Retain,意思就是说当使用方pod PVC被删除之后,这个PV会保留。

  • 提交完成模板文件之后,用户只需要在Pod yaml文件定义PVC,即可自动创建PVPVC

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: es
spec:
  ........
  template:
    metadata:
      labels: 
        app: elasticsearch
    spec:
      .........
      initContainers:
      ........
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
        .......
  volumeClaimTemplates:
  - metadata:
      name: data
      labels:
        app: elasticsearch
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: nfs-storage
      resources:
        requests:
          storage: 50Gi`

Capacity:存储对象的大小;

AccessModes:也是用户需要关心的,就是说使用这个PV的方式。它有三种使用方式:ReadWriteOnce是单node读写访问;ReadOnlyMany是多个node只读访问,常见的一种数据共享方式;ReadWriteMany是多个node上读写访问;

StorageClassNameStorageClassName这个我们刚才说了,动态Provisioning时必须指定的一个字段,就是说我们要指定到底用哪一个模板文件来生成PV

Kubernetes存储架构

存储架构图
  • PV Controller: 负责PV PVC的绑定、生命周期管理,并根据需求进行数据卷的Provision Delete操作

  • AD Controller:负责存储设备的Attach Detach操作,将设备挂载到目标节点

  • Volume Manager:管理卷的Mount Unmount操作、卷设备的格式化以及挂载到一些公用目录上的操作

  • Volume Plugins:它主要是对上面所有挂载功能的实现。PV Controller、AD Controller、Volume Manager 主要是进行操作的调用,而具体操作则是由Volume Plugins实现的。根据源码的位置可将Volume Plugins分为In-TreeOut-of-Tree两类:In-Tree表示源码是放在Kubernetes内部的(常见的NFS、cephfs等),和Kubernetes一起发布、管理与迭代,缺点是迭代速度慢、灵活性差;Out-of-TreeVolume Plugins的代码独立于Kubernetes,它是由存储提供商实现的,目前主要有Flexvolume CSI两种实现机制,可以根据存储类型实现不同的存储插件

  • Scheduler:实现对Pod的调度能力,会根据一些存储相关的的定义去做存储相关的调度

动态PV交互流程

Kubernetes挂载Volume过程
  1. 用户创建一个包含PVCPod

  2. PV Controller会观察ApiServer,如果它发现一个PVC已经创建完毕但仍然是未绑定的状态,它就会试图把一个PVPVC绑定

  3. Provision就是从远端上一个具体的存储介质创建一个Volume,并且在集群中创建一个PV对象,然后将此PVPVC进行绑定

  4. Scheduler进行多个维度考量完成后,把Pod调度到一个合适的Node

  5. Kubelet不断watch APIServer是否有Pod要调度到当前所在节点

  6. Pod调度到某个节点之后,它所定义的PV还没有被挂载(Attach),此时AD Controller就会调用VolumePlugin,把远端的Volume挂载到目标节点中的设备上(/dev/vdb);当Volum Manager 发现一个Pod调度到自己的节点上并且Volume已经完成了挂载,它就会执行mount操作,将本地设备(也就是刚才得到的/dev/vdb)挂载到 Pod在节点上的一个子目录中

  7. 启动容器,并将已经挂载到本地的Volume映射到容器中

总结

本文主要扯了如下内容,首先介绍KubernetesVolume、PV、PVC、StorageClass由来,然后介绍了StorageClass使用,最后简单介绍了Kubernetes存储架构以及动态存储交互流程。当然还有很多细节逻辑没有提到,如有兴趣,欢迎关注公众号,加我微信,一起讨论!

详解Kubernetes存储体系的更多相关文章

  1. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

  2. 详解Kubernetes微服务自动化发布系统

    实施微服务架构后,原先单一的系统结构统变成了数量众多的微服务应用,开发.测试.运维部署等都会面临不少挑战.在微服务架构下如何提高工程研发效率,确保开发.测试.运维部署等流程上的顺畅,是微服务技术体系能 ...

  3. 详解Map集合体系及方法entrySet、keySet、values

    简单回顾Map集合: Map表示映射关系,以键值对的方式来保存数据.key和value一一对应.key是唯一的,不可重复,而value是可重复的,可以被多个key关联.虽然Map是放入两个数据,但是却 ...

  4. 详解javascript 存储

    javascript用于存储的方式可谓是多种多样,善于应用‘存储’可以大大的提高网站的性能,博主结合日常开发常见需求做一下总结,希望对大家有用- 1.cookie 存储大小:   4kb左右,以20个 ...

  5. (MariaDB)MySQL数据类型详解和存储机制

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  6. MySQL教程详解之存储引擎介绍及默认引擎设置

    什么是存储引擎? 与其他数据库例如Oracle 和SQL Server等数据库中只有一种存储引擎不同的是,MySQL有一个被称为“Pluggable Storage Engine Architectu ...

  7. Kubernetes 实践指南之Kubernetes 的命令行工具详解

    kubectl作为客户端CLI工具,可以让用户通过命令行的方式对Kubernetes集群进行管理.本节内容将对kubectl的子命令和用法进行详细描述. 一.kubectl 用法概述 kubectl语 ...

  8. MySQL数据库的各种存储引擎详解

    原文来自:MySQL数据库的各种存储引擎详解   MySQL有多种存储引擎,每种存储引擎有各自的优缺点,大家可以择优选择使用: MyISAM.InnoDB.MERGE.MEMORY(HEAP).BDB ...

  9. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

随机推荐

  1. spring-boot-learning-监控相关

    springboot提供了对项目的监控功能,首先我们需要引入需要的jar包: <!--监控包--> <!-- https://mvnrepository.com/artifact/o ...

  2. Redis String Type

    Redis字符串的操作命令和对应的api如下: set [key] [value] JedisAPI:public String set(final String key, final String ...

  3. 会话缓存(Session Cache)?

    最常用的一种使用 Redis 的情景是会话缓存(session cache).用 Redis 缓存会 话比其他存储(如 Memcached)的优势在于:Redis 提供持久化.当维护一个不 是严格要求 ...

  4. idea问题之"一个或多个listeners启动失败问题"

    org.apache.catalina.core.StandardContext.startInternal 一个或多个listeners启动失败,更多详细信息查看对应的容器日志文件之 "A ...

  5. cpu内部组成

    计算机系统的硬件结构主要由四部分组成:控制器.运算器.内存和输入输出设备 其中,控制器和运算器统称为中央处理器.简称CPU.它是计算机硬件系统的指挥中心. 它包括控制器.运算器.寄存器三个部分,其中, ...

  6. C 语言中 static 的作用

    在 C 语言中,static 的字面意思很容易把我们导入歧途,其实它的作用有三条. (1)先来介绍它的第一条也是最重要的一条:隐藏 当我们同时编译多个文件时,所有未加 static 前缀的全局变量和函 ...

  7. Amaze UI 模版中心上线丨十几款高质量优秀模版免费提供!

    Amaze UI模版中心终于上线了,目前汇聚了包含企业门户.新闻资讯.管理后台等多个领域的模版,全都可以免费下载. Amaze UI模版中心后续还会增加更多的模版以及领域,请各位持续关注. 模版中心的 ...

  8. 写了一个web os脚手架

    预览地址在这里:http://thx.github.io/magix-os/项目地址在这里:https://github.com/thx/magix-os 介绍下目录结构 核心目录cores主要是构成 ...

  9. 小程序开发之一(使用fly进行http封装)

    原文地址:http://callmesoul.cn 下载fly js文件 fly小程序文档 /api/config.js 配置,主要配置全局的host url和request拦截和request拦截 ...

  10. three.js 入门详解(一)

    1. 概述 1.1 什么是WebGL? WebGL是在浏览器中实现三维效果的一套规范 想要使用WebGL原生的API来写3D效果的话,很吃力.three.js是WebGL的一个开源框架,它省去了很多麻 ...