ks8的数据管理---PV/PVC

1、背景

所谓容器的Volume,其实就是将一个宿主机上的目录跟一个容器里的目录绑定挂载在了一起;volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足:

  1. 要使用 Volume,Pod 必须事先知道Volume来自哪儿,需要提前创建;
  2. Pod 通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息:要么询问管理员;要么自己就是管理员。

这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境这样的情况还可以接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。

2、PV

1)介绍

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本身对于什么类别代表是不言而喻的。 这个概念有时在其他存储系统中称为“配置文件”。

2)生命周期

PV是群集中的资源。PVC是对这些资源的请求,并且还充当对资源的检查。PV和PVC之间的相互作用遵循以下生命周期:
Provisioning ——> Binding ——>Using——>Releasing——>Recycling

step1:供应准Provisioning—通过集群外的存储系统或者云平台来提供存储持久化支持。
  • 静态提供Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。它们存在于Kubernetes API中,可用于消费
  • 动态提供Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。要求该类的声明有效地为自己禁用动态配置
step2:绑定Binding—用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。
step3:使用Using—用户可在pod中像volume一样使用pvc。
step4:释放Releasing—用户删除pvc来回收存储资源,pv将变成“released”状态。

由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他pvc使用。

step5:回收Recycling—pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。
  • 保留策略:当删除与之绑定的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)策略。

3)PV 支持的类型

GCEPersistentDisk、NFS 、CephFS 、HostPath、Glusterfs 等

4)PV卷阶段状态

Available:资源尚未被claim使用
Bound:卷已经被绑定到claim了
Released:claim被删除,卷处于释放状态,但未被集群回收。
Failed:卷自动回收失败

5)PV的访问模型

accessModes:支持三种类型
ReadWriteMany(RWX) 多路读写,卷能被集群多个节点挂载并读写
ReadWriteOnce(RWO) 单路读写,卷只能被单一集群节点挂载读写
ReadOnlyMany(ROX) 多路只读,卷能被多个集群节点挂载且只能读
这里的访问模型总共有三种,但是不同的存储类型支持的访问模型不同,具体支持什么需要查询官网。比如我们这里使用nfs,它支持全部三种。但是ISCI就不支持ReadWriteMany;HostPath就不支持ReadOnlyMany和ReadWriteMany。

3、PVC

1)介绍

PVC是用户层面,作为对存储资源的需求申请,主要包括了存储空间大小、访问模式、PV的选择条件、存储类别等信息的设置

2)PVC的参数详解(PVC的yaml模板)

apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: test-pvc1
spec: 
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs-stoarge
  selector:
  	matchLabels:
  	  pv: test-pv1

3)PVC参数说明

spec.accessModes:访问模式;描述用户应用对存储资源的访问权限。

  • RWO:ReadWriteOnce,仅允许单个节点挂载进行读写;
  • ROX:ReadOnlyMany,允许多个节点挂载且只读;
  • RWX:ReadWriteMany,允许多个节点挂载进行读写;

spec.resources.requests.storage:资源请求的存储大小;
spec.storageClassName:存储卷模式,指定一个StorageClass资源对象的名称,具有特定类别的PV只能与请求了该类别的PVC进行绑定;(动态存储);当然,也可以设置为spec.storageClassName="",未设置特定类型的PV只能与不请求任何类型的PVC进行绑定(静态存储)。
spec.selector.matchLabels: PV的选择条件,可以通过标签匹配进行PV绑定;也可以通过spec.selector.matchExpressions:进行条件标签描述

4)PVC的生命周期

PVC一共也有4个生命周期阶段:Available/Bound/Released/Failed
Available: 可用状态,无PV绑定;
Bound:绑定状态,已经和某个PV绑定;
Released:释放状态,被绑定的PV已删除,资源释放,但没有被集群回收;
Failed:失败状态,自动资源回收失败;

5)PVC的常用命令

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

4、PVC和PV进行绑定原则(pv和pvc的机制)

1)pv和pvc绑定要求

  1. PV和PVC的spec字段要匹配.比如PV的存储(storage)大小
  2. PV和PVC的storageClassName字段必须一样
  3. PV描述的是持久化存储卷 这个API对象主要定义的是一个持久化存储在宿主机上的目录,如一个NFS的挂载目录;PVC可以理解为持久化存储的,它提供了对某种持久化存储的描述,但不提供具体的实现
  4. 持久化存储的实现部分则由PV负责完成
  5. PV与PVC进行绑定,其实就是将这个PV对象的名字,填在了PVC对象的spec.volumeName字段上
    当PV和PVC成功绑定后 Pod就能像使用hostPath等常规类型的Volume一样在YAML文件中使用PVC

2)共享存储的步骤

Pod(Deployment等配置好PVC)—>PVC—>PV—>存储资源。

1> 资源供应

PVC使用存储资源可以通过静态绑定或者动态绑定,静态模式就是集权管理员预先创建对应的PV对存储特性进行设置;动态模式就是集权管理员预先创建好StorageClass资源对后端存储进行描述,PVC创建时对存储类型进行声明,PVC创建后,k8s会自动创建合适的PV与PVC进行绑定。

2> 资源绑定

创建好PVC后,PVC会在已存在的PV中选择合适的PV进行绑定(可以通过标签进行特定绑定,也可以不通过标签,系统会自动选择合适(容量大小等参数)的PV进行绑定。),绑定成功,状态变成Bound,且该PV被对应的PVC独占绑定,不可以再被其他PVC绑定,除非该PVC释放。若在k8s系统中没有找到合适的PV,则PVC一直处于Pending状态。

3> 资源使用

在Deployment等资源中,通过spec.template.spec.volumes:进行PVC挂载路径设置。

4> 资源释放

删除PVC,与该PVC绑定的PV状态就会变成“Released”,该PVC在存储设备上的数据删除后,对应的PV才能与其他的PVC进行绑定。

5> 资源回收

PV中可以通过spec.persistentVolumeReclaimPolicy设置回收策略,这个主要用于绑定的PVC删除后,资源释放后如何处理该PVC在存储设备上写入的数据。

  • Retain:保留,删除PVC后,PV保留数据;
  • Recycle:回收空间,删除PVC后,简单的清除文件;(NFS和HostPath存储支持);
  • Delete:删除,删除PVC后,与PV相连接的后端存储会删除数据;(AWS EBS、Azure Disk、Cinder volumes、GCE PD支持)。

5、案例演示

1)搭建nfs服务(node2|node3|node4均安装)

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

在这里插入图片描述

2)创建pv(pv的yaml需要有metadata.labels进行标签标记)

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

在这里插入图片描述

3)创建pvc,绑定pv(pv的yaml需要有metadata.labels进行标签标记)

在这里插入图片描述
红框中可有可无(有则匹配到指定的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

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

4)在pod中使用PVC

step1:创建命名空间

cat pod-ns.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: pv
kubectl apply -f pvc-vol.yaml
step2:创建pv

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
step3:创建pvc

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 #进入容器查看

在这里插入图片描述

step4:创建pod

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的数据目录。

5)在deploy中使用pvc(利用在4.2和4.3中已创建好的pv和pvc)

step1:创建deployment

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服务器上的目录中。

step2:创建svc

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。

6)小结

负责把PVC绑定到PV的是一个持久化存储卷控制循环,这个控制器也是kube-manager-controller的一部分运行在master上。而真正把目录挂载到容器上的操作是在POD所在主机上发生的,所以通过kubelet来完成。而且创建PV以及PVC的绑定是在POD被调度到某一节点之后进行的,完成这些操作,POD就可以运行了。下面梳理一下挂载一个PV的过程:

  1. 用户提交一个包含PVC的POD
  2. 调度器根据各种调度算法把该POD分配到某个节点,比如node01
  3. Node01上的kubelet等待Volume Manager准备存储设备
  4. PV控制器调用存储插件创建PV并与PVC进行绑定
  5. Attach/Detach Controller或Volume Manager通过存储插件实现设备的attach。(这一步是针对块设备存储)
  6. Volume Manager等待存储设备变为可用后,挂载该设备到/var/lib/kubelet/pods/<Pod 的ID>/volumes/kubernetes.io~<Volume 类型 >/<Volume 名字 >目录上
  7. Kubelet被告知卷已经准备好,开始启动POD,通过映射方式挂载到容器中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值