k8s入门到实战(五)—— k8s存储卷详细介绍

存储卷

什么是存储卷

在 k8s 中,存储卷(Volume)是一种抽象的概念,用于提供 pod 中容器的持久化存储。存储卷允许将数据存储在 pod 的生命周期之外,以便在容器重启、迁移或重新调度时保留数据。

存储卷可以连接到 pod 中的一个或多个容器,并提供持久化的存储空间。这些存储卷可以是来自 k8s 集群的本地存储、网络存储、云存储提供商或外部存储系统等。

存储卷可以用于各种用途,例如:

  • 数据持久化:将数据存储在存储卷中,以便在容器重启后仍然可用。
  • 数据共享:将存储卷连接到多个容器,使它们可以共享相同的数据。
  • 数据备份和恢复:使用存储卷来备份和还原应用程序的数据。
  • 数据迁移和复制:将存储卷从一个 pod 迁移到另一个 pod,或者将存储卷复制到其他地方。

由于 pod 本身是具有生命周期的,所以 pod 内部运行的容器及相关的数据,在 pod 中是无法持久化存储的。我们知道,docker 支持配置容器使用存储卷,已实现数据在容器之外的存储空间中持久化存储。相应的,k8s 也支持类似的存储卷功能,此处存储卷与 pod 资源绑定。

简单来说,存储卷是定义在 pod 资源之上、可被其他内容所有容器挂载的共享目录,它关联至外部的存储设备之上的存储空间,从而独立于容器自身的文件系统,而数据是否具有持久化存储能力取决于存储卷自身是否支持持久存储机制,与 pod 无关。

k8s 支持的存储类型

k8s 支持非常丰富的存储卷类型,总体上来看,大致可以分为如下三种类型:

本地存储,例如 emptyDir、HostPath;

网络存储,nfs、cinder、cephfs、AzureFile;

特殊存储资源,例如 secret、ConfigMap

对于本地存储,emptyDir 的生命周期与 pod 资源相同,所以 pod 一旦删除,存储的数据同时被删除。HostPath(node1 node2)的生命周期与节点一致,当 pod 重新被调度到其他节点时,虽然原节点上的数据没有被删除,但是 pod 不再使用此前的数据。

网络存储系统是独立于 k8s 集群之外的存储资源,数据存储的持久性与 k8s 集群解耦合。k8s 在集群中设计了一种集群级别的资源 PersistentVolume:服务器资源(管理主动分配一些存储空间)(简称 PV)来关联网络存储,用户通过 PersistentVolumeClaim:用户就要申请使用资源(服务器就会自动匹配)(简称 PVC)来申请使用存储资源。

secret 和 ConfigMap 算是 k8s 集群中两种特殊类型的存储资源。secret 用于向 pod 传递敏感信息,例如密码、私钥、证书等。这些信息直接定义在镜像中容易导致泄露,用户可以讲这些信息集中存储在 secret 中,由 pod 进行挂载,从而实现敏感数据与系统解耦。

ConfigMap 资源用于向 pod 注入非敏感数据,用户将一些非敏感的配置数据存储在 ConfigMap 对象中,然后在 pod 中使用 ConfigMap 卷引用它即可,从而帮助实现容器配置文件集中化定义和管理。

emptyDir

emptyDir:初始内容为空的本地临时目录

它是一个临时卷(Ephemeral Volume)

与 pod 一起创建和删除,生命周期与 pod 相同

emptyDir 会创建一个初始状态为空的目录

通常使用本地临时存储来设置缓存、保存日志等

例如,将 redis 的存储目录设置为 emptyDir,编辑文件redis-pod.yaml

apiVersion: v1
kind: Pod
metadata:name: redis-pod
spec:containers:- name: redis01image: redisvolumeMounts:- name: redis-storagemountPath: /data/redisvolumes:- name: redis-storageemptyDir: {}
[root@k8s-master k8s]# vim redis-pod.yaml
[root@k8s-master k8s]# kubectl apply -f redis-pod.yaml 
pod/redis-pod created
[root@k8s-master k8s]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
redis-pod   1/1     Running   0          2m27s

容器启动之后我们进入容器内部,添加数据

[root@k8s-master k8s]# kubectl exec -it redis-pod /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@redis-pod:/data# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name yigongsui
OK

这样我们添加了一条数据,接下来我们退出并删除这个容器

127.0.0.1:6379> exit
root@redis-pod:/data# exit
exit
[root@k8s-master k8s]# kubectl delete -f redis-pod.yaml 
pod "redis-pod" deleted

删除容器后,我们再重新启动这个容器,看看数据还在不在

[root@k8s-master k8s]# kubectl apply -f redis-pod.yaml 
pod/redis-pod created
[root@k8s-master k8s]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
redis-pod   1/1     Running   0          16s
[root@k8s-master k8s]# kubectl exec -it redis-pod /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@redis-pod:/data# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> get name
(nil)

发现数据不存在了,这就说明 emptyDir 的生命周期很短,与 pod 相同,只做临时存储使用

网络存储 nfs

nfs:全称是 Network File System,它最大的功能就是可以通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。

在这里插入图片描述

安装 nfs

三台服务器都要安装 nfs

yum install -y nfs-utils

接下来,在 master 主节点配置:

# 主节点配置
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
# 创建/nfs/data文件夹(主节点)
mkdir -p /nfs/data  
# 启动rpc远程绑定(主节点)
systemctl enable rpcbind --now 
# (开机)启动nfs服务(主节点)
systemctl enable nfs-server --now # 配置生效(主节点)
exportfs -r 
# 查看目录
exportfs
[root@k8s-master k8s]# echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
[root@k8s-master k8s]# mkdir -p /nfs/data
[root@k8s-master k8s]# systemctl enable rpcbind --now
[root@k8s-master k8s]# systemctl enable nfs-server --now
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
[root@k8s-master k8s]# exportfs -r
[root@k8s-master k8s]# exportfs
/nfs/data     	<world>

接下来在 node 节点下执行,

# 查看主节点机器有哪些目录可以同步挂载(node节点)
# showmount -e 主节点的内网ip,我的内网ip是192.168.0.1
showmount -e 192.168.0.1
[root@k8s-node1 home]# showmount -e 192.168.0.1
Export list for 192.168.0.1:
/nfs/data *

接下来在 node 节点执行以下命令挂载 nfs 服务器上的共享目录到本机路径

# mkdir -p 本机目录 (名字可以任取)
# mount -t nfs 192.168.0.1:/nfs/data 本机目录
# node1 执行
mkdir -p /nfs/node1
mount -t nfs 192.168.0.1:/nfs/data /nfs/node1
# node2 执行
mkdir -p /nfs/node2
mount -t nfs 192.168.0.1:/nfs/data /nfs/node2

测试看看三个节点是否共通

# master节点新增文件
[root@k8s-master k8s]# cd /nfs/data/
[root@k8s-master data]# echo "hello master" > master.txt
# node1节点新增文件
[root@k8s-node1 home]# cd /nfs/node1/
[root@k8s-node1 node1]# echo "hello node1" > node1.txt# 查看三个节点内数据是否共通
[root@k8s-master data]# ls
master.txt  node1.txt
[root@k8s-node1 node1]# ls
master.txt  node1.txt
[root@k8s-node2 home]# ls /nfs/node2/
master.txt  node1.txt

可以看到三个节点已经共通了

文件都共享,在 nfs 文件系统中,volumes 肯定也可以连通

测试:编辑文件nginx-nfs.yaml

apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginx-nfsname: nginx-nfs
spec:replicas: 2selector:matchLabels:app: nginx-nfstemplate:metadata:labels:app: nginx-nfsspec:containers:- image: nginx01name: nginxvolumeMounts:- name: nginx-storagemountPath: /usr/share/nginx/htmlvolumes:- name: nginx-storagenfs:server: 192.168.0.1path: /nfs/data/nginx-nfs

创建一个 deployment 部署,自行测试即可,在主节点的/nfs/data/nginx-nfs目录,新建 index.html,编辑内容,在容器里进行访问测试。

主节点的/nfs/data/nginx-nfs目录也和从节点的目录共通(node1 的目录就是/nfs/node1/nginx-nfs),也都可以进行测试

结论:无论容器怎么部署怎么删除,数据都可以持久化保存了

PV & PVC

持久卷(Persistent Volume):删除 pod 后,卷不会被删除

PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置

PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格

k8s 支持的存储系统非常多,要求大家全都掌握,是不现实的。为了屏蔽底层存储实现细节,方便使用,引入了 PV 和 PVC 两种资源对象。

封装机制!数据中台

在这里插入图片描述

PV

Persistent Volume 是持久卷的意思,是对底层共享存储的一种抽象封装。一般情况 PV 由管理员创建和配置,它与底层具体的存储技术有关,通过插件完成与存储的对接。

PV 是存储资源的抽象,资源清单如下:

apiVersion: v1  
kind: PersistentVolume
metadata:name: pv2
spec:nfs: # 存储类型,与底层真正存储对应capacity:  # 存储能力,目前只支持存储空间的设置storage: 2GiaccessModes:  # 访问模式storageClassName: # 存储类别persistentVolumeReclaimPolicy: # 回收策略

accessModes 用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

  • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
  • ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
  • ReadWriteMany(RWX):读写权限,可以被多个节点挂载
  • 需要注意的是,底层不同的存储类型可能支持的访问模式不同

回收策略(persistentVolumeReclaimPolicy)

persistentVolumeReclaimPolicy 当 PV 不再被使用了之后,对其的处理方式。目前支持三种策略:

  • Retain (保留) 保留数据,需要管理员手工清理数据
  • Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
  • Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务

一个 PV 的生命周期中,可能会处于4种不同的阶段:

  • Available(可用):表示可用状态,还未被任何 PVC 绑定
  • Bound(已绑定):表示 PV 已经被 PVC 绑定
  • Released(已释放):表示 PVC 被删除,但是资源还未被集群重新声明
  • Failed(失败):表示该 PV 的自动回收失败

PVC

Persistent Volume Claim 持久卷声明的意思,是用户对存储需求的一种声明。也就是向 k8s 系统发出的一种资源需求申请。

PVC 作为资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvcnamespace: dev
spec:accessModes: # 访问模式selector: # 采用标签对PV选择storageClassName: # 存储类别resources: # 请求空间requests:storage: 5Gi

示例

创建一个 pv,创建一个 pvc,创建一个 pod 绑定 pvc 就可以了!

pv 做就是连接存储系统,规定一个大小的空间,权限配置

pvc 做的就是写一个声明,根据自己的使用者的要求(存储系统、大小、权限),来匹配 pv

pod 使用 pvc volumes 挂载的类型!

  1. 准备工作:在 nfs 主节点(master 节点)创建 PV 池
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03
  1. 创建 pv,编辑文件my-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: pv01-10m
spec:capacity:storage: 10MaccessModes:- ReadWriteManystorageClassName: nfsnfs:path: /nfs/data/01server: 192.168.0.1
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv02-1gi
spec:capacity:storage: 1GiaccessModes:- ReadWriteManystorageClassName: nfsnfs:path: /nfs/data/02server: 192.168.0.1
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv03-3gi
spec:capacity:storage: 3GiaccessModes:- ReadWriteManystorageClassName: nfsnfs:path: /nfs/data/03server: 192.168.0.1
  1. 执行 yaml 文件
[root@k8s-master k8s]# kubectl apply -f my-pv.yaml 
persistentvolume/pv01-10m created
persistentvolume/pv02-1gi created
persistentvolume/pv03-3gi created
  1. 查看所有 pv
kubectl get pv
[root@k8s-master k8s]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv01-10m   10M        RWX            Retain           Available           nfs                     50s
pv02-1gi   1Gi        RWX            Retain           Available           nfs                     50s
pv03-3gi   3Gi        RWX            Retain           Available           nfs                     50s
  1. 创建 pvc,编辑my-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: nginx-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 500MistorageClassName: nfs 
  1. 执行 yaml 文件
[root@k8s-master k8s]# vim my-pvc.yaml
[root@k8s-master k8s]# kubectl apply -f my-pvc.yaml 
persistentvolumeclaim/nginx-pvc created
  1. 再次查看所有 pv
[root@k8s-master k8s]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
pv01-10m   10M        RWX            Retain           Available                       nfs                     7m54s
pv02-1gi   1Gi        RWX            Retain           Bound       default/nginx-pvc   nfs                     7m54s
pv03-3gi   3Gi        RWX            Retain           Available                       nfs                     7m54s

可以看到 pv02-1gi 的状态变成了 Bound,也就是说我们创建的这个 pvc 绑定到了 pv02-1gi

这是因为在 pvc 会根据我们 yaml 文件设置的存储类型以及需要的存储容量来选择绑定到最合适的 pv,我们在 pvc 中设置了存储类型为 nfs,所需的容量为 500M,所以绑定到了 pv02-1gi

  1. 删除这个 pvc,查看 pv 状态
[root@k8s-master k8s]# kubectl delete -f my-pvc.yaml 
persistentvolumeclaim "nginx-pvc" deleted
[root@k8s-master k8s]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
pv01-10m   10M        RWX            Retain           Available                       nfs                     12m
pv02-1gi   1Gi        RWX            Retain           Released    default/nginx-pvc   nfs                     12m
pv03-3gi   3Gi        RWX            Retain           Available                       nfs                     12m

可以看到,状态变为了 Released,也就是释放状态

  1. 根据 my-pvc.yaml 文件再创建一个 pvc,查看 pv 状态
[root@k8s-master k8s]# kubectl apply -f my-pvc.yaml 
persistentvolumeclaim/nginx-pvc created
[root@k8s-master k8s]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
pv01-10m   10M        RWX            Retain           Available                       nfs                     14m
pv02-1gi   1Gi        RWX            Retain           Released    default/nginx-pvc   nfs                     14m
pv03-3gi   3Gi        RWX            Retain           Bound       default/nginx-pvc   nfs                     14m
# 查看 pvc 绑定到了哪个 pv上
[root@k8s-master k8s]# kubectl get pvc
NAME        STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nginx-pvc   Bound    pv03-3gi   3Gi        RWX            nfs            101s

可以看到 pvc 绑定到了 pv03-3gi 上,说明正处于 Released 状态的 pv 无法绑定任何 pvc

已经了解 pv 和 pvc 的绑定关系,接下来我们创建一个 pod 去绑定 pvc

  1. 清除所有的 deployment 和 pod
[root@k8s-master k8s]# kubectl get deploy
No resources found in default namespace.
[root@k8s-master k8s]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
redis-pod   1/1     Running   0          16h
[root@k8s-master k8s]# kubectl delete pod redis-pod
pod "redis-pod" deleted
  1. 编辑文件my-pvc-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginx-pod-pvcname: nginx-pod-pvc
spec:replicas: 2selector:matchLabels:app: nginx-pod-pvctemplate:metadata:labels:app: nginx-pod-pvcspec:containers:- image: nginxname: nginx01volumeMounts:- name: nginx-volumemountPath: /usr/share/nginx/htmlvolumes:- name: nginx-volumepersistentVolumeClaim:claimName: nginx-pvc
  1. 执行 yaml 文件,查看 deployment 和 pod
[root@k8s-master k8s]# kubectl apply -f my-pvc-pod.yaml 
deployment.apps/nginx-pod-pvc created
[root@k8s-master k8s]# kubectl get deploy
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
nginx-pod-pvc   2/2     2            2           19s
[root@k8s-master k8s]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-pod-pvc-967fcb547-rj5ll   1/1     Running   0          30s
nginx-pod-pvc-967fcb547-wbbh7   1/1     Running   0          30s
  1. 查看 pod 的详细信息,里面有关于 pvc 信息
[root@k8s-master k8s]# kubectl describe pod nginx-pod-pvc-967fcb547-rj5ll
......
Volumes:nginx-volume:Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)ClaimName:  nginx-pvcReadOnly:   falsekube-api-access-5rlkl:Type:                    Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds:  3607ConfigMapName:           kube-root-ca.crtConfigMapOptional:       <nil>DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
......
  1. 因为 pvc 绑定在 pv03-3gi 这个 pv 上,这个 pv 的挂载目录是/nfs/data/03,所以我们去这个目录下编辑文件
[root@k8s-master k8s]# cd /nfs/data/03
[root@k8s-master 03]# echo "hello yigongsui" > index.html
  1. 进入 pod 容器内部,访问首页,查看结果
[root@k8s-master 03]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-pod-pvc-967fcb547-rj5ll   1/1     Running   0          11m
nginx-pod-pvc-967fcb547-wbbh7   1/1     Running   0          11m
[root@k8s-master 03]# kubectl exec -it nginx-pod-pvc-967fcb547-rj5ll /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-pod-pvc-967fcb547-rj5ll:/# curl localhost
hello yigongsui

可以看到里面的首页也变化了

这样我们的两个容器内目录就永久存储到我们的本地目录了,这样无论 pod 怎么重新部署删除,数据都不会丢失了

生命周期

PVC 和 PV 是一一对应的,PV 和 PVC 之间的相互作用遵循以下生命周期:

  • 资源供应:管理员手动创建底层存储和 PV。
  • 资源绑定:用户创建 PVC,k8s 负责根据 PVC 的声明去寻找 PV,并绑定。

在用户定义好 PVC 之后,系统将根据 PVC 对存储资源的请求在已存在的 PV 中选择一个满足条件的。

  • 一旦找到,就将该 PV 与用户定义的 PVC 进行绑定,用户的应用就可以使用这个 PVC 了,就可以在 pod 里面去使用
  • 如果找不到,PVC 则会无限期处于 Pending 状态,直到等到系统管理员创建了一个符合其要求的 PV,PV 一旦绑定到某个 PVC 上,就会被这个 PVC 独占,不能再与其他 PVC 进行绑定了,一一绑定。
  • 资源使用:用户可在 pod 中像 volume 一样使用 pvc。

pod 使用 volume 的定义,将 PVC 挂载到容器内的某个路径进行使用。

  • 资源释放:用户删除 pvc 来释放 pv。

当存储资源使用完毕后,用户可以删除 PVC,与该 PVC 绑定的 PV 将会被标记为“已释放”,但还不能立刻与其他 PVC 进行绑定。通过之前 PVC 写入的数据可能还被留在存储设备上,只有在清除之后该 PV 才能再次使用。

这里我们查看 pv02-1gi 的绑定关系:

kubectl get pv pv02-1gi -o yaml

在这里插入图片描述

在这里唯一绑定了 pvc,需要清除才可以绑定其它 pvc

我们可以使用以下命令去动态修改 k8s 配置

kubectl edit pv pv02-1gi

与 linux 的 vim 编辑器一致,点击i进入输入模式,删除这两行即可

查看 pv 状态

[root@k8s-master 03]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
pv01-10m   10M        RWX            Retain           Available                       nfs                     135m
pv02-1gi   1Gi        RWX            Retain           Available   default/nginx-pvc   nfs                     135m
pv03-3gi   3Gi        RWX            Retain           Bound       default/nginx-pvc   nfs                     135m

可以看到 pv02-1gi 的状态已经变为 Available,就可以重新绑定 pvc 了

资源回收:k8s 根据 pv 设置的回收策略进行资源的回收。

对于 PV,管理员可以设定回收策略,用于设置与之绑定的 PVC 释放资源之后如何处理遗留数据的问题。只有 PV 的存储空间完成回收,才能供新的PVC绑定和使用。

问题:pv、pvc都是我们手动创建和绑定的,十分麻烦

有没有这样一种技术可以自动帮我们绑定,我们在 pod 创建的时候,自动帮我们创建 pv 和 pvc

答:有,StorageClass

StorageClass(存储类)

官方地址:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#local

在 java 中,我们知道 class 是类的概念,相当于一个模板,通过类来创建对象

那么 StorageClass 其实就相当于是 pv 的模板,通过这个模版可以自动帮我们创建 pv 并通过 pvc 自动挂载上

接下来我们去理解 StorageClass

什么是 StorageClass

在 k8s 中,StorageClass 是用于定义和管理动态供应的持久化存储的对象。它是 PersistentVolume(PV)的动态供应机制的一部分。

StorageClass 定义了一组存储配置,包括存储提供者、存储类型、I/O 特性、复制策略等。它允许管理员为不同的存储需求创建多个 StorageClass,并为每个 StorageClass 指定不同的参数。

当创建 PersistentVolumeClaim(PVC)时,可以指定所需的 StorageClass。k8s 会根据 StorageClass 的定义和可用的存储资源,动态创建与 PVC 匹配的 PersistentVolume,并将其绑定到 PVC 上。

StorageClass 的优点是可以根据应用程序的需求自动创建和配置持久化存储,无需手动预先创建 PersistentVolume。这样可以简化存储管理的工作,提高存储资源的利用率。

另外,StorageClass 还支持动态卷的回收和回收策略的定义。当 PVC 被删除时,如果定义了回收策略,k8s 会自动回收对应的 PersistentVolume,释放存储资源。

总之,StorageClass 是 k8s 中用于动态供应和管理持久化存储的重要机制,可以根据需求自动创建、配置和回收存储资源,提高存储的灵活性和利用率。

静态供应与动态供应

我们这里的 PV 是我们提前开辟好的空间申明,是静态供应。

还有一种动态供应,根据 PVC 申请的空间,来实现 PV 的创建,从而进行绑定。

在动态资源供应模式下,通过 StorageClass 和 PVC 完成资源动态绑定(系统自动生成 PV),并供 pod 使用的存储管理机制。

在一个大规模的 k8s 集群里,可能有成千上万个 PVC,这就意味着运维人员必须实现创建出这个多个 PV,此外,随着项目的需要,会有新的 PVC 不断被提交,那么运维人员就需要不断的添加新的,满足要求的 PV,否则新的 pod 就会因为 PVC 绑定不到 PV 而导致创建失败。而且通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求。

而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,为了解决这一问题,k8s 又为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,用户根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了。

而 StorageClass 对象的作用,其实就是创建 PV 的模板。

示例

获取指定 ns 下的 StorageClass 命令,默认是 default:

[root@k8s-master 03]# kubectl get sc
No resources found

接下来我们开始测试:

一个 k8s 中可以有多个 StorageClass,多个模版!

  1. k3s 自带一个 local-path 存储类,我们这里也创建一个 local-path-storage.yaml 去创建存储类
apiVersion: v1
kind: Namespace
metadata:name: local-path-storage---
apiVersion: v1
kind: ServiceAccount
metadata:name: local-path-provisioner-service-accountnamespace: local-path-storage---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: local-path-provisioner-role
rules:- apiGroups: [ "" ]resources: [ "nodes", "persistentvolumeclaims", "configmaps" ]verbs: [ "get", "list", "watch" ]- apiGroups: [ "" ]resources: [ "endpoints", "persistentvolumes", "pods" ]verbs: [ "*" ]- apiGroups: [ "" ]resources: [ "events" ]verbs: [ "create", "patch" ]- apiGroups: [ "storage.k8s.io" ]resources: [ "storageclasses" ]verbs: [ "get", "list", "watch" ]---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: local-path-provisioner-bind
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: local-path-provisioner-role
subjects:- kind: ServiceAccountname: local-path-provisioner-service-accountnamespace: local-path-storage---
apiVersion: apps/v1
kind: Deployment
metadata:name: local-path-provisionernamespace: local-path-storage
spec:replicas: 1selector:matchLabels:app: local-path-provisionertemplate:metadata:labels:app: local-path-provisionerspec:serviceAccountName: local-path-provisioner-service-accountcontainers:- name: local-path-provisionerimage: rancher/local-path-provisioner:master-headimagePullPolicy: IfNotPresentcommand:- local-path-provisioner- --debug- start- --config- /etc/config/config.jsonvolumeMounts:- name: config-volumemountPath: /etc/config/env:- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespacevolumes:- name: config-volumeconfigMap:name: local-path-config---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: local-path
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete---
kind: ConfigMap
apiVersion: v1
metadata:name: local-path-confignamespace: local-path-storage
data:config.json: |-{"nodePathMap":[{"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES","paths":["/opt/local-path-provisioner"]}]}setup: |-#!/bin/shset -eumkdir -m 0777 -p "$VOL_DIR"teardown: |-#!/bin/shset -eurm -rf "$VOL_DIR"helperPod.yaml: |-apiVersion: v1kind: Podmetadata:name: helper-podspec:containers:- name: helper-podimage: busyboximagePullPolicy: IfNotPresent
  1. 执行 yaml 文件
[root@k8s-master k8s]# vi local-path-storage.yaml
[root@k8s-master k8s]# kubectl apply -f local-path-storage.yaml 
namespace/local-path-storage created
serviceaccount/local-path-provisioner-service-account created
clusterrole.rbac.authorization.k8s.io/local-path-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/local-path-provisioner-bind created
deployment.apps/local-path-provisioner created
storageclass.storage.k8s.io/local-path created
configmap/local-path-config created
[root@k8s-master k8s]# kubectl get sc
NAME         PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  17s
  1. 把这个存储类设置为默认的存储类型,执行以下命令:
kubectl patch storageclass local-path  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
[root@k8s-master k8s]# kubectl patch storageclass local-path  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
storageclass.storage.k8s.io/local-path patched
[root@k8s-master k8s]# kubectl get sc
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  119s

每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件创建持久卷。 该字段必须指定。

在很多 k8s 系统中是自带的。

  1. 我们创建一个 pod 去测试是否会自动生成 pv 和 pvc,创建文件mysql-pod.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: local-path-pvcnamespace: default
spec:accessModes:- ReadWriteOncestorageClassName: local-pathresources:requests:storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:name: mysql-pod
spec:containers:- image: mysql:5.7name: mysql01env:- name: MYSQL_ROOT_PASSWORDvalue: "123456"ports:- containerPort: 3306volumeMounts:- mountPath: /var/lib/mysqlname: local-mysql-datavolumes:- name: local-mysql-datapersistentVolumeClaim:claimName: local-path-pvc
[root@k8s-master k8s]# vim mysql-pod.yaml
[root@k8s-master k8s]# kubectl apply -f mysql-pod.yaml 
persistentvolumeclaim/local-path-pvc created
pod/mysql-pod created
  1. 查看 pv 和 pvc 是否自动创建了

在这里插入图片描述

可以看到 pv 和 pvc 都自动创建了

创建 pod 时去申请 pvc,StorageClass 会动态创建 pvc 和 pv,pvc 申请多大存储 pv 就会创建多大空间

local卷也存在自身的问题,当 pod 所在节点上的存储出现故障或者整个节点不可用时,pod 和卷都会失效,仍然会丢失数据,因此最安全的做法还是将数据存储到集群之外的存储或云存储上。同时配置,做一些灾备,保证数据不会丢失!

总结

本地存储:

  • 缺点:
    • 容易丢失
    • pod 一没有可能就不见了
    • pod 换了节点启动,数据也可能没了

存储卷:

  • nfs
    • 系统就全部连接了,数据就不会再丢失
    • 方便使用
  • 问题
    • 一个系统中可能有很多的存储类型 nfs cifs hdfs oss,用户连接不方便,希望存在一个统一平台

pv

  • k8s 提供的同一存储类型对象
    • 管理声明(文件类型、大小、使用方式,权限…回收策略)

pvc

  • 用户拿着 pvc 就可以在 k8s 中自动找到 pv 绑定,从而实现数据持久化(k8s 的持久化存储策略)

storageClass

  • pv 每次手动创建十分麻烦,希望可以动态创建pv
  • storageClass 动态创建 pv 模版实现。
    • pvc 直接在 pod 中声明就好了! 不需要在手动创建 pv 了! 自动根据用户 pod 申请的 pvc 来根据 storageClass 自动创建 pv

至此,k8s 数据持久化搞定!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/286831.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python:基础语法

一、import与from.....import 有时候我们需要使用一些第三方库或包时&#xff0c;我们就需要通过import或from.....import导入模块。 # 导入库 import sys print("hello,world") 当我们自己写了些函数&#xff0c;在其他py文件&#xff0c;我们也可以通过from.....im…

OC对象 - Block解决循环引用

文章目录 OC对象 - Block解决循环引用前言1. 循环引用示例1.1 分析 2. 解决思路3. ARC下3.1 __weak3.2 __unsafe_unretained3.3 __block 4. MRC下4.1 __unsafe_unretain....4.1 __block 5. 总结5.1 ARC下5.2 MRC下 OC对象 - Block解决循环引用 前言 本章将会通过一个循环引用…

项目管理商业文件--商业论证与效益管理计划

本文描述从事项目管理和了解项目管理领域所需的基本知识&#xff0c;词汇定义来自于《项目知识管理体系》(PMBOK指南)第六版&#xff0c;仅作个人学习使用&#xff0c;任何对此文章的引用&#xff0c;应当说明源出处&#xff0c;不得用于商业用途。 如有侵权、联系速删 文章目录…

SAP ABAP Update Module 调试

最近搞SAP migo的调试 BADI 那如何让起效呢 参考 SAP调试一&#xff1a; Update Module函数调试 - 程序员大本营 先在 BEFORE_update 里面打上内部断点 再在update里面打上外部断点 断点调试的时候 在设置->更改调试器参数文件/设置 如下图

第十三届蓝桥杯物联网试题(省赛)

做后感悟&#xff1a; OLED显示函数需要一直显示&#xff0c;所以在主函数中要一直循环&#xff0c;为了确保这个检错功能error只输出一次&#xff0c;最好用中断串口进行接收数据&#xff0c;数据收完后自动进入中断函数中&#xff0c;做一次数据检查就好了&#xff0c;该开灯…

YOLOv8融入低照度图像增强算法---传统算法篇

YOLOv8n原图检测YOLOv8n增强后检测召回率和置信度都有提升 前言 这篇博客讲讲低照度,大家都催我出一些内容,没想到这么多同学搞这个,恰好我也做过这方面的一些工作,那今天就来讲解一些方法,低照度的图像增强大体分“传统算法”和“深度学习算法”; 目前低照度的图像增…

Python学习笔记(二)

一&#xff1a;异常&#xff1a; 1.1&#xff1a;异常处理&#xff1a; 1.2&#xff1a;异常捕获&#xff1a; 1.3&#xff1a;异常传递&#xff1a; 二&#xff1a;模块&#xff1a; 2.1&#xff1a;模块的定义&#xff1a; 2.2&#xff1a;模块的导入&#xff1a; 2.3&…

Open WebUI大模型对话平台-适配Ollama

什么是Open WebUI Open WebUI是一种可扩展、功能丰富、用户友好的大模型对话平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&#xff0c;包括与Ollama和Openai兼容的API。 功能 直观的界面:我们的聊天界面灵感来自ChatGPT&#xff0c;确保了用户友好的体验。响应…

窥探向量乘矩阵的存内计算原理—基于向量乘矩阵的存内计算

前言 在计算机科学和数学领域&#xff0c;向量乘矩阵的内积计算是许多算法和模型中的核心操作之一。这一操作的高效实现对于优化算法的性能以及提高计算速度至关重要。本文将深入探讨向量乘矩阵的存内计算原理&#xff0c;聚焦于基于这一操作的存内计算方法。 本文的目标是解…

第16篇:奇偶校验器

Q&#xff1a;本期我们将实现4位奇偶校验逻辑电路&#xff0c;即校验4位二进制代码中 “1” 的个数是奇数或偶数。 A&#xff1a;奇偶校验器的基本原理&#xff1a;采用异或运算对“1”的奇偶个数进行校验&#xff0c;从最高位依次往最低位进行连续异或运算。如果最后的异或运…

Linux离线安装Docker-Oracle_11g

拉取oracle11g镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g创建11g容器 docker run -d -p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g查看容器是否创建成功 docker ps -a导出oracle容器&#xff0c;查看…

计算机视觉之三维重建(3)---单视几何

文章目录 一、问题提出二、无穷远点、无穷远线、无穷远平面2.1 2D空间2.2 3D空间 三、影消点和影消线3.1 2D平面上的无穷远点&#xff0c;无穷远线变换3.2 影消点3.3 影消线 四、单视重构 一、问题提出 1. 当摄像机标定后&#xff0c;内部参数 K K K 已知&#xff0c;外部参数…

最新上门预约服务派单小程序源码 仿东郊到家小程序源码 开源可二开 含完整搭建部署教程

上门预约服务派单小程序源码的在提供便捷的预约服务、实现有效的派单管理、优化服务流程、提升用户体验&#xff0c;并为业务发展和优化提供数据支持。分享一个最新上门预约服务派单小程序源码&#xff0c;仿东郊到家小程序源码&#xff0c;O2O平台系统&#xff0c;跟58到家模式…

简易电路设计,PW1605芯片实现24V/30V/48V限流过压保护功能

一般描述 PW1605 是一款电流限制开关&#xff0c;具有可编程输入过压保护和输出电压箝位功能。集成保护 N 沟道 FET 具有极低的 RDS&#xff08;ON&#xff09; 功能&#xff0c;PW1605有助于降低正常工作期间的功率损耗。可编程软启动时间控制启动期间输出电压的压摆率。独立的…

Docker学习笔记 - 基本概念

一. 什么是“容器”&#xff08;container&#xff09;和“镜像”&#xff08;Image&#xff09; 所谓“容器”可以理解为一个模拟操作系统的虚拟层&#xff0c;大部分是基于Linux的&#xff0c;应用程序及其配置信息&#xff0c;依赖库可以打包成一个Image独立运行在这个虚拟…

基于springboot+vue+Mysql的校园博客系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Android 系统应用 pk8签名文件转jks或keystore教程

一、介绍 签名文件对于我们在做应用开发中&#xff0c;经常遇到&#xff0c;且签名文件不仅仅是保护应用安全&#xff0c;还会涉及到应用与底层之间的数据共享和API文件等问题。 在Android中&#xff0c;签名文件同样也存在这个问题。但是android中又区分系统应用和普通应用。系…

Python数据结构实验 串和数组的实现

一、实验目的 1&#xff0e;熟悉串和数组类型的实现方法&#xff0c;了解简单文字处理的设计方法&#xff1b; 2&#xff0e;熟悉Python语言的字符和把字符串处理的原理和方法&#xff1b; 3&#xff0e;了解矩阵的存储结构&#xff0c;运用Python语言进行矩阵简单运算处理。…

UE像素流公网(Windows、Liunx)部署无需GPU服务器

前言 之前有个前端地图服务项目要改成UE来渲染3D,有需要在云服务器上多实例运行,所以就先研究了Windows版本的像素流云渲染,后来客户的云服务器是Linux版CectOS系统,加上又有了一些后端服务在上面运行了不能重装成Windows,所以就又着手去研究了Linux系统的云渲染。 推流…

【笔记】以论文发表形式通俗理解 TCP/IP模型

【笔记】以论文发表形式通俗理解 TCP/IP模型 前言TCP/IP模型理论通俗理解 前言 在网络基础学习过程中&#xff0c;以前只对TCP/IP理解个字面&#xff0c;网上查一下能知道个字面意思&#xff0c;但是连起来到底是什么意思&#xff0c;还是一知半解的&#xff0c;停留在表面&am…