写点什么

在 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:009946

评论 1 条评论

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

4364Mb/s,助力SM4性能提升40倍的商密 SIG 还有哪些新进展?

OpenAnolis小助手

Linux 开源 互联网社区 sig

java培训:内存泄漏问题排查与分析

@零度

JAVA开发

2021 年的技术总结与趋势分析,我们访谈了几位开发者

知晓云

小程序 微信 元宇宙

以开发之名|致敬女性开发者 用“代码”创造无限可能

最新动态

有Python基础后,3天就拿Flask开发项目系列博客之一

梦想橡皮擦

3月月更

3个案例,详解如何选择合适的研发模式 | 研发效能提升36计

阿里云云效

阿里云 云原生 研发团队 研发 研发提效

订单中心探索业务系统数据预置助力快交付之路

鲸品堂

敏捷交付

【51单片机】keil5如何创建工程

謓泽

单片机 3月月更 keil5

普通索引和唯一索引,难道还分不清

华为云开发者联盟

MySQL 数据库 索引 唯一索引 普通索引

2022年中国婴童零辅食行业市场洞察

易观分析

零辅食

技术平台&应用开发专题月 | 一文搞懂全链路监控系统(下)

用友BIP

用友 用友iuap

可观测性能力升级,Apache APISIX 集成 OpenTelemetry

API7.ai 技术团队

开源 api 网关 OpenTelemetry Apache APISIX

眼影、口红、香水…特别的日子献给所有的她 | InfoQ 会员周女神节特别限定活动

InfoQ写作社区官方

热门活动 InfoQ会员周 38妇女节

金融数据查询增速三倍,服务器成本减半,海尔云链的 OLAP 引擎选型之路

StarRocks

数据库 数据分析 OLAP StarRocks

web前端培训:使用 Rust 编写 React 组件

@零度

前端开发 React

WebGPU小白入门(一): 零基础创建第一个WebGPU项目

Orillusion

开源 WebGL 元宇宙 Metaverse webgpu

毕业总结

施正威

Apache APISIX 携手 CoreDNS 打开服务发现新大门

API7.ai 技术团队

服务发现 API网关 Apache APISIX

技术分享会回顾|Rust在量化领域如何应用?

非凸科技

Flink 流处理在中信建投证券的实践与应用

Apache Flink

大数据 flink 开源 编程 实时计算

电商秒杀系统

tony

「架构实战营」

新 Slogan 新征程|OceanBase 海量记录 笔笔算数

OceanBase 数据库

分布式数据库 oceanbase 品牌slogan

摄影师教你开发小程序,「龟斯的风光摄影助手」的设计与开发思路详解

知晓云

微信 前端开发 小程序开发

开源云 IDE 产品新宠儿,如何使用 Gitpod 开发 APISIX?

API7.ai 技术团队

ide 开发工具 Apache APISIX

对容器在野安全问题的观测和分析

腾讯安全云鼎实验室

网络安全 容器安全 在野攻击

GraphQL 碰撞 Apache APISIX,提升 API 领域的安全与性能

API7.ai 技术团队

开源 api 网关 graphql APISIX 网关

项目启动丨木林森携手用友iuap共谱数字化转型新篇章

用友BIP

用友 用友iuap

API 网关 Apache APISIX 集成 Eureka 作为服务发现

API7.ai 技术团队

Eureka 服务注册与发现 API Gateway APISIX 网关

毕业设计

施正威

两天两夜,1M图片优化到100kb!

沉默王二

Java

大数据培训:SQL如何去重的方法

@零度

大数据开发

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