赞
踩
在 k8s 中,存储卷(Volume)是一种抽象的概念,用于提供 pod 中容器的持久化存储。存储卷允许将数据存储在 pod 的生命周期之外,以便在容器重启、迁移或重新调度时保留数据。
存储卷可以连接到 pod 中的一个或多个容器,并提供持久化的存储空间。这些存储卷可以是来自 k8s 集群的本地存储、网络存储、云存储提供商或外部存储系统等。
存储卷可以用于各种用途,例如:
由于 pod 本身是具有生命周期的,所以 pod 内部运行的容器及相关的数据,在 pod 中是无法持久化存储的。我们知道,docker 支持配置容器使用存储卷,已实现数据在容器之外的存储空间中持久化存储。相应的,k8s 也支持类似的存储卷功能,此处存储卷与 pod 资源绑定。
简单来说,存储卷是定义在 pod 资源之上、可被其他内容所有容器挂载的共享目录,它关联至外部的存储设备之上的存储空间,从而独立于容器自身的文件系统,而数据是否具有持久化存储能力取决于存储卷自身是否支持持久存储机制,与 pod 无关。
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:初始内容为空的本地临时目录
它是一个临时卷(Ephemeral Volume)
与 pod 一起创建和删除,生命周期与 pod 相同
emptyDir 会创建一个初始状态为空的目录
通常使用本地临时存储来设置缓存、保存日志等
例如,将 redis 的存储目录设置为 emptyDir,编辑文件redis-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-pod
spec:
containers:
- name: redis01
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}
[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:全称是 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-nfs name: nginx-nfs spec: replicas: 2 selector: matchLabels: app: nginx-nfs template: metadata: labels: app: nginx-nfs spec: containers: - image: nginx01 name: nginx volumeMounts: - name: nginx-storage mountPath: /usr/share/nginx/html volumes: - name: nginx-storage nfs: server: 192.168.0.1 path: /nfs/data/nginx-nfs
创建一个 deployment 部署,自行测试即可,在主节点的/nfs/data/nginx-nfs
目录,新建 index.html,编辑内容,在容器里进行访问测试。
主节点的/nfs/data/nginx-nfs
目录也和从节点的目录共通(node1 的目录就是/nfs/node1/nginx-nfs
),也都可以进行测试
结论:无论容器怎么部署怎么删除,数据都可以持久化保存了
持久卷(Persistent Volume):删除 pod 后,卷不会被删除
PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置
PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格
k8s 支持的存储系统非常多,要求大家全都掌握,是不现实的。为了屏蔽底层存储实现细节,方便使用,引入了 PV 和 PVC 两种资源对象。
封装机制!数据中台
Persistent Volume 是持久卷的意思,是对底层共享存储的一种抽象封装。一般情况 PV 由管理员创建和配置,它与底层具体的存储技术有关,通过插件完成与存储的对接。
PV 是存储资源的抽象,资源清单如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
nfs: # 存储类型,与底层真正存储对应
capacity: # 存储能力,目前只支持存储空间的设置
storage: 2Gi
accessModes: # 访问模式
storageClassName: # 存储类别
persistentVolumeReclaimPolicy: # 回收策略
accessModes 用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
回收策略(persistentVolumeReclaimPolicy)
persistentVolumeReclaimPolicy 当 PV 不再被使用了之后,对其的处理方式。目前支持三种策略:
rm -rf /thevolume/*
一个 PV 的生命周期中,可能会处于4种不同的阶段:
Persistent Volume Claim 持久卷声明的意思,是用户对存储需求的一种声明。也就是向 k8s 系统发出的一种资源需求申请。
PVC 作为资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc
namespace: dev
spec:
accessModes: # 访问模式
selector: # 采用标签对PV选择
storageClassName: # 存储类别
resources: # 请求空间
requests:
storage: 5Gi
创建一个 pv,创建一个 pvc,创建一个 pod 绑定 pvc 就可以了!
pv 做就是连接存储系统,规定一个大小的空间,权限配置
pvc 做的就是写一个声明,根据自己的使用者的要求(存储系统、大小、权限),来匹配 pv
pod 使用 pvc volumes 挂载的类型!
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03
my-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: pv01-10m spec: capacity: storage: 10M accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/01 server: 192.168.0.1 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv02-1gi spec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/02 server: 192.168.0.1 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv03-3gi spec: capacity: storage: 3Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/03 server: 192.168.0.1
[root@k8s-master k8s]# kubectl apply -f my-pv.yaml
persistentvolume/pv01-10m created
persistentvolume/pv02-1gi created
persistentvolume/pv03-3gi created
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
my-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 500Mi
storageClassName: nfs
[root@k8s-master k8s]# vim my-pvc.yaml
[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 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
[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,也就是释放状态
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
[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
my-pvc-pod.yaml
apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx-pod-pvc name: nginx-pod-pvc spec: replicas: 2 selector: matchLabels: app: nginx-pod-pvc template: metadata: labels: app: nginx-pod-pvc spec: containers: - image: nginx name: nginx01 volumeMounts: - name: nginx-volume mountPath: /usr/share/nginx/html volumes: - name: nginx-volume persistentVolumeClaim: claimName: nginx-pvc
[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
[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-pvc ReadOnly: false kube-api-access-5rlkl: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s ......
/nfs/data/03
,所以我们去这个目录下编辑文件[root@k8s-master k8s]# cd /nfs/data/03
[root@k8s-master 03]# echo "hello yigongsui" > index.html
[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 之间的相互作用遵循以下生命周期:
在用户定义好 PVC 之后,系统将根据 PVC 对存储资源的请求在已存在的 PV 中选择一个满足条件的。
pod 使用 volume 的定义,将 PVC 挂载到容器内的某个路径进行使用。
当存储资源使用完毕后,用户可以删除 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
官方地址:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#local
在 java 中,我们知道 class 是类的概念,相当于一个模板,通过类来创建对象
那么 StorageClass 其实就相当于是 pv 的模板,通过这个模版可以自动帮我们创建 pv 并通过 pvc 自动挂载上
接下来我们去理解 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,多个模版!
local-path-storage.yaml
去创建存储类apiVersion: v1 kind: Namespace metadata: name: local-path-storage --- apiVersion: v1 kind: ServiceAccount metadata: name: local-path-provisioner-service-account namespace: 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.io kind: ClusterRole name: local-path-provisioner-role subjects: - kind: ServiceAccount name: local-path-provisioner-service-account namespace: local-path-storage --- apiVersion: apps/v1 kind: Deployment metadata: name: local-path-provisioner namespace: local-path-storage spec: replicas: 1 selector: matchLabels: app: local-path-provisioner template: metadata: labels: app: local-path-provisioner spec: serviceAccountName: local-path-provisioner-service-account containers: - name: local-path-provisioner image: rancher/local-path-provisioner:master-head imagePullPolicy: IfNotPresent command: - local-path-provisioner - --debug - start - --config - /etc/config/config.json volumeMounts: - name: config-volume mountPath: /etc/config/ env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace volumes: - name: config-volume configMap: 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-config namespace: local-path-storage data: config.json: |- { "nodePathMap":[ { "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES", "paths":["/opt/local-path-provisioner"] } ] } setup: |- #!/bin/sh set -eu mkdir -m 0777 -p "$VOL_DIR" teardown: |- #!/bin/sh set -eu rm -rf "$VOL_DIR" helperPod.yaml: |- apiVersion: v1 kind: Pod metadata: name: helper-pod spec: containers: - name: helper-pod image: busybox imagePullPolicy: IfNotPresent
[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
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 系统中是自带的。
mysql-pod.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: local-path-pvc namespace: default spec: accessModes: - ReadWriteOnce storageClassName: local-path resources: requests: storage: 1Gi --- apiVersion: v1 kind: Pod metadata: name: mysql-pod spec: containers: - image: mysql:5.7 name: mysql01 env: - name: MYSQL_ROOT_PASSWORD value: "123456" ports: - containerPort: 3306 volumeMounts: - mountPath: /var/lib/mysql name: local-mysql-data volumes: - name: local-mysql-data persistentVolumeClaim: 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
可以看到 pv 和 pvc 都自动创建了
创建 pod 时去申请 pvc,StorageClass 会动态创建 pvc 和 pv,pvc 申请多大存储 pv 就会创建多大空间
local
卷也存在自身的问题,当 pod 所在节点上的存储出现故障或者整个节点不可用时,pod 和卷都会失效,仍然会丢失数据,因此最安全的做法还是将数据存储到集群之外的存储或云存储上。同时配置,做一些灾备,保证数据不会丢失!
本地存储:
存储卷:
pv
pvc
storageClass
至此,k8s 数据持久化搞定!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。