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 name: emptydir-volume args: - /bin/sh - -c - echo "hello world" > /write-dir/hello; sleep 30000 - image: busybox name: read-box volumeMounts: - mountPath: /read-dir name: emptydir-volume args: - /bin/sh - -c - cat /read-dir/hello; sleep 30000 volumes: - name: emptydir-volume emptyDir: {}
3.2 发布验证 $ kubectl apply -f empty-volume-deploy.yaml pod/emptydir-demo created $ kubectl logs emptydir-demo read-box hello world
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: - name: hostpath-volume hostPath: path: /home/go
4.2 发布验证 $ kubectl apply -f hostpaht-volume-deploy.yaml pod/hostpath-demo created $ kubectl describe pod hostpath-demo Name: hostpath-demo Namespace: default Priority: 0 Node: node2/192.168.148.132 Start Time: Fri, 02 Sep 2022 19:02:35 +0800 ... [root@node2 go]$ cat /home/go/hello hello world
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 accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /data/pv1 server: 192.168 .148 .130
配置参数说明:
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 ..
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
6.2.2 创建&绑定 $ kubectl apply -f nfs-pvc1.yaml persistentvolumeclaim/nfs-pvc1 created $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-pvc1 Bound nfs-pv 1Gi RWO nfs 4s $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS ... nfs-pv 1Gi RWO Retain Bound default/nfs-pvc1 nfs ...
通过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: - name: pvc-volume persistentVolumeClaim: claimName: nfs-pvc1
6.3.2 发布 & 验证 $ kubectl apply -f pvc-pod.yaml $ tree -l data data └── pv1 └── hello-pvc $ kubectl exec -it nfs-demo /bin/sh / bin dev etc home proc pvc root sys tmp usr var / /pvc hello-pvc
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 \ --set nfs.path=/data/share \ --set image.repository=eipwork/nfs-subdir-external-provisioner \ --set storageClass.name=nfs-client \ --set storageClass.defaultClass=true
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
7.1.3 查看StorageClass
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
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 $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS pvc-... 1Mi RWX Delete Bound default/nfs-pvc nfs-client
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: - name: pvc-volume persistentVolumeClaim: claimName: nfs-pvc
7.3.2 发布 & 验证 $ kubectl apply -f nfs-pod.yaml pod/nfs-pod-demo created