PCon全球产品创新大会最新日程上线,这里直达 了解详情
写点什么

从入门到上手:什么是 K8S 持久卷?

  • 2021 年 6 月 27 日
  • 本文字数:5493 字

    阅读完需:约 18 分钟

从入门到上手:什么是K8S持久卷?

本文是介绍 Kubernetes 的基本概念的系列文章之一, 在第一篇文章中,我们简单介绍了持久卷(Persistent Volumes)。在本文中,我们将学习如何设置数据持久性,并将编写 Kubernetes 脚本以将我们的 Pod 连接到持久卷。在此示例中,将使用 Azure 文件存储(Azure File Storage)来存储来自我们 MongoDB 数据库的数据,但您可以使用任何类型的卷来实现相同的结果(例如 Azure Disk,GCE 持久磁盘,AWS 弹性块存储等)。


如果你想全面了解 K8S 其他概念的话,可以先查看此前发布的文章



请注意:本文提供的脚本不限定于某个平台,因此您可以使用其他类型的云提供商或使用具有 K3S 的本地集群实践本教程。本文建议使用 K3S,因为它非常轻,所有的依赖项被打包在单个二进制中包装大小小于 100MB。它也是一种高可用的认证的 Kubernetes 发行版,用于在资源受限环境中的生产工作负载。想了解更多信息,请查看官方文档:https://docs.rancher.cn/k3s/

前期准备

在开始本教程之前,请确保已安装 Docker。同时安装 Kubectl(如果没有,请访问以下链接安装:

https://kubernetes.io/docs/tasks/tools/#install-kubectl-on-windows


在 kubectl Cheat Sheet.中可以找到整个本教程中使用的 kubectl 命令:

https://kubernetes.io/docs/reference/kubectl/cheatsheet/


本教程中,我们将使用 Visual Studio Code,您也可以使用其他的编辑器。

Kubernetes 持久卷可以解决什么问题?


请记住,我们有一个节点(硬件设备或虚拟机)和在节点内部,我们有一个 Pod(或多个 Pod),在 Pod 中,我们有容器。Pod 的状态是暂时的,所以他们神出鬼没(时常会被删除或重新调度等)。在这种情况下,如果你想在 Pod 被删除之后已经保存其中的数据,你需要数据移动到 Pod 外部。这样它就可以独立于任何 Pod 存在。此外部位置称为卷,它是存储系统的抽象。使用卷,您可以在多个 Pod 保持持久化状态。

什么时候使用持久卷

当容器开始被广泛应用时,它们旨在支持无状态工作负载,其持久性数据存储在其他地方。从那时起,人们做了很多努力以支持容器生态系统中的有状态应用。


每个项目都需要某种数据持久性,因此,您通常需要一个数据库来存储数据。但在简洁的设计中,你不想依赖具体的实现;您想写一个尽可能可以重复使用和独立于平台的应用程序。


一直以来,始终需要向应用程序隐藏存储实现的详细信息。但现在,在云原生应用的时代,云提供商创建了的环境中,想要访问数据的应用程序或用户需要与特定存储系统集成。例如,许多应用程序直接使用特定存储系统,诸如 Amazon S3、AzureFile 或块存储等,这造成了不健康的依赖。Kubernetes 正在尝试通过创建一个名为持久卷的抽象来改变这一情况,它允许云原生应用程序连接到各种云存储系统,而无需与这些系统建立明确的依赖关系。这可以使云存储的消耗更加无缝和消除集成成本。它还可以更容易地迁移云并采用多云策略。


即使有时候,由于金钱,时间或人力等客观条件的限制,你需要做出一些妥协,将你的应用程序与特定的平台或提供商直接耦合,您应该尽量避免尽可能多的直接依赖项。从实际数据库实现中解耦应用程序的一种方法(还有其他解决方案,但这些解决方案更加复杂)是使用容器(和持久卷来防止数据丢失)。这样,您的应用程序将依赖于抽象而不是特定实现。


现在真正的问题是,我们是否应该总是使用带有持久性卷的容器化数据库,或者哪些存储系统类型不应该在容器中使用?


何时使用持久卷并没有通用的黄金法则,但作为起点,您应该考虑可扩展性和集群中节点丢失的处理。


根据可扩展性,我们可以有两种类型的存储系统:

  1. 垂直伸缩——包括传统的 RDMS 解决方案,例如 MySQL、PostgreSQL 以及 SQL Server

  2. 水平伸缩——包括“NoSQL”解决方案,例如 ElasticSearch 或基于 Hadoop 的解决方案


像 MySQL、Postgres、Microsoft SQL 等垂直伸缩的解决方案不应进入容器。这些数据库平台需要高 I / O、共享磁盘、块存储等,并且不能优雅地处理集群中的节点丢失,这通常发生在基于容器的生态系统中。


对于水平伸缩的应用程序(Elastic、Cassandra、Kafka 等),您应该使用容器,因为它们可以承受数据库集群中的节点丢失,并且数据库应用程序可以独立地再平衡。


通常,您可以并且应该分布式数据库容器化,这些数据库使用冗余存储技术,可以承受数据库集群中的节点丢失(Elasticsearch 是一个非常好的例子)。

Kubernetes 持久卷的类型

我们可以根据其生命周期和配置方式对 Kubernetes 卷进行分类。


考虑到卷的生命周期,我们可以分为:


  • 临时卷,即与节点的生命周期紧密耦合(例如 ExpertDir 或 HostPath),如果节点倒闭,则删除它们的截阵数量。

  • 持久卷,即长期存储,并且与 Ppd 或节点生命周期无关。这些可以是云卷(如 gcePersistentDisk、awselasticBlockStore、AzureFile 或 AzureDisk),NFS(网络文件系统)或 Persistent Volume Claim(一系列抽象来连接到底层云提供存储卷)。


根据卷的配置方式,我们可以分为:

  1. 直接访问

  2. 静态配置

  3. 动态配置

直接访问持久卷


在这种情况下,Pod 将直接与 Volume 耦合,因此它将知道存储系统(例如,Pod 将与 Azure 存储帐户耦合)。该解决方案与云无关,它取决于具体实施而不是抽象。因此,如果可能的话尽量避免这样的解决方案。它唯一的优点是速度快,在 Pod 中创建 Secret,并指定应使用的 Secret 和确切的存储类型。


创建 Secret 脚本如下:



apiVersion: v1 kind: Secret metadata: name: static-persistence-secret type: Opaque data: azurestorageaccountname: "base64StorageAccountName" azurestorageaccountkey: "base64StorageAccountKey"
复制代码


在任何 Kubernetes 脚本中,在第 2 行我们指定了资源的类型。在这种情况下,我们称之为 Secret。在第 4 行,我们给它一个名字(我们称之为静态,因为它是由管理员手动创建的,而不是自动生成的)。从 Kubernetes 的角度来看,Opaque 类型意味着该 Secret 的内容(数据)是非结构化的(它可以包含任意键值对)。要了解有关 Kubernetes Secrets 的更多信息,可以参阅 Secrets Design Document 和 ConfigureKubernetes Secrets。


  • https://github.com/kubernetes/community/blob/master/contributors/design-proposals/auth/secrets.md

  • https://kubernetes.io/docs/concepts/configuration/secret/


在数据部分中,我们必须指定帐户名称(在 Azure 中,它是存储帐户的名称)和 Access 键(在 Azure 中,选择存储帐户下的“Settings ”,Access key)。别忘了两者应该使用 Base64 进行编码。


下一步是修改我们的 Deployment 脚本以使用卷(在这种情况下,卷是 Azure File Storage)。



apiVersion: apps/v1 kind: Deployment metadata: name: user-db-deployment spec: selector: matchLabels: app: user-db-app replicas: 1 template: metadata: labels: app: user-db-app spec: containers: - name: mongo image: mongo:3.6.4 command: - mongod - "--bind_ip_all" - "--directoryperdb" ports: - containerPort: 27017 volumeMounts: - name: data mountPath: /data/db resources: limits: memory: "256Mi" cpu: "500m" volumes: - name: data azureFile: secretName: static-persistence-secret shareName: user-mongo-db readOnly: false
复制代码


我们可以发现,唯一的区别是,从第 32 行我们指定了使用的卷,给它一个名称并指定底层存储系统的确切详细信息。secretName 必须是先前创建的 Secret 的名称。


Kubernetes 存储类


要了解静态或动态配置,首先我们必须了解 Kubernetes 存储类。


通过 StorageClass,管理员可以提供关于可用存储的配置文件或“类”。不同的类可能映射到不同服务质量级别,或备份策略或由集群管理员确定的任意策略。


例如,你可以有一个在 HDD 上存储数据的配置文件,命名为慢速存储,或一个在 SSD 上存储数据的配置文件,命名为快速存储。这些存储的类型由供应者确定。对于 Azure,有两种提供者:AzureFile 和 AzureDisk(区别在于 AzureFile 可以与 Read Wriite Many 访问模式一起使用,而 AzureDisk 只支持 Read Write Once 访问,当您希望同时使用多个 Pod 时,这可能是不利因素)。您可以在此处了解有关不同类型的 Storage Classes:

https://kubernetes.io/docs/concepts/storage/storage-classes/


以下是 Storage Class 的脚本:



kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: azurefilestorage provisioner: kubernetes.io/azure-file parameters: storageAccount: storageaccountname reclaimPolicy: Retain allowVolumeExpansion: true
复制代码


Kubernetes 预定义提供者属性的值(请参阅 Kubernetes 存储类)。保留回收策略意味着在我们删除 PVC 和 PV 之后,未清除实际存储介质。我们可以将其设置为删除和使用此设置,一旦删除 PVC,它也会触发相应的 PV 以及实际存储介质(此处实际存储是 Azure 文件存储)的删除。


持久卷及 Persistent Volume Claim



Kubernetes 对每一个传统的存储操作活动(供应/配置/附加)都有一个匹配的原语。持久卷是供应,存储类正在配置,并且持久卷 Claim 是附加的。


来自初始文档:


Persistent Volume(PV)是集群中的存储,它已由管理员配置或使用存储类动态配置。

Persistent Volume Claim(PVC)是用户存储的请求。它类似于 Pod。Pod 消耗节点资源与 PVC 消耗 PV 资源是类似的。Pod 可以请求特定的资源级别(CPU 和内存)。Claim 可以请求特定的大小和访问模式(例如,它们可以安装一次读/写或多次只读)。

这意味着管理员将创建持久卷以指定 Pod 可以使用的存储大小、访问模式和存储类型。开发人员将创建 Persistent Volume Claim,要求提供一个卷、访问权限和存储类型。这样一来,在“开发侧”和“运维侧”之间就有了明显的区分。开发人员负责要求必要的卷(PVC),运维人员负责准备和配置要求的卷(PV)。

静态和动态配置之间的差异是,如果没有持久卷和管理员手动创建的 Secret,Kubernetes 将尝试自动创建这些资源。

动态配置


在这种情况下,没有手动创建的持久卷和 Secret,因此 Kubernetes 将尝试生成它们。Storage Class 是必要的,我们将使用在前文中创建的 Storage Class。


PersistentVolumeClaim 的脚本如下所示:



apiVersion: v1 kind:Persistent Volume Claim metadata: name: persistent-volume-claim-mongo spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: azurefilestorage
复制代码


以及我们更新的 Deployment 脚本:



apiVersion: apps/v1 kind: Deployment metadata: name: user-db-deployment spec: selector: matchLabels: app: user-db-app replicas: 1 template: metadata: labels: app: user-db-app spec: containers: - name: mongo image: mongo:3.6.4 command: - mongod - "--bind_ip_all" - "--directoryperdb" ports: - containerPort: 27017 volumeMounts: - name: data mountPath: /data/db resources: limits: memory: "256Mi" cpu: "500m" volumes: - name: data Persistent Volume Claim: claimName: persistent-volume-claim-mongo
复制代码


如你所见,在第 34 行中,我们通过名称引用了先前创建的 PVC。在这种情况下,我们没有手动为它创建持久卷或 Secret,因此它将自动创建。


这种方法的最重要的优势是您不必手动创建 PV 和 Secret,而且 Deployment 是与云无关的。存储的底层细节不存在于 Pod 的 spec 中。但是也有一些缺点:您无法配置存储帐户或文件共享,因为它们是自动生成的,并且您无法重复使用 PV 或 Secret ——它们将为每个新 Claim 重新生成。

静态配置


静态和动态配置之间的唯一区别是我们手动创建静态配置中的持久卷和 Secret。这样,我们就可以完全控制在集群中创建的资源。


持久卷脚本如下:



apiVersion: v1 kind: PersistentVolume metadata: name: static-persistent-volume-mongo labels: storage: azurefile spec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: azurefilestorage azureFile: secretName: static-persistence-secret shareName: user-mongo-db readOnly: false
复制代码


重要的是,在第 12 行我们按名称引用 Storage Class。此外,在第 14 行我们引用了 Secret,用于访问底层存储系统。


本文更推荐这个解决方案,即使它需要更多的工作,但它是与云无关的(cloud-agnostic)。它还允许您应用有关角色(集群管理员与开发人员)的关注点分离,并让您控制命名和创建资源。

总结

在本文中,我们了解了如何使用 Volume 持久化数据和状态,并提出了三种不同的方法来设置系统,即为直接访问、动态配置和静态配置,并讨论了每个系统的优缺点。


在下一篇文章中,我们将介绍 CI / CD 流水线以自动部署微服务。点击下方卡片,关注我们并星标,确保您能收到我们下一次的推送噢!


本文转载自:RancherLabs(ID:RancherLabs)

原文链接:从入门到上手:什么是K8S持久卷?

2021 年 6 月 27 日 07:00982

评论

发布
暂无评论
发现更多内容

消灭微服务的坏味道 之 共享库

码猿外

微服务 共享库

周六

IT蜗壳-Tango

七日更 28天写作 二月春节不断更

2.1 Go语言从入门到精通:Go语言基础语法

xcbeyond

28天写作 基础语法 Go 语言

从一次洗头发的经历,学习一家公司的成长

数列科技杨德华

28天写作

程序员成长第十六篇:代码重构

石云升

程序员 28天写作 2月春节不断更

Selenium 项目代码的优化与重构之路,滚雪球学 Python 番外篇

梦想橡皮擦

Python 28天写作 2月春节不断更

状态图与概念模型

克比

【死磕JVM】五年 整整五年了 该知道JVM加载机制了!

牧小农

JVM 类加载 类加载器 类加载时机 双亲委派

模型评估指标-1-基础篇-FPR/TPR/F1/ROC/AUC

一直学习一直爽

机器学习 模型评估 分类模型 一直学习一直爽

LeetCode题解:121. 买卖股票的最佳时机,JavaScript,动态规划,详细注释

Lee Chen

算法 大前端 LeetCode

【管理笔记15】行销观念

俊毅

你存在我深深的脑海里——兼谈间隔效应

Justin

心理学 28天写作 游戏设计

第五次作业

秦挺

如何节省数据库写操作资源(6)【写缓存】

我爱娃哈哈😍

数据库 缓存 架构设计 抢购思路 写缓存

(28DW-S8-Day8) 区块链之瞎扯淡

mtfelix

区块链 28天写作

必学必会-音频和视频

魔王哪吒

html5 大前端 28天写作 2月春节不断更

现在写还来得及吗?

Nydia

javascript中的模块系统

程序那些事

JavaScript 程序那些事 模块系统

备战金三银四必备:2021最新Java面试汇总(附答案解析)

比伯

Java 编程 架构 面试 计算机

翻译:《实用的Python编程》03_00_Overview

codists

Python

Linux之旅 - 入⻔命令集

诚义舅

bash Linux 运维 Shell

边缘计算云原生开源方案选型比较

远鹏

Kubernetes 边缘计算 kubeedge openyurt superedge

Linux之旅 - 入⻔命令集 - 文件管理(1/2)

诚义舅

bash Linux Shell linux命令

使用 Helm 部署 Wikijs

东风微鸣

k8s openshift wiki

关于整理东西这件事「Day 8」

道伟

28天写作

可能是Java Stream的最佳实践(三)

ES_her0

28天写作

Linux之旅 - 自序

诚义舅

bash Linux Shell

【LeetCode】至少有K个重复字符的最长子串Java题解

HQ数字卡

算法 LeetCode 28天写作 2月春节不断更

LeetCode题解:122. 买卖股票的最佳时机 II,动态规划,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

Linux之旅 - 行程介绍

诚义舅

bash Linux Shell

Elasticsearch Doc Values 和 doc_values

escray

elastic 七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试 2月春节不断更

ShadowRealm 与微前端沙箱

ShadowRealm 与微前端沙箱

从入门到上手:什么是K8S持久卷?-InfoQ