6.5 从底层存储技术解耦pod
6.5 从底层存储技术解耦pod
到目前为止,我们探索过的所有持久卷类型都要求pod的开发人员了解集群中可用的真实网络存储的基础结构。例如,要创建支持NFS协议的卷,开发人员必须知道NFS节点所在的实际服务器。这违背了Kubernetes的基本理念,这个理念旨在向应用程序及其开发人员隐藏真实的基础设施,使他们不必担心基础设施的具体状态,并使应用程序可在大量云服务商和数据企业之间进行功能迁移。
理想的情况是,在Kubernetes上部署应用程序的开发人员不需要知道底层使用的是哪种存储技术,同理他们也不需要了解应该使用哪些类型的物理服务器来运行pod,与基础设施相关的交互是集群管理员独有的控制领域。
当开发人员需要一定数量的持久化存储来进行应用时,可以向Kubernetes请求,就像在创建pod时可以请求CPU、内存和其他资源一样。系统管理员可以对集群进行配置让其可以为应用程序提供所需的服务。
6.5.1 介绍持久卷和持久卷声明
在Kubernetes集群中为了使应用能够正常请求存储资源,同时避免处理基础设施细节,引入了两个新的资源,分别是持久卷和持久卷声明,这名字可能有点误导,因为正如在前面几节中看到的,甚至常规的Kubernetes卷也可以用来存储持久性数据。
在pod中使用PersistentVolume(持久卷,简称PV)要比使用常规的pod卷复杂一些,研发人员无须向他们的pod中添加特定技术的卷,而是由集群管理员设置底层存储,然后通过Kubernetes API服务器创建持久卷并注册。在创建持久卷时,管理员可以指定其大小和所支持的访问模式。
当集群用户需要在其pod中使用持久化存储时,他们首先创建持久卷声明(PersistentVolumeClaim,简称PVC)清单,指定所需要的最低容量要求和访问模式,然后用户将持久卷声明清单提交给Kubernetes API服务器,Kubernetes将找到可匹配的持久卷并将其绑定到持久卷声明。
持久卷声明可以当作pod中的一个卷来使用,其他用户不能使用相同的持久卷,除非先通过删除持久卷声明绑定来释放。
关于挂载、持久性和 minikube 主机的说明
minikube 被配置为将存储在以下目录下的文件持久化,这些文件是在 Minikube VM 中创建的(如果在裸机上运行,则在本地主机上)。重新启动时,您可能会丢失其他目录中的数据。
/data
/var/lib/minikube
/var/lib/docker
/var/lib/containerd
/var/lib/buildkit
/var/lib/containers
/tmp/hostpath_pv
/tmp/hostpath-provisioner
这是将数据保存在“/data”目录中的示例 PersistentVolume 配置:
mongodb-pv-hostpath.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv
spec:
capacity:
storage: 1Gi # 定义PersistentVolume的大小
accessModes:
- ReadWriteOnce #单个客户端挂载为读写模式,多个客户端挂载为只读模式
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain #当声明被释放后 persistentVolume将会保留(不清理和删除)
hostPath:
path: /tmp/mongodb
在创建持久卷时,管理员需要告诉Kubernetes其对应的容量需求,以及它是否可以由单个节点或多个节点同时读取或写入。管理员还需要告诉Kubernetes如何处理PersistentVolume(当持久卷声明的绑定被删除时)。最后,无疑也很重要的事情是,管理员需要指定持久卷支持的实际存储类型、位置和其他属性。如果仔细观察,当直接在pod卷中引用GCE持久磁盘时,最后一部分配置与前面完全相同(在下面的代码清单中再次显示)。
在使用kubectl create命令创建持久卷之后,应该可以声明它了。看看是否列出了所有的持久卷:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mongodb-py 5Gi RWO Retain Available 2m42s
注意 部分省略,同时pv也用作persistentvolume的简写。
正如预期的那样,持久卷显示为可用,因为你还没创建持久卷声明。
6.5.3 通过创建持久卷声明来获取持久卷
假设现在需要部署一个需要持久化存储的pod,将要用到之前创建的持久卷,但是不能直接在pod内使用,需要先声明一个。
声明一个持久卷和创建一个pod是相对独立的过程,因为即使pod被重新调度(切记,重新调度意味着先前的pod被删除并且创建了一个新的pod),我们也希望通过相同的持久卷声明来确保可用。
创建持久卷声明
现在开始创建一个声明。先参考下面的代码清单所示的内容来准备一个持久卷声明清单,并通过kubectl create将其发布到Kubernetes API。
mongodb-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc # 声明的名称,稍后将声明当作pod的卷使用时候用到
spec:
resources:
requests:
storage: 1Gi #申请存储空间
accessModes:
- ReadWriteOnce #允许单个客户端访问(读取和写入)
storageClassName: "" #与动态配置有关
当创建好声明,Kubernetes就会找到适当的持久卷并将其绑定到声明,持久卷的容量必须足够大以满足声明的需求,并且卷的访问模式必须包含声明中指定的访问模式。在该示例中,声明请求1 GiB的存储空间和ReadWriteOnce访问模式。之前创建的持久卷符合刚刚声明中的这两个条件,所以它被绑定到对应的声明中。我们可以通过检查声明来查看。
列举持久卷声明
列举出所有的持久卷声明来查看PVC的状态:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mongodb-pvc Bound mongodb-pv 1Gi RWO,ROX 26s
注意 我们使用pvc来代称persistentvolumeclaim。 PVC状态显示已与持久卷的mongodb-pv绑定。请留意访问模式的简写:
- RWO——ReadWriteOnce——仅允许单个节点挂载读写。
- ROX——ReadOnlyMany——允许多个节点挂载只读。
- RWX——ReadWriteMany——允许多个节点挂载读写这个卷。
注意 RWO、ROX、RWX涉及可以同时使用卷的工作节点的数量而并非pod的数量。
列举持久卷
通过使用kubectl get命令,我们还可以看到持久卷现在已经Bound,并且不再是Available。
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mongodb-pv 1Gi RWO,ROX Retain Bound custom/mongodb-pvc 27m
持久卷显示被绑定在custom/mongodb-pvc的声明上,我们之前有提到过持久卷是集群范围的,因此不能在特定的命名空间中创建,但是持久卷声明又只能在特定的命名空间创建,所以持久卷和持久卷声明只能被同一命名空间内的pod创建使用。
6.5.4 在pod中使用持久卷声明
持久卷现在已经可用了,除非先释放掉卷,否则没有人可以申明相同的卷。要在pod中使用持久卷,需要在pod的卷中引用持久卷声明名称,如下面的代码清单所示。
代码清单6.12 使用PVC卷的pod: mongodb-pod-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: mongodb
spec:
containers:
- image: mongo
name: mongodb
volumeMounts:
- name: mongodb-data
mountPath: /data/db
ports:
- containerPort: 27017
protocol: TCP
volumes:
- name: mongodb-data
persistentVolumeClaim:
claimName: mongodb-pvc #在pod卷中通过名称引用持久卷声明
继续创建pod,通过再次运行MongoDB shell,应该可以看到之前存储的数据,如下面的代码清单所示。
代码清单6.13 在已使用PVC和PV的pod中检索MongoDB的持久化数据
$ kubectl exec -it mongodb -- mongo
> use mystore
> db.foo.find()
符合预期,可以检索之前存储到MongoDB的文档。
6.5.5 了解使用持久卷和持久卷声明的好处
pod可以直接使用,或者通过持久卷和持久卷声明,这两种方式使用GCE持久磁盘。
考虑如何使用这种间接方法从基础设施获取存储,对于应用程序开发人员(或者集群用户)来说更加简单。是的,这需要额外的步骤来创建持久卷和持久卷声明,但是研发人员不需要关心底层实际使用的存储技术。
此外,现在可以在许多不同的Kubernetes集群上使用相同的pod和持久卷声明清单,因为它们不涉及任何特定依赖于基础设施的内容。声明说:“我需要x存储量,并且我需要能够支持一个客户端同时读取和写入。”然后pod通过其中一个卷的名称来引用声明。
6.5.6 回收持久卷
在结束关于持久卷的本节前,让我们先做一个快速实验,删除pod和持久卷声明:
$ kubectl delete pod mongodb
pod "mongodb" deleted
$ kubectl delete pvc mongodb-pvc
persistentvolumeclaim "mongodb-pvc" deleted
如果再次创建持久卷声明会怎样?它是否会被绑定到持久卷?在创建声明后,kubectl get pvc命令返回的结果是什么?
$ kubectl get pvc
这个持久卷声明的状态显示为Pending,有趣。之前创建声明的时候,它立即绑定到了持久卷,那么为什么现在不绑定呢?也许列出持久卷可以看得更清楚一些:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mongodb-pv 1Gi RWO,ROX Retain Released test/mongodb-pvc 3h21m
STATUS列显示持久卷的状态是Released,不像之前那样是Available。原因在于之前已经使用过这个卷,所以它可能包含前一个声明人的数据,如果集群管理员还没来得及清理,那么不应该将这个卷绑定到全新的声明中。除此之外,通过使用相同的持久卷,新的pod可以读取由前一个pod存放的数据,即使声明和pod是在不同的命名空间中创建的(因此有可能属于不同的集群租户)。
手动回收持久卷
通过将persistentVolumeReclaimPolicy设置为Retain从而通知到Kubernetes,我们希望在创建持久卷后将其持久化,让Kubernetes可以在持久卷从持久卷声明中释放后仍然能保留它的卷和数据内容。据我所知,手动回收持久卷并使其恢复可用的唯一方法是删除和重新创建持久卷资源。当这样操作时,你将决定如何处理底层存储中的文件:可以删除这些文件,也可以闲置不用,以便在下一个pod中复用它们。
手动回收持久卷:
$ kubectl delete pv mongodb-pv
自动回收持久卷
存在两种其他可行的回收策略:Recycle 和Delete。第一种删除卷的内容并使卷可用于再次声明,通过这种方式,持久卷可以被不同的持久卷声明和pod反复使用.
而另一边,Delete策略删除底层存储。需要注意当前GCE持久磁盘无法使用Recycle选项。这种类型的持久卷只支持Retain和Delete策略,其他类型的持久磁盘可能支持这些选项,也可能不支持这些选项。因此,在创建自己的持久卷之前,一定要检查卷中所用到的特定底层存储支持什么回收策略。提示 可以在现有的持久卷上更改持久卷回收策略。比如,如果最初将其设置为Delete,则可以轻松地将其更改为Retain,以防止丢失有价值的数据。