写点什么

在 Kubernetes 中,如何动态配置本地存储?

  • 2019-05-30
  • 本文字数:3008 字

    阅读完需:约 10 分钟

在 Kubernetes 中,如何动态配置本地存储?

在企业 IT 架构转型的过程中,存储一直是个不可避免的大问题。


Kubernetes 中使用节点的本地存储资源有 emptyDir、hostPath、Local PV 等几种方式。这之中,emptyDir 无法持久化数据,hostPath 方式需要手动管理卷的生命周期,运维压力大。因此在某些场景下,如果用户出于性能和运维成本考虑需要使用本地存储,Local PV 似乎是唯一选择。

1 什么是 Local PV?

所谓 Local PV(本地持久化存储),指的就是利用机器上的磁盘来存放业务需要持久化的数据,和远端存储类似,此时数据依然独立于 Pod 的生命周期,即使业务 Pod 被删除,数据也不会丢失。


同时,和远端存储相比,本地存储可以避免网络 IO 开销,拥有更高的读写性能,所以分布式文件系统和分布式数据库这类对 IO 要求很高的应用非常适合本地存储。

2 设计方案

在具体介绍如何动态配置本地存储前,我们先来介绍一下 Kubernetes 上游对于 Local PV 的一些支持情况:


  • Kubernetes v1.7: 正式引入 Local PV;

  • Kubernetes v1.10: Local PV 进入 Beta;

  • Kubernetes v1.14: Local PV 进入 GA。


在今年 3 月发布的 Kubernetes v1.14 中,社区对此的评价是:


出于性能和成本考量,分布式文件系统和数据库一直是 Local PV 的主要用例。相比云服务供应商,本地 SSD 提供的性能远比远程磁盘优秀;而相比裸机,除了性能,本地存储通常更便宜,并且使用它是配置分布式文件系统的必要条件。


目前,Local PV 的本地持久存储允许我们直接使用节点上的一块磁盘、一个分区或者一个目录作为持久卷的存储后端,但暂时还不提供动态配置支持,也就是说:你得先把 PV 准备好。


不同于其他类型的存储,本地存储强依赖于节点。换言之,它在调度 Pod 的时候还要考虑到这些 Local PV 对容量和拓扑域的要求。


这里我先介绍一下延迟绑定机制和 volume topology-aware scheduling。延迟绑定机制可以让 PVC 的绑定推迟到有 Pod 使用它并且完成调度后,而 volume topology-aware scheduling 则可以让 Kubernetes 的调度器知道卷的拓扑约束,也就是这个存储卷只能在特定的区域或节点上使用(访问),让调度器在调度 Pod 的时候必须考虑这一限制条件。


在介绍了这些背景之后,我们来看一个使用本地存储的 PV 示例:



其他内容和一个普通 PV 无异,只是多了一个 nodeAffinity


这个字段的值使得 Kubernetes 调度器能够把使用这个 PV 的 Pod 调度到正确的 Node 上。


对于本地存储的动态配置,除了实现最基础的根据 StorageClass 和 PVC 动态创建 Persistent Volume 外,它还要让 Kubernetes 的调度器能够感知本地存储节点的剩余容量,选择存储量足够大的节点,能够将使用本地存储的 Pod 调度到正确的拓扑域上,例如上面例子中的一个节点或者一个特定的区域。


为了方便对本地存储节点的磁盘进行管理,本地存储功能的底层选择使用 LVM 来实现。LVM 是 Linux 环境下对磁盘分区进行管理的一种机制,是建立在硬盘和分区之上的一个逻辑层,具有很高的灵活性。下面是 LVM 架构的一个示意图:



图片源于网络


而为了让 Kubernetes 的调度器能够感知本地存储节点的剩余容量,我们选择使用 Kubernetes Scheduler Extender,使用一个 webhook 来扩展原生调度器的功能,这种方法实现起来简单、易于维护和使用且无侵入性,不修改源代码。


所以整个组件由两部分组成:一个是 LVM Manager,它以 DaemonSet 的形式运行,负责管理每个节点上的磁盘,汇报节点磁盘的容量和剩余容量,动态创建 PV 等;另一个是个 local storage scheduler 调度模块,负责为使用本地存储的 Pod 选择合适(有足够容量)的节点


StorageClass 需要设置 provisioner 字段的值为我们自定义的 local-volume-provisioner 之类的,表示需要动态创建 Persistent Volume:



创建 StorageClass 时需要选择的节点和磁盘等信息会先记录在 parameters 中,数据结构定义如下(JSON 格式化成普通字符串后存储在 parameters 中):



然后 LVM Manager 会根据这个信息在对应的节点上将选择的磁盘合并成一个 LVM 的卷组(VG),方便后续管理。


考虑到可扩展性,和 StorageClass、Node 关联的磁盘、VG 等信息会记录在一个新增的自定义资源(Custom Resources,以下简称 CR)里面,而不是直接将信息记录在对应的 StorageClass 和 Node 的 annotation 中。原因如下:


  • 其一,我们需要自定义的结构化数据;

  • 其二,我们把本地存储作为一种扩展资源。它区别于 CPU 和内存,包含了类型、节点和磁盘等众多属性,并且一个节点可以关联多个本地存储资源。


一组 StorageClass、Node 和磁盘信息就有一条记录,新的 CR 的定义如下(注意,以下结构只是为了方便说明和阅读,并不是 Kubernetes 推荐的标准结构):



关系示意图如下:



几乎所有和 LVM 相关的操作都只需要监听和更新这一个对象。LVM Manager 监听这个对象,在需要的 Node 上动态创建 VG 并定时更新这个对象中的 VG 的容量和剩余容量等;Scheduler 根据这个对象上的容量信息辅助调度。


然后对于 local storage scheduler 模块,首先我们要配置 Kubernetes Scheduler,为其增加一个 extender,使其在进行 node filter 的时候会访问我们的 local storage scheduler webhook 以达到我们想要的对节点进行二次筛选的效果。下面是一个配置的示例:



下面有一个增加了 scheduler extender 之后的调度流程示例:



最后,我再总结一下整个动态配置的正常流程:


  • 创建 StorageClass 并配置想要选择的节点和对应的磁盘等信息;

  • LVM Manager 为对应的节点创建 VG;

  • LVM Manager 同时需要负责定期上报 VG 的容量信息;

  • 创建 PVC 和使用它的 Pod;

  • Kubernetes 调度器为 Pod 选择合适的节点,然后访问 Extender webhook;

  • local storage scheduler 对选择的节点根据容量条件进行二次过滤;

  • Kubernetes 调度器最后再选中一个节点,并且把该节点名称也存储到 PVC 的 volume.kubernetes.io/selected-node annotation 中;

  • dynamic provisioner 介入,根据 PVC 的 volume.kubernetes.io/selected-node annotation 的值,在这个节点上根据 PVC 的要求创建一个 LVM 的逻辑卷(LV),再创建对应的 PV;

  • volume 绑定完成,Pod 和 Node 绑定,调度完成。

3 结语

动态本地存储涉及多个组件的交互,异常处理尤为重要


例如,若 NodeLocalStorage 对象的容量信息没有及时更新,导致选中的节点其实没有剩余容量了,那么相应的 LVM 的逻辑卷(LV)也创建不出来,provisioning 失败。


这时,local-storage-provisioner 就要将 PVC 的 volume.kubernetes.io/selected-node annotation 清空,接下来 Kubernetes Scheduler 会重新调度。


类似异常处理很多,限于篇幅,这里不一一列举。如果你对这方面的创新和进展感兴趣,欢迎关注才云科技公众号(ID:Caicloud2015),之后我们还有会奉送更多一线技术内容。


当然,如果你对动态配置本地存储还有疑问或是有新思路,欢迎留言讨论,才云有多个面向开发者的技术社群,期待你的加入。


参考文献


  1. [Volumes - Kubernetes]

  2. https://kubernetes.io/docs/concepts/storage/volumes/#local

  3. [Volume Topology-aware Scheduling]

  4. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/volume-topology-scheduling.md

  5. [Scheduler extender]

  6. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/scheduler_extender.md


本文转载自公众号才云 Caicloud(ID:Caicloud2015)


原文链接


https://mp.weixin.qq.com/s/aUl0GWn7HZLT53MjVDf1Fw


2019-05-30 08:009646

评论 1 条评论

发布
用户头像
实现开源了么?
2019-09-19 11:51
回复
没有更多了
发现更多内容

【直播预告】HarmonyOS 极客松赋能直播第六期:产品创新从哪里来?

HarmonyOS开发者

HarmonyOS

CSS is、where和has选择器

南城FE

CSS 前端开发 选择器 伪类

聚焦前沿技术产业应用,文心大模型应用研讨会于广州顺利举办

飞桨PaddlePaddle

人工智能 百度 paddle 百度飞桨

创新驱动转型:软件外包企业迎接AI赋能时代

知者如C

想要用Altair的仿真软件,记住这个入门级配置

智造软件

有限元分析 altair Hypermesh hyperworks 有限元技术

浅谈常态化压测 | 京东物流技术团队

京东科技开发者

测试 压力测试 常态化压测 企业号 7 月 PK 榜

兼容性测试的正确打开方式

老张

兼容性测试 兼容性

语音软件源码开发搭建,好友管理功能剖析

山东布谷科技

源码 软件开发 源码剖析 语音源码 语音软件

Sping Security前后端分离两种方案

EquatorCoco

前端 前后端分离 springboot

CAE软件配置要求

智造软件

CAE 有限元仿真技术 有限元分析 CAE软件 计算机软件

新版危险废物标签二维码制作教程

草料二维码

二维码 二维码生成

主流开源分析引擎梳理,看看你最中意谁?| StoneDB数据库观察

StoneDB

MySQL 数据库 StoneDB

Linux系统-gzip命令 – 压缩和解压文件

百度搜索:蓝易云

Linux 服务器 云服务器 gzip 蓝易云

落地领域大模型应知必会(2): 轻量化微调

Baihai IDP

人工智能 企业号 7 月 PK 榜 大模型微调 领域大模型 轻量化微调

有限元分析软件Hypermesh的配置要求

智造软件

有限元分析 计算机软件 altair 有限元仿真 Hypermesh

非常小的一个东西,Spring依赖注入Bean类型的8种情况

不在线第一只蜗牛

前端 spring-boot

华为云流水线CodeArts Pipeline怎么样?能实现哪些功能?

华为云PaaS服务小智

云计算 PaaS 云服务 华为云 华为开发者大会

ArcGIS模型构建器ModelBuilder的使用方法

EquatorCoco

架构 模型调参 Arch

率先布局 RWA 赛道,PoseiSwap 成为最具先进性的 DEX

西柚子

OpenHarmony社区运营报告(2023年6月)

OpenHarmony开发者

OpenHarmony

Linux系统 cp命令 – 复制文件或目录

百度搜索:蓝易云

云计算 Linux 运维 服务器 云服务器

聊聊「画图」和工具

Java 架构 画图工具

重磅!用友首个全球交付中心在南昌成立啦!

用友BIP

全面预算管理对企业盈利能力的影响

智达方通

运营管理 全面预算管理 盈利能力 数据互通 管理报告

直播预约|漫漫用户增长之路,如何快人一手

HarmonyOS SDK

HMS Core

Mes系统|开源Mes|万界星空

万界星空科技

开源 mes 免费

Huggingface:导出transformers模型到onnx

程序员架构进阶

ONNX 大模型 7月日更 7月月更 huggingface

一文读懂 Kubernetes 存储设计

江湖十年

k8s 后端 存储 Kubernetes 集群

华为云出品《深入理解高并发编程:Java线程池核心技术》电子书发布

华为云PaaS服务小智

云计算 华为云 java 技术提升 华为开发者大会

火山引擎 DataLeap 套件下构建数据目录(Data Catalog)系统的实践

字节跳动数据平台

数据库 大数据 数据中台 企业号 7 月 PK 榜

Seal AppManager v0.2 发布:进一步简化应用部署体验

SEAL安全

软件开发 运维‘ 平台工程

在 Kubernetes 中,如何动态配置本地存储?_数据库_iawia002_InfoQ精选文章