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