数据管理
# 1. 什么是存储卷(Volume)
容器和Pod生命周期可能很短,会被频繁地销毁和创建。容器销毁时,保存在容器内部文件系统中的数据都会被清除,为了持久化保存容器的数据,可以使用Kubernetes 中的卷(Volume);
通俗点讲,Volume就是一个目录,这一点与Docker Volume类似。当Volume被mount到Pod,Pod中的所有容器都可以访问这个Volume
Volume的生命周期独立于容器,Pod中的容器可能被销毁和重建,但Volume会被保留。
# 2. 存储卷分类
Kubernetes支持非常丰富的存储卷类型,包括本地存储(节点)和网络存储,下面只列出一些常见的类型:
emptyDir: 用于存储临时数据的简单空目录。hostPath: 用于将目录从工作节点的文件系统挂载到pod中。persistentVolumeClaim: 用来将持久卷(PersistentVolume)挂载到Pod中。- ....
查看更多支持类型:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/
# 3. emptyDir 使用
emptyDir是最基础的Volume类型,emptyDir Volume 对于容器来说是持久的,对于Pod则不是。当Pod从节点删除时,Volume的内容也会被删除。但如果只是容器被销毁而Pod还在,则Volume不受影响。也就是说:emptyDir Volume的生命周期与Pod一致。
Pod中的所有容器都可以共享Volume,它们可以指定各自的mount路径。下面通过例子来实践emptyDir,配置文件如下:
# 3.1 配置文件
文件:empty-volume-deploy.yaml
apiVersion: v1
kind: Pod
metadata:
name: emptydir-demo
spec:
containers:
- image: busybox
name: write-box
volumeMounts:
- mountPath: /write-dir # 写容器将emptydir-volume挂载到 /write-dir
name: emptydir-volume
args:
- /bin/sh
- -c
- echo "hello world" > /write-dir/hello; sleep 30000 # 写数据到文件
- image: busybox
name: read-box
volumeMounts:
- mountPath: /read-dir # 读容器将emptydir-volume挂载到 /read-dir
name: emptydir-volume
args:
- /bin/sh
- -c
- cat /read-dir/hello; sleep 30000 # 从文件中读出
volumes: # 定义一个名字为:emptydir-volume的emptyDir类型卷
- name: emptydir-volume
emptyDir: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 3.2 发布验证
# 发布资源
$ kubectl apply -f empty-volume-deploy.yaml
pod/emptydir-demo created
# 查看读容器是否度到数据
$ kubectl logs emptydir-demo read-box
hello world
2
3
4
5
6
# 4. hostPath 使用
hostPath Volume的作用是将节点(宿主机)文件系统中已存在的目录挂载给Pod的容器。大部分应用都不会使用hostPath Volume,因为这实际上增加了Pod与节点的耦合,限制了Pod的使用。不过那些需要访问Kubernetes或Docker内部数据(配置文件和二进制库)的应用则需要使用hostPath。
如果
Pod被销毁了,hostPath对应的目录还是会被保留,从这一点来看,hostPath的持久性比emptyDir强。不过一旦Host崩溃,hostPath也就无法访问了。
# 4.1 配置文件
文件: hostpaht-volume-deploy.yaml
apiVersion: v1
kind: Pod
metadata:
name: hostpath-demo
spec:
containers:
- image: busybox
name: go-box
volumeMounts:
- mountPath: /home/go
name: hostpath-volume
args:
- /bin/sh
- -c
- echo "hello world" > /home/go/hello; sleep 30000 # 写数据到文件
volumes: # 定义hostPath类型卷
- name: hostpath-volume
hostPath:
path: /home/go
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 4.2 发布验证
# 发布资源
$ kubectl apply -f hostpaht-volume-deploy.yaml
pod/hostpath-demo created
# 查看pod 所在节点IP
$ kubectl describe pod hostpath-demo
Name: hostpath-demo
Namespace: default
Priority: 0
Node: node2/192.168.148.132 # 这里看到节点IP
Start Time: Fri, 02 Sep 2022 19:02:35 +0800
...
# 到对应的节点查看文件信息
[root@node2 go]$ cat /home/go/hello
hello world
2
3
4
5
6
7
8
9
10
11
12
13
14
# 5. PV和PVC
# 5.1 概念
Volume虽然提供了非常好的数据持久化方案,但是管理性上还有不足。
Pod通常是由应用的开发人员维护,而Volume则通常是由存储系统的管理员维护。开发人员要获得上面的信息,要么询问管理员,要么自己就是管理员。
这样就带来一个管理上的问题: 应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境,这样的情况还可以接受,当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。
为了解决上面的问题,Kubernetes给出的解决方案是PersistentVolume(PV)和PersistentVolumeClaim(PVC)。
PersistentVolume(PV)和PersistentVolumeClaim(PVC)说明:
PersistentVolume(PV):是外部存储系统中的一块存储空间,由管理员创建和维护。与Volume一样,PV具有持久性,生命周期独立于Pod。PersistentVolumeClaim (PVC): 是对PV的申请(Claim)。PVC通常由普通用户创建和维护。需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes会查找并提供满足条件的PV;
# 5.2 关系图

# 6.PV & PVC初使用
# 6.1 创建PV
下面示例是基于
NFS文件共享系统为存储空间,至于NFS文件系统安装,此处省略。
# 6.1.1 配置文件
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1Gi # 指定PV的容量为1G
accessModes:
- ReadWriteOnce # 访问模式
persistentVolumeReclaimPolicy: Retain # 指定PV的回收策略
storageClassName: nfs # 指定PV的class为nfs
nfs:
path: /data/pv1 # 指定PV在NFS服务器上的对应的目录
server: 192.168.148.130 # NFS服务器IP
2
3
4
5
6
7
8
9
10
11
12
13
14
配置参数说明:
accessModes:访问模式
ReadWriteOnce(RWO): 仅允许单个节点挂载读写;ReadOnlyMany(ROX): 允许多个节点挂载只读 ;ReadWriteMan(RWX): 允许多个节点挂载读写 ;
persistentVolumeReclaimPolicy:回收策略
Retain: 需要手工回收;Recycle:自动回收,即删除存储卷目录下的所有文件(包括子目录和隐藏文件),效果相当于执行rm -rf/xx/*,目前仅NFS和hostPath支持此操作;Delete: 删除存储卷,仅部分云端存储系统支持,如AWS EBS、GCE PD、Azure Disk和Cinder。
# 6.1.2 创建&发布
# 创建资源
$ kubectl apply -f nfs-pv.yaml
persistentvolume/nfs-pv created
# 查询状态
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS STORAGECLASS ..
nfs-pv 1Gi RWO Retain Available nfs ..
2
3
4
5
6
7
PV状态说明
Available:可用状态的自由资源,尚未被PVC绑定。Bound:已经绑定至某PVC。Released:绑定的PVC已经被删除,但资源尚未被集群回收。Failed:因自动回收资源失败而处于的故障状态。
# 6.2 创建PVC
# 6.2.1 配置文件
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfs
2
3
4
5
6
7
8
9
10
11
# 6.2.2 创建&绑定
# 创建PVC
$ kubectl apply -f nfs-pvc1.yaml
persistentvolumeclaim/nfs-pvc1 created
# 查看PVC状态
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-pvc1 Bound nfs-pv 1Gi RWO nfs 4s
# 查看PV状态
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS ...
nfs-pv 1Gi RWO Retain Bound default/nfs-pvc1 nfs ...
2
3
4
5
6
7
8
9
10
11
通过
PV和PVC的状态都是Bound,则说明已经绑定成功。
# 6.3 使用PVC
经过上面几个步骤,已经成功创建了持久卷,接下来就可以在Pod中使用存储了。
# 6.3.1 配置文件
apiVersion: v1
kind: Pod
metadata:
name: nfs-demo
spec:
containers:
- name: pvc-pod
image: busybox
volumeMounts:
- mountPath: /pvc
name: pvc-volume
args:
- /bin/sh
- -c
- echo "hello world" > /pvc/hello-pvc; sleep 30000 # 写数据到文件
volumes: # 使用以下方式关联pvc
- name: pvc-volume
persistentVolumeClaim:
claimName: nfs-pvc1 # 和之前创建的pvc名称一致
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 6.3.2 发布 & 验证
# 发布资源
$ kubectl apply -f pvc-pod.yaml
# 查看nfs服务文件
$ tree -l data
data
└── pv1
└── hello-pvc
# 进入pod,查看pod内部文件
$ kubectl exec -it nfs-demo /bin/sh
/ # ls
bin dev etc home proc pvc root sys tmp usr var
/ # cd pvc/
/pvc # ls
hello-pvc
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7. PV动态供给(StorageClass)
在前面的例子中,我们提前创建了PV,然后通过PVC申请PV并在Pod中使用,这种方式叫作静态供给(Static Provision)。
与之对应的是动态供给(Dynamical Provision),即如果没有满足PVC条件的PV,会动态创建PV。相比静态供给,动态供给有明显的优势:不需要提前创建PV,减少了管理员的工作量,效率高。
动态供给是通过StorageClass实现的,每个StorageClass 都包含
provisioner、parameters和reclaimPolicy字段, 这些字段会在 StorageClass 需要动态分配 PersistentVolume 时会使用到。
StorageClass 支持多种类型的卷插件(Provisioner),不同的Provisoner的创建方法各有不同,参数也会有所区别,下面以NFS卷插件为例,进行学习。其他插件可参见文档: https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#aws-ebs
# 7.1 NFS驱动安装
因为Kubernetes 不包含内部 NFS 驱动。所以需要使用外部驱动为 NFS 创建 StorageClass,创建文档参考https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
# 7.1.1 使用helm安装
# 添加仓库
$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
# 安装
$ helm install nfs-client nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.148.130 \ # nfs服务器IP
--set nfs.path=/data/share \ # nfs共享目录
--set image.repository=eipwork/nfs-subdir-external-provisioner \ # 更换镜像地址
--set storageClass.name=nfs-client \
--set storageClass.defaultClass=true # 开启默认使用的nfs的storageclass
2
3
4
5
6
7
8
9
10
# 7.1.2 查看deployment
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-nfs-subdir-external-provisioner 1/1 1 1 2m28s
2
3
# 7.1.3 查看StorageClass
[root@master ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client (default) cluster.local/nfs-client-nfs-subdir-external-provisioner Delete Immediate true 4m17s
2
3
# 7.2 绑定PVC
# 7.2.1 配置文件 nfs-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nfs-pvc
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
2
3
4
5
6
7
8
9
10
11
# 7.2.2 发布
$ kubectl apply -f nfs-pvc.yaml
persistentvolumeclaim/nfs-pvc created
# 查看状态发现状态 已经变成绑定
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-pvc Bound pvc-... 1Mi RWX nfs-client 4s
# 虽然我们没有创建PV,但会自动创建
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS
pvc-... 1Mi RWX Delete Bound default/nfs-pvc nfs-client
2
3
4
5
6
7
8
9
10
11
# 7.3 Pod使用
# 7.3.1 配置文件nfs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nfs-pod-demo
spec:
containers:
- name: pvc-pod
image: busybox
volumeMounts:
- mountPath: /pvc
name: pvc-volume
args:
- /bin/sh
- -c
- echo "hello world..." > /pvc/hello-pvc; sleep 30000 # 写数据到文件
volumes: # 使用以下方式关联pvc
- name: pvc-volume
persistentVolumeClaim:
claimName: nfs-pvc # 和之前创建的pvc名称一致
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 7.3.2 发布 & 验证
# 发布资源
$ kubectl apply -f nfs-pod.yaml
pod/nfs-pod-demo created
2
3
[root@node1 share]# pwd
/data/share
[root@node1 share]# ls
default-nfs-pvc-pvc-71043bd1-5fef-4b6d-8cf5-dbfdbif19a75
[root@node1 share]# cd default-nfs-pvc-pvc-71043bd1-5feef-4b6d-8cf5-dbfdb1f19a75/
[root@node1 default-nfs-pvc-pvc-71043bd1-5fef-4b6d-8cf5-dbfdb1f19a75]# ls
hello-pvc
[root@node1 default-nfs-pvc-pvc-71043bd1-5fef-4b6d-8cf55-dbfdb1f19a75]# cat hello-pvc
hello world..
2
3
4
5
6
7
8
9