赞
踩
所谓容器的Volume,其实就是将一个宿主机上的目录跟一个容器里的目录绑定挂载在了一起;volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足:
这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境这样的情况还可以接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。
PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。集群中的资源就像一个节点是一个集群资源。PV是诸如卷之类的卷插件,但其生命周期独立于使用PV的任何单个pod。该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统。
PersistentVolumeClaim(PVC)是由用户进行存储的请求,PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim), 它类似于pod。 Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以一次读/写或多次只读)。
PVC和PV是一一对应的,有了 PersistentVolumeClaim,用户只需要告诉 Kubernetes 需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心创建 PersistentVolume 的细节信息。
虽然PersistentVolumeClaims允许用户使用抽象存储资源,但PersistentVolumes对于不同的问题,用户通常需要具有不同属性(例如性能)。群集管理员需要能够提供各种PersistentVolumes不同的方式,而不仅仅是大小和访问模式,而不会让用户了解这些卷的实现方式。对于这些需求,有StorageClass 资源。
StorageClass为管理员提供了一种描述他们提供的存储的“类”的方法。 不同的类可能映射到服务质量级别,或备份策略,或者由群集管理员确定的任意策略。 Kubernetes本身对于什么类别代表是不言而喻的。 这个概念有时在其他存储系统中称为“配置文件”。
PV是群集中的资源。PVC是对这些资源的请求,并且还充当对资源的检查。PV和PVC之间的相互作用遵循以下生命周期:
Provisioning ——> Binding ——>Using——>Releasing——>Recycling
静态提供Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。它们存在于Kubernetes API中,可用于消费
。动态提供Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。要求该类的声明有效地为自己禁用动态配置
。由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他pvc使用。
保留策略:当删除与之绑定的PVC时候,这个PV被标记为released(PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV上,但是该PV不可用,需要手动来处理这些数据并删除该PV
。删除策略:当删除与之绑定的PVC时候
。回收策略:这个在1.14版本中以及被废弃,取而代之的是推荐使用动态存储供给策略,它的功能是当删除与该PV关联的PVC时,自动删除该PV中的所有数据
。注:
1> PV必须先与POD创建,而且只能是网络存储不能属于任何Node,虽然它支持HostPath类型但由于你不知道POD会被调度到哪个Node上,所以你要定义HostPath类型的PV就要保证所有节点都要有HostPath中指定的路径。
2> 目前只有NFS和HostPath类型卷支持回收策略,AWS EBS,GCE PD,Azure Disk和Cinder支持删除(Delete)策略。
GCEPersistentDisk、NFS 、CephFS 、HostPath、Glusterfs 等
Available:资源尚未被claim使用
Bound:卷已经被绑定到claim了
Released:claim被删除,卷处于释放状态,但未被集群回收。
Failed:卷自动回收失败
accessModes:支持三种类型
ReadWriteMany(RWX) 多路读写,卷能被集群多个节点挂载并读写
ReadWriteOnce(RWO) 单路读写,卷只能被单一集群节点挂载读写
ReadOnlyMany(ROX) 多路只读,卷能被多个集群节点挂载且只能读
这里的访问模型总共有三种,但是不同的存储类型支持的访问模型不同,具体支持什么需要查询官网。比如我们这里使用nfs,它支持全部三种。但是ISCI就不支持ReadWriteMany;HostPath就不支持ReadOnlyMany和ReadWriteMany。
PVC是用户层面,作为对存储资源的需求申请,主要包括了存储空间大小、访问模式、PV的选择条件、存储类别等信息的设置
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc1
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: nfs-stoarge
selector:
matchLabels:
pv: test-pv1
spec.accessModes
:访问模式;描述用户应用对存储资源的访问权限。
spec.resources.requests.storage
:资源请求的存储大小;
spec.storageClassName
:存储卷模式,指定一个StorageClass资源对象的名称,具有特定类别的PV只能与请求了该类别的PVC进行绑定;(动态存储);当然,也可以设置为spec.storageClassName="",未设置特定类型的PV只能与不请求任何类型的PVC进行绑定(静态存储)。
spec.selector.matchLabels
: PV的选择条件,可以通过标签匹配进行PV绑定;也可以通过spec.selector.matchExpressions
:进行条件标签描述
PVC一共也有4个生命周期阶段:Available/Bound/Released/Failed
Available: 可用状态,无PV绑定;
Bound:绑定状态,已经和某个PV绑定;
Released:释放状态,被绑定的PV已删除,资源释放,但没有被集群回收;
Failed:失败状态,自动资源回收失败;
kubectl create -f pvc.yaml # 创建(yaml的方式)
kubectl delete pvc pvc_name # 删除
kubectl get pvc # 查看所有PVC
kubectl get pvc pvc_name # 查看某个PVC
kubectl describe pvc pvc_name # 查看详情
注意: 若在某个命名空间下,以上命令可以加上-n ns_name
Pod(Deployment等配置好PVC)—>PVC—>PV—>存储资源。
PVC使用存储资源可以通过静态绑定或者动态绑定,静态模式就是集权管理员预先创建对应的PV对存储特性进行设置;动态模式就是集权管理员预先创建好StorageClass资源对后端存储进行描述,PVC创建时对存储类型进行声明,PVC创建后,k8s会自动创建合适的PV与PVC进行绑定。
创建好PVC后,PVC会在已存在的PV中选择合适的PV进行绑定(可以通过标签进行特定绑定,也可以不通过标签,系统会自动选择合适(容量大小等参数)的PV进行绑定。),绑定成功,状态变成Bound,且该PV被对应的PVC独占绑定,不可以再被其他PVC绑定,除非该PVC释放。若在k8s系统中没有找到合适的PV,则PVC一直处于Pending状态。
在Deployment等资源中,通过spec.template.spec.volumes:进行PVC挂载路径设置。
删除PVC,与该PVC绑定的PV状态就会变成“Released”,该PVC在存储设备上的数据删除后,对应的PV才能与其他的PVC进行绑定。
PV中可以通过spec.persistentVolumeReclaimPolicy设置回收策略,这个主要用于绑定的PVC删除后,资源释放后如何处理该PVC在存储设备上写入的数据。
yum -y install nfs-utils
mkdir -p /nfsdata
echo "/nfsdata *(rw,sync,no_root_squash)" > /etc/exports
systemctl start nfs-server && systemctl enable nfs-server
showmount -e
cat node2-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: # PV建立不要加名称空间,因为PV属于集群级别的 name: pv1 # PV名称 labels: # 这些labels可以不定义 name: pv1 storetype: nfs spec: # 这里的spec和volumes里面的一样 storageClassName: normal accessModes: # 设置访问模型 - ReadWriteOnce - ReadWriteMany - ReadOnlyMany capacity: # 设置存储空间大小 storage: 3Gi persistentVolumeReclaimPolicy: Recycle # 回收策略 nfs: path: /nfsdata server: 10.10.0.110
cat node3-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: # PV建立不要加名称空间,因为PV属于集群级别的 name: pv2 # PV名称 labels: # 这些labels可以不定义 name: pv2 storetype: nfs spec: # 这里的spec和volumes里面的一样 storageClassName: normal accessModes: # 设置访问模型 - ReadWriteOnce - ReadWriteMany capacity: # 设置存储空间大小 storage: 5Gi persistentVolumeReclaimPolicy: Recycle # 回收策略 nfs: path: /nfsdata server: 10.10.0.111
cat node4-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: # PV建立不要加名称空间,因为PV属于集群级别的 name: pv3 # PV名称 labels: # 这些labels可以不定义 name: pv3 storetype: nfs spec: # 这里的spec和volumes里面的一样 storageClassName: normal accessModes: # 设置访问模型 - ReadWriteOnce capacity: # 设置存储空间大小 storage: 10Gi persistentVolumeReclaimPolicy: Recycle # 回收策略 nfs: path: /nfsdata server: 10.10.0.112
kubectl apply -f node2-pv.yaml
kubectl apply -f node3-pv.yaml
kubectl apply -f node4-pv.yaml
红框中可有可无(有则匹配到指定的pv上,也可以在pod中指定如3.4中的pod指定)
分别创建三个pvc,如下所示:
cat pvc-vol.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc01 # pvc的名字 namespace: default labels: # 这些labels可以不定义 name: pvc01 storetype: nfs capacity: 3Gi spec: storageClassName: normal accessModes: # PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV 1. ReadWriteMany resources: # 定义资源要求PV满足这个PVC的要求才会被匹配到 requests: storage: 3Gi # 定义要求有多大空间
cat pvc-vol2.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc02 # pvc的名字 namespace: default labels: # 这些labels可以不定义 name: pvc02 storetype: nfs capacity: 1Gi spec: storageClassName: normal accessModes: # PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV 2. ReadWriteMany resources: # 定义资源要求PV满足这个PVC的要求才会被匹配到 requests: storage: 1Gi # 定义要求有多大空间
cat pvc-vol3.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc03 # pvc的名字 namespace: default labels: # 这些labels可以不定义 name: pvc03 storetype: nfs capacity: 6Gi spec: storageClassName: normal accessModes: # PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV 3. ReadWriteOnce resources: # 定义资源要求PV满足这个PVC的要求才会被匹配到 requests: storage: 6Gi # 定义要求有多大空间
kubectl apply -f pvc-vol.yaml
kubectl apply -f pvc-vol2.yaml
kubectl apply -f pvc-vol3.yaml
cat pod-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: pv
kubectl apply -f pvc-vol.yaml
cat pod-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: # PV建立不要加名称空间,因为PV属于集群级别的 name: nginx-pv # PV名称 labels: # 这些labels可以不定义 name: nginx-pv storetype: nfs spec: # 这里的spec和volumes里面的一样 storageClassName: normal accessModes: # 设置访问模型 - ReadWriteOnce - ReadWriteMany capacity: # 设置存储空间大小 storage: 5Gi persistentVolumeReclaimPolicy: Recycle # 回收策略 nfs: path: /nfsdata server: 10.10.0.111
kubectl apply -f pod-pv.yaml
cat pod-pvc.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-pvc # pvc的名字 namespace: pv labels: # 这些labels可以不定义 name: nginx-pvc storetype: nfs capacity: 5Gi spec: storageClassName: normal accessModes: # PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV 4. ReadWriteOnce resources: # 定义资源要求PV满足这个PVC的要求才会被匹配到 requests: storage: 5Gi # 定义要求有多大空间
由于nginx-pvc消费的是nginx-pv,而nginx-pv是在111节点下的nfs,所以在111的nfs目录下写入文件,进入到nginx的容器同样可以看到
cd /nfsdata/ && echo '13' > index.html #111节点写入数据
kubectl exec -it my-nginx-pod -n pv /bin/bash #进入容器查看
cat pod-pod.yaml
apiVersion: v1 kind: Pod metadata: name: my-nginx-pod namespace: pv labels: name: my-nginx-pod spec: containers: - name: my-nginx image: www.my.com/web/nginx:v1 volumeMounts: - mountPath: "/usr/share/nginx/html" name: nginx-pv volumes: - name: nginx-pv persistentVolumeClaim: claimName: nginx-pvc #将/usr/share/nginx/html挂载到nginx-pvc
发现pod服务正常,且nginx的数据目录使用的nginx-pvc对应的pv,通过kubectl get pv
可以看到nginx-pvc具体消费的那个pv,然后这个pv使用的是哪个nfs的存储,再在对应的nfs的共享目录下看到nginix的数据目录。
cat pvc-deploy.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy spec: replicas: 1 selector: matchLabels: appname: myapp-nginx template: metadata: name: myapp labels: appname: myapp-nginx spec: containers: - name: myapp image: www.my.com/web/nginx:v1 ports: - name: http containerPort: 80 protocol: TCP volumeMounts: - name: nginxdata mountPath : /usr/share/nginx/html volumes: - name: nginxdata persistentVolumeClaim: claimName: pvc02 #将/usr/share/nginx/html挂载到pvc02上
这里通过volumes来声明使用哪个PVC,可以看到和自己定义持久化卷类似,但是这里更加简单了,直接使用PVC的名字即可。在容器中使用/usr/share/nginx/html目录就会把数据写入到NFS服务器上的目录中。
cat pvc-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy
spec:
ports:
5. port: 8000
protocol: TCP
targetPort: 80
selector:
appname: myapp-nginx
type: ClusterIP
kubectl apply -f pvc-svc.yaml
由于使用的是pvc02,而pvc02时在pv1上面消费的,所以在node2上面的nfs服务的目录下下文件,并访问测试
可以看出来PVC就相当于是容器和PV之间的一个接口,使用人员只需要和PVC打交道即可。另外你可能也会想到如果当前环境中没有合适的PV和我的PVC绑定,那么我创建的POD不就失败了么?的确是这样的,不过如果发现这个问题,那么就赶快创建一个合适的PV,那么这时候持久化存储循环控制器会不断的检查PVC和PV,当发现有合适的可以绑定之后它会自动给你绑定上然后被挂起的POD就会自动启动,而不需要你重建POD。
负责把PVC绑定到PV的是一个持久化存储卷控制循环,这个控制器也是kube-manager-controller的一部分运行在master上。而真正把目录挂载到容器上的操作是在POD所在主机上发生的,所以通过kubelet来完成。而且创建PV以及PVC的绑定是在POD被调度到某一节点之后进行的,完成这些操作,POD就可以运行了。下面梳理一下挂载一个PV的过程:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。