九、应用存储和持久化数据卷 – 核心知识
本文最后更新于 784 天前,其中的信息可能已经有所发展或是发生改变。

Volumes 介绍

Pod Volumes

  • 场景一:如果 pod 中的某一个容器在运行时异常退出,被 kubelet 重新拉起之后,如何保证之前容器产生的重要数据没有丢失?

  • 场景二:如果同一个 pod 中的多个容器想要共享数据,应该如何去做?

    有状态的容器,就需要卷。

    根据使用场景,临时文件直接用 host 的形式存到宿主机,非;临时的可以往云盘里存,例如分布式存储系统 CephFS

    Ceph 文件系统或 CephFS 是一个兼容 POSIX 的文件系统,它构建在 Ceph 的分布式对象存储 RADOS 之上。CephFS 致力于为各种应用程序提供最新,多用途,高可用性和高性能的文件存储,包括传统用例(如共享主目录,HPC 暂存空间和分布式工作流共享存储)。

Pod Volumes 的常见类型

  1. 本地存储,常用的有 emptydir/hostpath;

    一个是不指定宿主机目录,交给容器来管理

    另一个时指定宿主机目录

  2. 网络存储:网络存储当前的实现方式有两种

    1. in-tree,它的实现的代码是放在 K8s 代码仓库中的,随着k8s对存储类型支持的增多,这种方式会给k8s本身的维护和发展带来很大的负担

    2. out-of-tree,它的实现其实是给 K8s 本身解耦的,通过抽象接口将不同存储的driver实现从k8s代码仓库中剥离,因此out-of-tree 是后面社区主推的一种实现网络存储插件的方式;

      依赖倒置原则桥接模式

  3. Projected Volumes:它其实是将一些配置信息,如 secret/configmap 用卷的形式挂载在容器中,让容器中的程序可以通过POSIX接口来访问配置数据;

Pod Volumes 存在的问题

pod 中声明的 volume 生命周期与 pod 是相同的,以下有几种常见的场景:

  • 场景一:pod 重建销毁,如用 Deployment 管理的 pod,在做镜像升级的过程中,新旧 pod 之间如何复用数据?

  • 场景二:宿主机宕机的时候,要把上面的 pod 迁移,这个时候 StatefulSet 管理的 pod,其实已经实现了带卷迁移的语义。这时通过 Pod Volumes 显然是做不到的;

    宿主机 crash 了,pod 也没了,pod volumes 肯定不存在了

  • 场景三:多个 pod 之间,如果想要共享数据,应该如何去声明呢?我们知道,同一个 pod 中多个容器想共享数据,可以借助 Pod Volumes 来解决;当多个 pod 想共享数据时,Pod Volumes 就很难去表达这种语义;

    不同场景使用不同级别的资源

  • 场景四:如果要想对数据卷做一些功能扩展性,如:snapshot、resize 这些功能,又应该如何去做呢?

Pod Volumes 使用

image-20220224150255934

  • subPath:多个容器共享一个卷时,用于隔离数据

Persistent Volumes(PV)

  • 将存储和计算分离,通过不同的组件来管理存储资源和计算资源

    计算是指动态提供需要的资源,例如新建一个 pod 需要 10g 临时存储,就需要计算哪个存储能提供这个需求。

  • 解耦 pod 和 Volume 之间生命周期的关联

PV 状态扭转

image-20220224154606785

当用户在使用完 PVC,将其删除后,这个 PV 就处在 released 状态,这时通过 ReclaimPolicy 决定删除还是保留。

但是即使保留也不能复用这个 PV,因为 PV 已经处在 released 状态下,它是没有办法直接回到 available 状态,也就是说接下来无法被一个新的 PVC 去做绑定。

  • 第一种方式:我们可以新建一个 PV 对象,然后把之前的 released 的 PV 的相关字段的信息填到新的 PV 对象里面,这样的话,这个 PV 就可以结合新的 PVC 了;
  • 第二种是我们在删除 pod 之后,不要去删除 PVC 对象,这样给 PV 绑定的 PVC 还是存在的,下次 pod 使用的时候,就可以直接通过 PVC 去复用。K8s中的 StatefulSet 管理的 Pod 带存储的迁移就是通过这种方式。

PersistentVolumnClaim(PVC) 设计意图

  • 职责拆分,用户在 PVC 里声明需要的存储
  • PVC 简化用户对存储的需求,通过 kube-controller-manager 中的 PersistentVolumeController 将 PVC 与合适的 PV bound 在一起,从而满足用户对存储的实际需求
  • PVC 像是面向对象编程中抽象出来的接口,PV 是对应的实现

Static Volume Provisioning

提前创建一些 PV,用户提交 PVC 时,k8s 将 PVC 与合适的 PV bound 在一起

创建 PV

image-20220224150751586

  • AccessModes:也是用户需要关心的,就是说我使用这个 PV 的方式。它有三种使用方式。

    • 单 node 读写访问;

    • 多个 node 只读访问,是常见的一种数据的共享方式;

    • 多个 node 上读写访问。

  • 有多个 PV 满足PVC 里的 Capacity 和 AccessModes 时,选择 PV 的 size 最小的,accessmodes 列表最短的 PV,也即最小适合原则。

    accessmodes 为啥是数组,有多个值?

    没查到啥

  • ReclaimPolicy: PV 的 PVC 在删除之后,PV 如何处理

    • delete,也就是说 PVC 被删除之后,PV 也会被删除;
    • Retain,就是保留,保留之后,后面这个 PV 需要管理员来手动处理。
  • NodeAffinity:创建出来的 PV,能被哪些 node 去挂载使用,通过 NodeAffinity 来声明对node的限制,对使用该PV的pod调度限制,pod 必须要调度到这些能访问 PV 的 node 上,才能使用这块 PV

使用 PV

image-20220224151224610

缺点

需求不同,想要与预规划的 PV 匹配上很难。如果制定标准,减少匹配难度,又会造成资源浪费。

Dynamic Volume Provisioning

配置存储模板 StorageClass,在需要 PV 时,提交 PVC,指定模板,动态创建需要的 PV。

创建 StorageClass

image-20220224151341906

使用 PV

image-20220224151632869

  • 相对于静态 PV,多了个StorageClassName

架构设计

PV 和 PVC 的处理流程

image-20220224163615105

  1. create阶段:用户提交完 PVC,由 csi-provisioner 创建存储,并生成 PV 对象,之后 PV controller 将 PVC 及生成的 PV 对象做 bound,bound 之后,create 阶段就完成了;
  2. attach阶段:用户在提交 pod yaml 的时候,首先会被调度选中某一个 合适的node,等 pod 的运行 node 被选出来之后,会被 AD Controller watch 到 pod 选中的 node,它会去查找 pod 中使用了哪些 PV。然后它会生成一个内部的对象叫 VolumeAttachment 对象,从而去触发 csi-attacher去调用csi-controller-server 去做真正的 attache 操作,attach操作调到云存储厂商OpenAPI。这个 attach 操作就是将存储 attach到 pod 将会运行的 node 上面。
  3. mount 阶段:发生在kubelet 创建 pod的过程中,它在创建 pod 的过程中,首先要去做一个 mount,这里的 mount 操作是为了将已经attach到这个 node 上面那块盘,进一步 mount 到 pod 可以使用的一个具体路径,之后 kubelet 才开始创建并启动容器。
  • csi:container storage interface,它是K8s社区后面对存储插件实现(out of tree)的官方推荐方式。csi 的实现大体可以分为两部分:

    • 第一部分是由k8s社区驱动实现的通用的部分,例如 csi-provisioner和 csi-attacher controller;

    • 另外一种是由云存储厂商实践的,对接云存储厂商的 OpenApi,主要是实现真正的 create/delete/mount/unmount 存储的相关操作,对应到上图中的csi-controller-server和csi-node-server。

其他

docker管理的volume

在Dockerfile里声明 volume,可用于持久化数据,多容器共享数据。这里的volume没有指定宿主机目录,所以是交给docker管理。经测试,这样声明的volume,容器删除后依旧存在。

docker 保持容器运行

提供前台程序,不让容器退出。

docker run -d test-docker-volume sleep infinity

k8s 保持容器运行

containers:
  - name: ubuntu
    image: ubuntu
    command: [ "sleep" ]
    args: [ "infinity" ]

docker build 命令后点的意思 . 号的意思 以及 .dockerignore文件的作用

作者:Yuyy
博客:https://yuyy.info
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇