❝
本文转自 weiliang 的工作笔记,原文:https://weiliang-ms.github.io/wl-awesome/2.%E5%AE%B9%E5%99%A8/k8s/storage/OpenEBS.html,版权归原作者所有。欢迎投稿,投稿请添加微信好友:cloud-native-yang
简介
OpenEBS 是什么?
OpenEBS
是一种开源云原生存储解决方案,托管于 CNCF
基金会,目前该项目处于沙箱阶段。
OpenEBS 是一组存储引擎,允许您为有状态工作负载 (StatefulSet) 和 Kubernetes 平台类型选择正确的存储解决方案。在高层次上,OpenEBS 支持两大类卷——本地卷和复制卷。
OpenEBS 是 Kubernetes 本地超融合存储解决方案,它管理节点可用的本地存储,并为有状态工作负载提供本地或高可用的分布式持久卷。作为一个完全的 Kubernetes 原生解决方案的另一个优势是,管理员和开发人员可以使用 kubectl、Helm、 Prometheus、Grafana、Weave Scope 等 Kubernetes 可用的所有优秀工具来交互和管理 OpenEBS。
OpenEBS 能做什么?
OpenEBS
管理 k8s
节点上存储,并为 k8s
有状态负载(StatefulSet
)提供本地存储卷或分布式存储卷。
-
本地卷(Local Storage)
-
OpenEBS 可以使用宿主机裸块设备或分区,或者使用 Hostpaths 上的子目录,或者使用
LVM
、ZFS
来创建持久化卷 -
本地卷直接挂载到 Stateful Pod 中,而不需要 OpenEBS 在数据路径中增加任何开销
-
OpenEBS 为本地卷提供了额外的工具,用于监控、备份 / 恢复、灾难恢复、由
ZFS
或LVM
支持的快照等
-
-
对于分布式卷 (即复制卷)
-
OpenEBS 使用其中一个引擎 (
Mayastor
、cStor
或Jiva
) 为每个分布式持久卷创建微服务 -
有状态 Pod 将数据写入 OpenEBS 引擎,OpenEBS 引擎将数据同步复制到集群中的多个节点。OpenEBS 引擎本身作为 Pod 部署,并由 Kubernetes 进行协调。当运行 Stateful Pod 的节点失败时,Pod 将被重新调度到集群中的另一个节点,OpenEBS 将使用其他节点上的可用数据副本提供对数据的访问
-
有状态的 Pods 使用
iSCSI
(cStor
和Jiva
) 或NVMeoF
(Mayastor
) 连接 OpenEBS 分布式持久卷 -
OpenEBS cStor
和Jiva
专注于存储的易用性和持久性。它们分别使用自定义版本的ZFS
和Longhorn
技术将数据写入存储。OpenEBS Mayastor
是最新开发的以耐久性和性能为设计目标的引擎,高效地管理计算 (大页面、核心) 和存储 (NVMe Drives
),以提供快速分布式块存储
-
❝
注意:
OpenEBS
分布式块卷被称为复制卷,以避免与传统的分布式块存储混淆,传统的分布式块存储倾向于将数据分布到集群中的许多节点上。复制卷是为云原生有状态工作负载设计的,这些工作负载需要大量的卷,这些卷的容量通常可以从单个节点提供,而不是使用跨集群中的多个节点分片的单个大卷
对比传统分布式存储
OpenEBS
与其他传统存储解决方案不同的几个关键方面 :
-
使用微服务体系结构构建,就像它所服务的应用程序一样。
OpenEBS
本身作为一组容器部署在Kubernetes
工作节点上。使用Kubernetes
本身来编排和管理OpenEBS
组件 -
完全建立在用户空间,使其高度可移植性,以运行在任何操作系统 / 平台。
-
完全意图驱动,继承了
Kubernetes
易用性的相同原则 -
OpenEBS
支持一系列存储引擎,因此开发人员可以部署适合于其应用程序设计目标的存储技术。像Cassandra
这样的分布式应用程序可以使用LocalPV
引擎进行最低延迟的写操作。像MySQL
和PostgreSQL
这样的单片应用程序可以使用使用NVMe
和SPDK
构建的Mayastor
或基于ZFS
的cStor
来实现弹性。像Kafka
这样的流媒体应用程序可以在边缘环境中使用NVMe
引擎Mayastor
以获得最佳性能。
驱使用户使用 OpenEBS
的主要原因是 :
-
在所有的
Kubernetes
发行版上都是可移植的 -
提高了开发人员和平台
SRE
的生产力 -
与其他解决方案相比,易于使用
-
优秀的社区支持
-
免费开源
本地卷类型
本地卷只能从集群中的单个节点访问。必须在提供卷的节点上调度使用 Local Volume
的 Pods
。本地卷通常是分布式工作负载的首选,比如 Cassandra
、MongoDB
、Elastic
等,这些工作负载本质上是分布式的,并且内置了高可用性(分片)
根据附加到 Kubernetes
工作节点上的存储类型,您可以从不同的动态本地 PV
进行选择——Hostpath
、Device
、LVM
、ZFS
或 Rawfile
可复制卷类型
复制卷
顾名思义,是指将数据同步复制到多个节点的卷。卷可以支持节点故障。还可以跨可用性区域设置复制,以帮助应用程序跨可用性区域移动。
复制卷还能够提供像快照、克隆、卷扩展等企业存储特性。复制卷是有状态工作负载 (如 Percona/MySQL
、Jira
、GitLab
等) 的首选。
根据附加到 Kubernetes
工作节点的存储类型和应用程序性能需求,您可以从 Jiva、cStor
或 Mayastor
中进行选择
OpenEBS 存储引擎建议
应用需求 | 存储类型 | OpenEBS 卷类型 |
---|---|---|
低时延、高可用性、同步复制、快照、克隆、精简配置 | SSD/ 云存储卷 | OpenEBS Mayastor |
高可用性、同步复制、快照、克隆、精简配置 | 机械 /SSD/ 云存储卷 | OpenEBS cStor |
高可用性、同步复制、精简配置 | 主机路径或外部挂载存储 | OpenEBS Jiva |
低时延、本地 PV | 主机路径或外部挂载存储 | Dynamic Local PV – Hostpath, Dynamic Local PV – Rawfile |
低时延、本地 PV | 本地机械 /SSD/ 云存储卷等块设备 | Dynamic Local PV – Device |
低延迟,本地 PV,快照,克隆 | 本地机械 /SSD/ 云存储卷等块设备 | OpenEBS Dynamic Local PV – ZFS , OpenEBS Dynamic Local PV – LVM |
总结:
-
多机环境,如果有额外的块设备(非系统盘块设备)作为数据盘,选用
OpenEBS Mayastor
、OpenEBS cStor
-
多机环境,如果没有额外的块设备(非系统盘块设备)作为数据盘,仅单块系统盘块设备,选用
OpenEBS Jiva
-
单机环境,建议本地路径
Dynamic Local PV - Hostpath, Dynamic Local PV - Rawfile
,由于单机多用于测试环境,数据可靠性要求较低。
由此看来,OpenEBS
常用场景为以上三个场景
OpenEBS 特性
容器附加存储
OpenEBS
是一个容器附加存储 (Container Attached Storage, CAS
) 的例子。通过 OpenEBS
提供的卷总是被容器化。每个卷都有一个专用的存储控制器,用于提高有状态应用程序的持久性存储操作的敏捷性和粒度。
同步复制
同步复制是 OpenEBS
的一个可选的流行特性。当与 Jiva
、cStor
和 Mayastor
存储引擎一起使用时,OpenEBS
可以同步复制数据卷以实现高可用性。跨 Kubernetes
区域进行复制,从而为跨 AZ
设置提供高可用性。这个特性对于使用 GKE、EKS
和 AKS
等云提供商服务上的本地磁盘构建高可用状态应用程序特别有用
快照和克隆
写时拷贝快照是 OpenEBS
另一个可选的流行特性。使用 cStor
引擎时,快照是瞬时创建的,并且不受快照个数的限制。增量快照功能增强了跨 Kubernetes
集群和跨不同云提供商或数据中心的数据迁移和可移植性。对快照和克隆的操作完全以 Kubernetes
原生方法执行,使用标准 kubectl
命令。常见的用例包括用于备份的高效复制和用于故障排除或针对数据的只读副本进行开发的克隆
备份和恢复
OpenEBS
卷的备份和恢复可以通过开源的 OpenEBS Velero
插件与 Kubernetes
备份和恢复解决方案 (如 Velero
(前身为 Heptio Ark
)) 协同工作。经常使用 OpenEBS
增量快照功能,将数据备份到 AWS S3、GCP object storage、MinIO
等对象存储目标。这种存储级别的快照和备份只使用增量数据进行备份,节省了大量的带宽和存储空间。
真正的 Kubernetes 云原生存储
OpenEBS
是 Kubernetes
上有状态应用程序的云原生存储,云原生
意味着遵循松散耦合的体系结构。因此,云原生、松散耦合体系结构的一般好处是适用的。例如,开发人员和 DevOps
架构师可以使用标准的 Kubernetes
技能和实用程序来配置、使用和管理持久存储需求
减少存储 TCO 高达 50%
在大多数云上,块存储的收费是基于购买的多少,而不是使用的多少 ; 为了实现更高的性能,并在充分利用容量时消除中断的风险,容量经常被过度配置。OpenEBS
的精简配置能力可以共享本地存储或云存储,然后根据需要增加有状态应用程序的数据量。可以动态添加存储,而不会中断暴露给工作负载或应用程序的卷。某些用户报告说,由于使用了 OpenEBS
的精简配置,节省了超过 60%
的资源。
高可用性
由于 OpenEBS
遵循 CAS
架构,在节点故障时,Kubernetes
将重新调度 OpenEBS
控制器,而底层数据则通过使用一个或多个副本来保护。更重要的是——因为每个工作负载都可以利用自己的 OpenEBS
——不存在因存储丢失而导致系统大范围宕机的风险。例如,卷的元数据不是集中的,它可能会像许多共享存储系统那样受到灾难性的通用中断的影响。相反,元数据保持在卷的本地。丢失任何节点都会导致只存在于该节点上的卷副本的丢失。由于卷数据至少在其他两个节点上进行了同步复制,因此当一个节点出现故障时,这些数据将在相同的性能级别上继续可用
CAS 介绍
在 CAS
或容器附加存储 (Container Attached Storage
) 体系结构中,存储在容器中运行,并且与存储绑定到的应用程序密切相关。存储作为微服务运行,没有内核模块依赖关系。像 Kubernetes
这样的编排系统编排存储卷,就像任何其他微服务或容器一样。CAS
具有 DAS
和 NAS
的优点
非 CAS 系统上的 PV
在非 CAS
模型中,Kubernetes
持久卷仍然与内核模块紧密耦合,使得 Kubernetes
节点上的存储软件本质上是单片的
基于 CAS 系统上的 PV
相反,CAS
使您能够利用云原生应用程序的灵活性和可伸缩性。定义 Kubernetes PV (Persistent Volume)
的存储软件是基于微服务架构的。存储软件的控制平面 (存储控制器) 和数据平面 (存储副本) 作为 Kubernetes Pods
运行,因此,使您能够将云原生的所有优势应用到 CAS
。
CAS 优势
-
敏捷
CAS
中的每个存储卷都有一个容器化的存储控制器和相应的容器化副本。因此,围绕这些组件的资源的维护和调优是真正敏捷的。Kubernetes
滚动升级功能可以实现存储控制器和存储副本的无缝升级。可以使用容器 cGroups
调优 CPU
和内存等资源配额。
-
存储策略粒度化
将存储软件容器化并将存储控制器专用于每个卷可以带来最大的存储策略粒度。在 CAS
体系结构中,可以按卷配置所有存储策略。此外,您可以监视每个卷的存储参数,并动态更新存储策略,以实现每个工作负载的预期结果。随着卷存储策略中这种额外粒度级别的增加,存储吞吐量、IOPS
和延迟的控制也会增加。
-
云原生
CAS
将存储软件装入容器,并使用 Kubernetes
自定义资源定义 (CRDs
) 来声明低级存储资源,如磁盘和存储池。这个模型使存储能够无缝地集成到其他云原生工具中。可以使用 Prometheus、Grafana、Fluentd、Weavescope、Jaeger
等云原生工具来供应、监控和管理存储资源
-
PV
是CAS
中的一个微服务
如上图所示,在 CAS
架构中,存储控制器和副本的软件完全是基于微服务的,因此不涉及内核组件。通常,存储控制器 POD
被调度在与持久卷相同的节点上,以提高效率,副本 POD
可以被调度在集群节点上的任何位置。每个副本使用本地磁盘、SAN
磁盘和云磁盘的任意组合完全独立于其他副本进行配置。这为大规模管理工作负载的存储分配提供了巨大的灵活性。
-
超融合非分布式
CAS
架构没有遵循典型分布式存储架构。通过从存储控制器到存储副本的同步复制,存储变得高度可用。卷副本的元数据不是在节点之间共享的,而是在每个本地节点上独立管理。如果一个节点故障,存储控制器 (在本例中是一个无状态容器) 将在一个节点上轮转,该节点上运行着第二个或第三个副本,数据仍然可用。
与超融合系统类似,CAS
中的卷的存储和性能是可扩展的。由于每个卷都有自己的存储控制器,因此存储可以在一个节点的存储容量允许的范围内进行扩展。在给定的 Kubernetes
集群中,随着容器应用程序数量的增加,会增加更多的节点,从而提高存储容量和性能的整体可用性,从而使存储对新的应用程序容器可用。这一过程与 Nutanix
等成功的超融合系统非常相似。
OpenESB 架构介绍
OpenESB
遵循容器附加存储(CAS
)模型,每个卷都有一个专用的控制器 POD
和一组副本 POD
。CAS
体系结构的优点在`CNCF` 博客[1] 上进行了讨论。OpenEBS
操作和使用都很简单,因为它看起来和感觉上就像其他云原生和 Kubernetes
友好的项目。
OpenEBS
有许多组件,可以分为以下类别 :
-
控制面组件 –
Provisioner
,API Server
,volume exports
,volume sidecars
-
数据面组件 –
Jiva
、cStor
-
节点磁盘管理器 –
Discover
,monitor
, 管理连接k8s
的媒介 -
与云原生工具的集成 – 已经与
Prometheus
,Grafana
,Fluentd
、Jaeger
集成
控制面
OpenEBS
集群的控制平面通常被称为Maya
。
OpenEBS
控制平面负责提供卷、相关的卷操作,如快照、克隆、创建存储策略、执行存储策略、导出 Prometheus/grafana
使用的卷指标,等等。
OpenEBS
提供了一个动态提供程序,这是 Kubernetes
的标准外部存储插件。OpenEBS PV
提供者的主要任务是向应用程序 PODS
启动卷供应,并实现 PV
的 Kubernetes
规范。
m-apiserver
开放存储的 REST API
,并承担大量卷策略处理和管理工作。
控制平面和数据平面之间的连通性使用 Kubernetes sidecar
模式。控制平面需要与数据平面通信的场景如下所示。
-
对于卷的统计,如
IOPS
,吞吐量,延迟等–通过卷暴漏的sidecar
实现 -
使用卷控制器
pod
执行卷策略,使用卷副本pod
进行磁盘 / 池管理-通过卷管理sidecar
实现
OpenEBS PV Provisioner
此组件作为 POD
运行,并做出配置决策 , 它的使用方式是 :
开发人员用所需的卷参数构造一个声明,选择适当的存储类,并在 YAML
规范上调用 kubelet
。OpenEBS PV
动态提供程序与 maya-apiserver
交互,在适当的节点上为卷控制器 pod
和卷副本 pod
创建部署规范。可以使用 PVC
规范中的注释来控制卷 Pod
(控制器 / 副本) 的调度。
目前,OpenEBS Provisioner
只支持一种绑定类型,即 iSCSI
。
Maya-ApiServer
m-apiserver作为
POD运行。顾名思义,
m-apiserver公开
OpenEBS REST api`。
m-apiserver
还负责创建创建卷 pod
所需的部署规范文件。在生成这些规范文件之后,它将调用 kube-apiserver
来相应地调度这些 pods
。OpenEBS PV
提供者在卷发放结束时,将创建一个 PV
对象并将其挂载到应用程序 pod
上。PV
由控制器 pod
承载,控制器 pod
由不同节点中的一组副本 pod
支持。控制器 pod
和复制 pod
是数据平面的一部分,在存储引擎部分有更详细的描述。
m-apiserver
的另一个重要任务是卷策略管理。OpenEBS
为表示策略提供了非常细粒度的规范。m-apiserver
解释这些 YAML
规范,将它们转换为可执行的组件,并通过容量管理 sidecar
来执行它们
Maya Volume Exporter
Maya卷导出器是每个存储控制器
pod的
sidecar`。
这些 sidecar
将控制平面连接到数据平面以获取统计信息。统计信息的粒度在卷级别。一些统计数据示例如下:
-
卷读取延迟
-
卷写入延迟
-
卷每秒读取速度
-
卷每秒写入速度
-
读取块大小
-
写入块大小
-
容量统计
这些统计信息通常由 Prometheus
客户端来拉取,该客户端在 OpenBS
安装期间安装和配置。
卷管理 sidecar
Sidecars
还用于将控制器配置参数和卷策略传递给卷控制器 pod
(卷控制器 pod
是一个数据平面), 并将副本配置参数和副本数据保护参数传递给卷副本 pod
。
数据面
OpenEBS
数据平面负责实际的卷 IO
路径。存储引擎在数据平面实现实际的 IO
路径。目前,OpenEBS
提供了两个可以轻松插入的存储引擎。它们被称为 Jiva
和 cStor
。这两个存储引擎都完全运行在 Linux
用户空间中,并基于微服务架构。
Jiva
Jiva
存储引擎基于 Rancher's LongHorn
与 gotgt
开发实现, 使用 go
语言开发,并运行于用户命名空间下。LongHorn
控制器将输入的 IO
同步复制到 LongHorn
副本。该副本将 Linux
稀疏文件视为构建存储特性 (如精简配置、快照、重建等) 的基础。
cStor
cStor
数据引擎使用 C
语言编写,具有高性能的 iSCSI target
和 Copy-On-Write
块系统,提供数据完整性、数据弹性和时间点的快照和克隆。cStor
有一个池特性,它以条带、镜像或 RAIDZ
模式聚合一个节点上的磁盘,以提供更大的容量和性能单位。cStor
还可以跨区域将数据同步复制到多个节点,从而避免节点丢失或节点重启导致数据不可用。
LocalPV
对于那些不需要存储级复制的应用程序,LocalPV
可能是很好的选择,因为它能提供更高的性能。OpenEBS LocalPV
与 Kubernetes LocalPV
类似,不同之处在于它是由 OpenEBS
控制平面动态提供的, 就像任何其他常规 PV
一样。OpenEBS LocalPV
有两种类型 :hostpath LocalPV
和 device LocalPV
。hostpath LocalPV
指的是主机上的子目录,LocalPV
指的是在节点上发现的磁盘 (可以是直接连接的,也可以是网络连接的)。OpenEBS
引入了一个 LocalPV
提供者,用于根据 PVC
和存储类规范中的一些标准选择匹配的磁盘或主机路径。
节点磁盘管理器
节点磁盘管理器 (NDM
) 填补了使用 Kubernetes
管理有状态应用程序的持久存储所需的工具链的空白。容器时代的 DevOps
架构师必须以一种自动化的方式满足应用程序和应用程序开发人员的基础设施需求, 这种方式可以跨环境提供弹性和一致性。这些要求意味着存储堆栈本身必须非常灵活, 以便 Kubernetes
和云原生生态系统中的其他软件可以轻松地使用这个堆栈。NDM
在 Kubernetes
的存储堆栈中起着基础性的作用,它统一了不同的磁盘, 并通过将它们标识为 Kubernetes
对象,提供了将它们汇聚的能力。此外,NDM
发现、提供、监视和管理底层磁盘的方式,可以让 Kubernetes PV
提供者 (如 OpenEBS
和其他存储系统) 和 Prometheus
管理磁盘子系统
CAS 引擎
存储引擎概述
存储引擎是持久化卷 IO
路径的数据平面组件。在 CAS
架构中,用户可以根据不同的配置策略,为不同的应用工作负载选择不同的数据平面。存储引擎可以通过特性集或性能优化给定的工作负载。
操作员或管理员通常选择具有特定软件版本的存储引擎,并构建优化的卷模板, 这些卷模板根据底层磁盘的类型、弹性、副本数量和参与 Kubernetes
集群的节点集进行微调。用户可以在发放卷时选择最优的卷模板,从而在给定的 Kubernetes
集群上为所有存储卷运行最优的软件和存储组合提供最大的灵活性。
存储引擎类型
OpenEBS
提供了三种存储引擎
-
Jiva
Jiva
是OpenEBS 0.1
版中发布的第一个存储引擎,使用起来最简单。它基于GoLang
开发,内部使用LongHorn
和gotgt
堆栈。Jiva
完全在用户空间中运行,并提供同步复制等标准块存储功能。Jiva
通常适用于容量较小的工作负载,不适用于大量快照和克隆特性是主要需求的情况 -
cStor
cStor
是OpenEBS 0.7
版本中最新发布的存储引擎。cStor
非常健壮,提供数据一致性,很好地支持快照和克隆等企业存储特性。 它还提供了一个健壮的存储池特性,用于在容量和性能方面进行全面的存储管理。cStor
与NDM
(Node Disk Manager
) 一起,为Kubernetes
上的有状态应用程序提供完整的持久化存储特性 -
OpenEBS Local PV
OpenEBS Local PV
是一个新的存储引擎,它可以从本地磁盘或工作节点上的主机路径创建持久卷或PV
。CAS
引擎可以从OpenEBS
的1.0.0
版本中获得。使用OpenEBS Local PV
,性能将等同于创建卷的本地磁盘或文件系统 (主机路径)。 许多云原生应用程序可能不需要复制、快照或克隆等高级存储特性,因为它们本身就提供了这些特性。这类应用程序需要以持久卷的形式访问管理的磁盘
-
SP
存储池,表示Jiva
自定义存储资源 -
CV
cStor
卷,表示cStor
卷自定义资源 -
CVR
cStor
卷副本 -
SPC
存储池声明,表示cStor
池聚合的自定义资源 -
CSP
cStor
存储池,表示cStor Pool
每个节点上的自定义资源
一个 SPC
对应多个 CSP
,相应的一个 CV
对应多个 CVR
存储引擎声明
通过指定注释 openebs
来选择存储引擎。StorageClass
规范中的 io/cas-type
。StorageClass
定义了提供程序的细节。为每个 CAS
引擎指定单独的供应程序。
cStor 存储类规范文件内容
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: cStor-storageclassannotations:openebs.io/cas-type: cstorcas.openebs.io/config: |- name: StoragePoolClaimvalue: "cStorPool-SSD"
provisioner: openebs.io/provisioner-iscsi
---
Jiva 存储类规范文件内容
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: jiva-storageclassannotations:openebs.io/cas-type: jivacas.openebs.io/config: |- name: StoragePoolvalue: default
provisioner: openebs.io/provisioner-iscsi
---
当 cas
类型为 Jiva
时,StoragePool
的 default
值具有特殊含义。当 pool
为默认值时,Jiva
引擎将从容器 (副本 pod
) 本身的存储空间中为副本 pod
开辟数据存储空间。当所需的卷大小很小 (比如 5G
到 10G
) 时,StoragePool default
工作得很好,因为它可以容纳在容器本身内。
Local PV 存储类规范文件内容-主机路径
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: localpv-hostpath-scannotations:openebs.io/cas-type: localcas.openebs.io/config: |- name: BasePathvalue: "/var/openebs/local"- name: StorageTypevalue: "hostpath"
provisioner: openebs.io/local
---
Local PV 存储类规范文件内容-主机设备
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: localpv-device-scannotations:openebs.io/cas-type: localcas.openebs.io/config: |- name: StorageTypevalue: "device"- name: FSTypevalue: ext4
provisioner: openebs.io/local
---
cStor
、Jiva
、LocalPV
特性比较:
特性 | Jiva | cStor | Local PV |
---|---|---|---|
轻量级运行于用户空间 | Yes | Yes | Yes |
同步复制 | Yes | Yes | No |
适合低容量工作负载 | Yes | Yes | Yes |
支持快照,克隆 | Basic | Advanced | No |
数据一致性 | Yes | Yes | NA |
使用 Velero 恢复备份 | Yes | Yes | Yes |
适合高容量工作负载 | No | Yes | Yes |
自动精简配置 | Yes | No | |
磁盘池或聚合支持 | Yes | No | |
动态扩容 | Yes | Yes | |
数据弹性 (RAID 支持) | Yes | No | |
接近原生磁盘性能 | No | No | Yes |
大多数场景推荐 cStor
,因其提供了强大的功能,包括快照 / 克隆、存储池功能(如精简资源调配、按需扩容等)。
Jiva
适用于低容量需求的工作负载场景,例如 5
到 50G
。尽管使用 Jiva
没有空间限制,但建议将其用于低容量工作负载。Jiva
非常易于使用,并提供企业级容器本地存储,而不需要专用硬盘。有快照和克隆功能的需求的场景,优先考虑使用 cStor
而不是 Jiva
。
CAS 引擎使用场景
如上表所示,每个存储引擎都有自己的优势。选择引擎完全取决于应用程序的工作负载以及它当前和未来的容量和 / 或性能增长。下面的指导原则在定义存储类时为选择特定的引擎提供一些帮助。
选择 cStor 的理想条件
-
当需要同步复制数据并在节点上有多个磁盘时
-
当您从每个节点上的本地磁盘或网络磁盘池管理多个应用程序的存储时。通过精简配置、存储池和卷的按需扩容、存储池的性能按需扩容等特性,实现对存储层的管理。
cStor
用于在本地运行的Kubernetes
集群上构建Kubernetes
本地存储服务,类似于AWS EBS
或谷歌PD
。 -
当需要存储级快照和克隆能力时
-
当您需要企业级存储保护特性,如数据一致性、弹性 (
RAID
保护)。 -
如果您的应用程序不需要存储级复制,那么使用
OpenEBS
主机路径LocalPV
或OpenEBS
设备LocalPV
可能是更好的选择。
选择 Jiva 的理想条件 :
-
当您想要数据的同步复制,并且拥有单个本地磁盘或单个管理磁盘 (如云磁盘 (
EBS
、GPD
)),并且不需要快照或克隆特性时 -
Jiva
是最容易管理的,因为磁盘管理或池管理不在这个引擎的范围内。Jiva
池是本地磁盘、网络磁盘、虚拟磁盘或云磁盘的挂载路径。 -
以下场景 Jiva 更优于 cStor :
-
当程序不需要存储级的快照、克隆特性
-
当节点上没有空闲磁盘时。
Jiva
可以在主机目录上使用,并且仍然可以实现复制。 -
当不需要动态扩展本地磁盘上的存储时。将更多磁盘添加到
Jiva
池是不可能的,因此Jiva
池的大小是固定的,如果它在物理磁盘上。但是,如果底层磁盘是虚拟磁盘、网络磁盘或云磁盘,则可以动态地更改Jiva
池的大小 -
容量需求较小。大容量应用通常需要动态增加容量,
cStor
更适合这种需求
-
选择 OpenEBS 主机路径 LocalPV 的理想条件 :
-
当应用程序本身具备管理复制能力(例如:
es
)时,不需要在存储层进行复制。在大多数这样的情况下,应用程序是作为statefulset
部署的 -
高于
Jiva
与cStor
的读写性能需求 -
当特定应用程序没有专用的本地磁盘或特定应用程序不需要专用的存储时,建议使用
Hostpath
。如果您想跨多个应用程序共享一个本地磁盘,主机路径LocalPV
是正确的方法
选择 OpenEBS 主机设备 LocalPV 的理想条件 :
-
当应用程序管理复制本身,不需要在存储层进行复制时。在大多数这种情况下,应用程序被部署为有状态集
-
高于
Jiva
与cStor
的读写性能需求 -
高于
OpenEBS
主机路径LocalPV
的读写性能需求 -
当需要接近磁盘性能时。该卷专用于写入单个
SSD
或NVMe
接口以获得最高性能
总结
-
如果应用程序处于生产中,并且不需要存储级复制,那么首选
LocalPV
-
如果您的应用程序处于生产状态,并且需要存储级复制,那么首选
cStor
-
如果应用程序较小,需要存储级复制,但不需要快照或克隆,则首选
Jiva
节点磁盘管理器(NDM)
节点磁盘管理器 (NDM
) 是 OpenEBS
体系结构中的一个重要组件。NDM
将块设备视为需要监视和管理的资源,就像 CPU
、内存和网络等其他资源一样。它是一个在每个节点上运行的守护进程,基于过滤器检测附加的块设备,并将它们作为块设备自定义资源加载到 Kubernetes
中。这些定制资源旨在通过提供类似于 :
-
轻松访问
Kubernetes
集群中可用的块设备清单 -
预测磁盘的故障,以帮助采取预防措施
-
允许动态地将磁盘挂载 / 卸载到存储
Pod
中,而无需重新启动在磁盘挂载 / 卸载的节点上运行的相应NDM Pod
尽管做了上述所有工作,NDM
还是有助于提供持久卷的总体简化。
NDM
是在 OpenEBS
安装期间作为守护进程部署的。NDM daemonset
发现每个节点上的磁盘,并创建一个名为 Block Device
或 BD
的自定义资源。
访问权限说明
NDM
守护进程运行在容器中,必须访问底层存储设备并以特权模式运行。NDM
需要特权模式,因为它需要访问 /dev、/proc
和 /sys
目录来监视附加设备,还需要使用各种探测器获取附加设备的详细信息。NDM
负责发现块设备并过滤掉不应该被 OpenEBS
使用的设备 ; 例如,检测有 OS
文件系统的磁盘。NDM pod
默认情况下在容器中挂载主机的 /proc
目录,然后加载 /proc/1/mounts
,以找到操作系统使用的磁盘
NDM 守护程序功能
-
发现
Kubernetes
节点上的块设备-
在启动时发现块设备-创建和 / 或更新状态。
-
维护集群范围内磁盘的唯一
id
: 对WWN / PartitionUUID / FileSystemUUID / DeviceMapperUUID
进行Hash
计算
-
-
检测节点中添加 / 移除块设备,并更新块设备状态
-
添加块设备作为
Kubernetes
自定义资源,具有以下属性:-
Active
: 节点上存在块设备 -
Inactive
: 给定节点上不存在块设备 -
Unknown
:NDM
在块设备最后被检测到的节点上停止 / 无法确定状态 -
主机名称 (
kubernetes.io/hostname
) -
块设备类型 (
ndm.io/blockdevice-type
) -
Managed (
ndm.io/managed
) -
设备路径
-
设备链接
-
供应商和型号信息
-
WWN
和序列号 -
容量
-
扇区和区块大小
-
spec
: 如果可用,将更新以下内容 -
labels
: -
status
: 状态可以有以下值
-
过滤器
-
为要创建块设备
CR
的块设备类型配置过滤器。过滤器可以通过供应商类型、设备路径模式或挂载点进行配置 -
过滤器可以是包含过滤器,也可以是排除过滤器。它们被配置为
configmap
。管理员用户可以在OpenEBS
安装时通过更改OpenEBS
操作员yaml
文件或helm
值中的NDM configmap
来配置这些过滤器。yaml
文件。如果这些过滤器需要在安装后更新,那么可以遵循以下方法之一 :-
使用
operator
方式安装OpenEBS
。在Yaml
文件中,更新configmap
中的过滤器并应用operator.yaml
-
如果
OpenEBS
是使用helm
安装的,更新values.yaml
中的configmap
并使用helm
进行升级 -
或者,使用
kubectl
编辑NDM configmap
,更新过滤器
-
落地实践
OpenEBS
的 cStor
与 Jiva
引擎由于组件过多,配置相较其他存储方案繁琐,生产环境不建议使用,这里我们仅论述 Local PV
引擎。
Local PV
引擎不具备存储级复制能力,适用于 k8s
有状态服务的后端存储(如 : es
、redis
等)
Local PV Hostpath 实践
对比 Kubernetes Hostpath
卷相比,OpenEBS 本地 PV Hostpath
卷具有以下优势 :
-
OpenEBS
本地PV Hostpath
允许您的应用程序通过StorageClass
、PVC
和PV
访问Hostpath
。这为您提供了更改PV
提供者的灵活性,而无需重新设计应用程序YAML
-
使用
Velero
备份和恢复进行数据保护 -
通过对应用程序
YAML
和pod
完全屏蔽主机路径来防范主机路径安全漏洞
环境依赖 :
-
k8s 1.12
以上 -
OpenEBS 1.0
以上
实践环境 :
-
docker 19.03.8
-
k8s 1.18.6
-
CentOS7
$ kubectl get node
NAME STATUS ROLES AGE VERSION
node1 Ready master,worker 8m8s v1.18.6
node2 Ready master,worker 7m15s v1.18.6
node3 Ready master,worker 7m15s v1.18.6
创建数据目录
在将要创建 Local PV Hostpaths
的节点上设置目录。这个目录将被称为 BasePath
。默认位置是 /var/openebs/local
节点 node1
、node2
、node3
创建 /data/openebs/local
目录 (/data 可以预先挂载数据盘,如未挂载额外数据盘,则使用操作系统 '/' 挂载点存储空间)
$ mkdir -p /data/openebs/local
下载应用描述文件
yaml 文件[2]
发布 openebs
应用
根据上述配置文件,保证 k8s
集群可访问到如下镜像(建议导入本地私有镜像库,如 : harbor
)
openebs/node-disk-manager:1.5.0
openebs/node-disk-operator:1.5.0
openebs/provisioner-localpv:2.10.0
更新 openebs-operator.yaml
中镜像 tag
为实际 tag
image: openebs/node-disk-manager:1.5.0
image: openebs/node-disk-operator:1.5.0
image: openebs/provisioner-localpv:2.10.0
发布
$ kubectl apply -f openebs-operator.yaml
查看发布状态
$ kubectl get pod -n openebs -w
NAME READY STATUS RESTARTS AGE
openebs-localpv-provisioner-6d6d9cfc99-4sltp 1/1 Running 0 10s
openebs-ndm-85rng 1/1 Running 0 10s
openebs-ndm-operator-7df6668998-ptnlq 0/1 Running 0 10s
openebs-ndm-qgqm9 1/1 Running 0 10s
openebs-ndm-zz7ps 1/1 Running 0 10s
创建存储类
更改配置文件中的内容
value: "/var/openebs/local/"
发布创建存储类
$ cat > openebs-hostpath-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: openebs-hostpathannotations:openebs.io/cas-type: localcas.openebs.io/config: |#hostpath type will create a PV by# creating a sub-directory under the# BASEPATH provided below.- name: StorageTypevalue: "hostpath"#Specify the location (directory) where# where PV(volume) data will be saved.# A sub-directory with pv-name will be# created. When the volume is deleted,# the PV sub-directory will be deleted.#Default value is /var/openebs/local- name: BasePathvalue: "/data/openebs/local/"
provisioner: openebs.io/local
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
EOF$ kubectl apply -f openebs-hostpath-sc.yaml
创建 PVC 验证可用性
$ cat > local-hostpath-pvc.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: local-hostpath-pvc
spec:storageClassName: openebs-hostpathaccessModes:- ReadWriteOnceresources:requests:storage: 5G
EOF$ kubectl apply -f local-hostpath-pvc.yaml
查看 pvc
状态
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
local-hostpath-pvc Pending openebs-hostpath 2m15s
输出显示 STATUS
为 Pending
。这意味着 PVC
还没有被应用程序使用。
创建 Pd
$ cat > local-hostpath-pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:name: hello-local-hostpath-pod
spec:volumes:- name: local-storagepersistentVolumeClaim:claimName: local-hostpath-pvccontainers:- name: hello-containerimage: busyboxcommand:- sh- -c- 'while true; do echo "`date` [`hostname`] Hello from OpenEBS Local PV." >> /mnt/store/greet.txt; sleep $(($RANDOM % 5 + 300)); done'volumeMounts:- mountPath: /mnt/storename: local-storage
EOF
发布创建
$ kubectl apply -f local-hostpath-pod.yaml
验证数据是否写入卷
$ kubectl exec hello-local-hostpath-pod -- cat /mnt/store/greet.txt
Thu Jun 24 15:10:45 CST 2021 [node1] Hello from OpenEBS Local PV.
验证容器是否使用 Local PV Hostpath 卷
$ kubectl describe pod hello-local-hostpath-pod
Name: hello-local-hostpath-pod
Namespace: default
Priority: 0
...
Volumes:local-storage:Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)ClaimName: local-hostpath-pvcReadOnly: falsedefault-token-98scc:Type: Secret (a volume populated by a Secret)SecretName: default-token-98sccOptional: false
...
查看 PVC 状态
$ kubectl get pvc local-hostpath-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
local-hostpath-pvc Bound pvc-6eac3773-49ef-47af-a475-acb57ed15cf6 5G RWO openebs-hostpath 10m
查看该 PV 卷数据存储目录为
$ kubectl get -o yaml pv pvc-6eac3773-49ef-47af-a475-acb57ed15cf6|grep 'path:'f:path: {}path: /data/openebs/local/pvc-6eac3773-49ef-47af-a475-acb57ed15cf6
并且 pv
配置了亲和性,制定了调度节点为 node2
spec:accessModes:- ReadWriteOncecapacity:storage: 5GclaimRef:apiVersion: v1kind: PersistentVolumeClaimname: local-hostpath-pvcnamespace: defaultresourceVersion: "9034"uid: 6eac3773-49ef-47af-a475-acb57ed15cf6local:fsType: ""path: /data/openebs/local/pvc-6eac3773-49ef-47af-a475-acb57ed15cf6nodeAffinity:required:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node2persistentVolumeReclaimPolicy: DeletestorageClassName: openebs-hostpathvolumeMode: Filesystem
结果证明数据仅存在于 node2
下。
清理 Pod
$ kubectl delete pod hello-local-hostpath-pod
基准测试
下载基准测试 Job 声明文件[3]
调整以下内容
image: openebs/perf-test:latest # 调整为内网镜像库tag
claimName: dbench # 调整为local-hostpath-pvc
发布运行
$ kubectl create -f fio-deploy.yaml
查看运行状态
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
dbench-729cw-nqfpt 1/1 Running 0 24s
查看基准测试结果
$ kubectl logs -f dbench-729cw-nqfpt
...
All tests complete.==================
= Dbench Summary =
==================
Random Read/Write IOPS: 2144/6654. BW: 131MiB/s / 403MiB/s
Average Latency (usec) Read/Write: 4254.08/3661.59
Sequential Read/Write: 1294MiB/s / 157MiB/s
Mixed Random Read/Write IOPS: 1350/443
清理
$ kubectl delete pvc local-hostpath-pvc
$ kubectl delete sc openebs-hostpath
Local PV Device 实践
对比 Kubernetes
本地持久卷,OpenEBS
本地 PV
设备卷有以下优点 :
-
OpenEBS
本地PV
设备卷provider
是动态的,Kubernetes
设备卷provider
是静态的 -
OpenEBS NDM
更好地管理用于创建本地pv
的块设备。NDM
提供了发现块设备属性、设置设备筛选器、度量集合以及检测块设备是否已经跨节点移动等功能
环境依赖 :
-
k8s 1.12
以上 -
OpenEBS 1.0
以上
实践环境 :
-
docker 19.03.8
-
k8s 1.18.6
-
CentOS7
$ kubectl get node
NAME STATUS ROLES AGE VERSION
node1 Ready master,worker 8m8s v1.18.6
node2 Ready master,worker 7m15s v1.18.6
node3 Ready master,worker 7m15s v1.18.6
三个节点上的 /dev/sdb
作为块设备存储
[root@node1 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part└─centos-root 253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.4G 0 rom[root@node2 ~]# lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTsda 8:0 0 400G 0 disk├─sda1 8:1 0 1G 0 part /boot└─sda2 8:2 0 399G 0 part└─centos-root 253:0 0 399G 0 lvm /sdb 8:16 0 20G 0 disksr0 11:0 1 4.4G 0 rom[root@node3 ~]# lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTsda 8:0 0 400G 0 disk├─sda1 8:1 0 1G 0 part /boot└─sda2 8:2 0 399G 0 part└─centos-root 253:0 0 399G 0 lvm /sdb 8:16 0 20G 0 disksr0 11:0 1 4.4G 0 rom
创建数据目录
在将要创建 Local PV Hostpaths
的节点上设置目录。这个目录将被称为 BasePath
。默认位置是 /var/openebs/local
节点 node1
、node2
、node3
创建 /data/openebs/local
目录 (/data 可以预先挂载数据盘,如未挂载额外数据盘,则使用操作系统 '/' 挂载点存储空间)
$ mkdir -p /data/openebs/local
下载应用描述文件
yaml 文件[4]
发布 openebs 应用
根据上述配置文件,保证 k8s
集群可访问到如下镜像(建议导入本地私有镜像库,如 : harbor
)
openebs/node-disk-manager:1.5.0
openebs/node-disk-operator:1.5.0
openebs/provisioner-localpv:2.10.0
更新 openebs-operator.yaml
中镜像 tag
为实际 tag
image: openebs/node-disk-manager:1.5.0
image: openebs/node-disk-operator:1.5.0
image: openebs/provisioner-localpv:2.10.0
发布
$ kubectl apply -f openebs-operator.yaml
查看发布状态
$ kubectl get pod -n openebs -w
NAME READY STATUS RESTARTS AGE
openebs-localpv-provisioner-6d6d9cfc99-4sltp 1/1 Running 0 10s
openebs-ndm-85rng 1/1 Running 0 10s
openebs-ndm-operator-7df6668998-ptnlq 0/1 Running 0 10s
openebs-ndm-qgqm9 1/1 Running 0 10s
openebs-ndm-zz7ps 1/1 Running 0 10s
创建存储类
$ cat > local-device-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: local-deviceannotations:openebs.io/cas-type: localcas.openebs.io/config: |- name: StorageTypevalue: device
provisioner: openebs.io/local
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
EOF$ kubectl apply -f local-device-sc.yaml
创建 Pod 及 PVC
$ cat > local-device-pod.yaml <<EOF
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: local-device-pvc
spec:storageClassName: local-deviceaccessModes:- ReadWriteOnceresources:requests:storage: 5G
---
apiVersion: v1
kind: Pod
metadata:name: hello-local-device-pod
spec:volumes:- name: local-storagepersistentVolumeClaim:claimName: local-device-pvccontainers:- name: hello-containerimage: busyboxcommand:- sh- -c- 'while true; do echo "`date` [`hostname`] Hello from OpenEBS Local PV." >> /mnt/store/greet.txt; sleep $(($RANDOM % 5 + 300)); done'volumeMounts:- mountPath: /mnt/storename: local-storage
EOF
发布
$ kubectl apply -f local-device-pod.yaml
查看 pod
状态
$ kubectl get pod hello-local-device-pod -w
NAME READY STATUS RESTARTS AGE
hello-local-device-pod 1/1 Running 0 9s
确认 pod
关联 pvc
是否为 local-device-pvc
$ kubectl describe pod hello-local-device-pod
Name: hello-local-device-pod
Namespace: default
Node: node2/192.168.1.112
...
Volumes:local-storage:Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)ClaimName: local-device-pvcReadOnly: false
...
观察到调度的节点为 node2
,确认 node2
节点 /dev/sdb
是否被使用
[root@node2 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part└─centos-root 253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.4G 0 rom
[root@node2 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part└─centos-root253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk /var/lib/kubelet/pods/266b7b14-5eb7-40ec-bccb-3ac189acf939/volumes/kubernetes.io~local-volume/pvc-9bd89019-13dc-4
sr0 11:0 1 4.4G 0 rom
确实被使用,OpenEBS
强大之处则在于此,极致的简洁。如上文我们讨论的那样,NDM
负责发现块设备并过滤掉不应该被 OpenEBS
使用的设备,例如,检测有 OS
文件系统的磁盘。
基准测试
创建基准测试 pvc
$ cat > dbench-pvc.yaml <<EOF
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: dbench
spec:storageClassName: local-deviceaccessModes:- ReadWriteOnceresources:requests:storage: 5GEOF
下载基准测试 Job 声明文件[5]
调整以下内容
image: openebs/perf-test:latest # 调整为内网镜像库tag
发布运行
$ kubectl create -f dbench-pvc.yaml
$ kubectl create -f fio-deploy.yaml
查看运行状态
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
dbench-vqk68-f9877 1/1 Running 0 24s
查看基准测试结果
$ kubectl logs -f dbench-vqk68-f9877
...All tests complete.==================
= Dbench Summary =
==================
Random Read/Write IOPS: 3482/6450. BW: 336MiB/s / 1017MiB/s
Average Latency (usec) Read/Write: 2305.77/1508.63
Sequential Read/Write: 6683MiB/s / 2312MiB/s
Mixed Random Read/Write IOPS: 3496/1171
从结果来看,相较 Local PV HostPath
模式性能翻倍
总结
在整个测试验证过程,OpenEBS
给我的感觉是:极简的操作,尤其 Local PV
引擎的部署使用。
但 OpenEBS
现阶段也存在一些不足:
-
cStor
与Jiva
数据面组件较多,配置较为繁琐(第一感觉概念性的组件过多,) -
cStor
与Jiva
部分组件创建依赖内部定义的镜像tag
,在离线环境下无法通过调整为私有库tag
导致组件无法成功运行 -
存储类型单一,多个引擎仅支持块存储类型,不支持原生多节点读写(需结合
NFS
实现),对比ceph
等稍显逊色
建议以下场景使用 OpenEBS
作为后端存储:
-
单机测试环境
-
多机实验 / 演示环境
引用链接
[1]
CNCF
博客: https://www.cncf.io/blog/2018/04/19/container-attached-storage-a-primer/
[2]
yaml 文件: https://openebs.github.io/charts/openebs-operator-lite.yaml
[3]
基准测试 Job 声明文件: https://github.com/openebs/performance-benchmark/blob/master/fio-benchmarks/fio-deploy.yaml
[4]
yaml 文件: https://openebs.github.io/charts/openebs-operator.yaml
[5]
基准测试 Job 声明文件: https://github.com/openebs/performance-benchmark/blob/master/fio-benchmarks/fio-deploy.yaml
Laf 是一个完全开源的云开发平台,可以在线编写、调试函数,不用重启服务,随时随地在 Web 上查看函数的运行日志,无需连接服务器,无需折腾数据库、对象存储、Nginx 等,可以随时随地上线应用,招之即来,挥之即去,随手发布!
Laf 可以帮助开发者拥有自己的云开发平台,让写代码像写博客一样简单,支持云函数/云数据库/对象存储,让前端秒变全栈,节省60%研发成本,实现0运维!
详情可参考这篇文章:👉云开发中的战斗机 Laf,让你像写博客一样写代码
对 Laf 感兴趣的可以扫码加入我们的技术交流群:
你可能还喜欢
点击下方图片即可阅读
Docker 出了个新玩意:软件物料清单
2022-05-19
Cilium 开源 Tetragon – 基于 eBPF 的安全可观测性 & 运行时增强
2022-05-18
云开发中的战斗机 Laf,让你像写博客一样写代码
2022-05-16
使用 Grafana 和 Loki 监控传说中的武当纵云梯
2022-05-15
云原生是一种信仰 🤘
关注公众号
后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!
点击 "阅读原文" 获取更好的阅读体验!
发现朋友圈变“安静”了吗?