云原生|kubernetes|持久化存储pv,pvc和StorageClass的学习

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 云原生|kubernetes|持久化存储pv,pvc和StorageClass的学习

前言:

kubernetes的持久化存储前面学习的时候好像有很多误区,在此,做一个准确的总结,并且与各位能够有一个深入的探讨。

A,

为什么需要持久化存储?

不管是怎么学习kubernetes,都需要先弄明白一件事,学的目的是什么?因此,我们需要先搞清楚,为什么需要持久化存储,原因如下:

在k8s中部署的应用都是以pod容器的形式运行的,因为Pod是有生命周期的,如果pod不挂载数据卷,那pod被删除或重启后这些数据会随之消失,如果想要长久的保留这些数据就要用到pod数据持久化存储。

例如,web服务,数据库服务,这些服务很多都是有状态的,这么说吧,比如nginx发布一个项目,你总不可能自己docker build一个镜像,把项目打进镜像,然后kubernetes在启动这个镜像吧,并且对外提供服务的时候,比如账号注册这些动态数据,如果pod意外挂掉了,岂不是懵逼了?因此,我们需要把pod内的一些数据做本地(或者远程)存储并且期限是永久的。

B,

存储方案介绍

数据持久化存储的迫切性是能够理解了,那么,数据是应该或者说可以存储到哪里呢(也可以理解为存储方案)?

方案有很多,目前,Kubernetes 支持的存储卷可简单归为以下类别,它们也各自有着不少的实现插件。

1)临时存储卷:emptyDir。

2)本地存储卷:hostPath 和 local。

3)网络存储卷:

云存储——awsElasticBlockStore、gcePersistentDisk、azureDisk 和 azureFile。

网络文件系统——NFS、GlusterFS、CephFS 和 Cinder。

网络块设备——iscsi、FC、RBD 和 vSphereVolume。

网络存储平台——Quobyte、PortworxVolume、StorageOS 和 ScaleIO。

4)特殊存储卷:Secret、ConfigMap、DownwardAPI 和 Projected。

5)扩展支持第三方存储的存储接口(Out-of-Tree 卷插件):CSI 和 FlexVolume。

下面是kubernetes大致支持的一些存储方案,可以看到有最为常用的local,nfs,iscsi,ceph,cinder等等类型。茫茫多的持久化存储方案,当然是先学习最基本的那几种了:hostpath,local,nfs

 

[root@master coredns]# k explain pv.spec
KIND:     PersistentVolume
VERSION:  v1
RESOURCE: spec <Object>
DESCRIPTION:
     Spec defines a specification of a persistent volume owned by the cluster.
     Provisioned by an administrator. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
     PersistentVolumeSpec is the specification of a persistent volume.
FIELDS:
   accessModes  <[]string>
     AccessModes contains all ways the volume can be mounted. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes
   awsElasticBlockStore <Object>
     AWSElasticBlockStore represents an AWS Disk resource that is attached to a
     kubelet's host machine and then exposed to the pod. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
   azureDisk  <Object>
     AzureDisk represents an Azure Data Disk mount on the host and bind mount to
     the pod.
   azureFile  <Object>
     AzureFile represents an Azure File Service mount on the host and bind mount
     to the pod.
   capacity <map[string]string>
     A description of the persistent volume's resources and capacity. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity
   cephfs <Object>
     CephFS represents a Ceph FS mount on the host that shares a pod's lifetime
   cinder <Object>
     Cinder represents a cinder volume attached and mounted on kubelets host
     machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md
   claimRef <Object>
     ClaimRef is part of a bi-directional binding between PersistentVolume and
     PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName
     is the authoritative bind between PV and PVC. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding
   csi  <Object>
     CSI represents storage that is handled by an external CSI driver (Beta
     feature).
   fc <Object>
     FC represents a Fibre Channel resource that is attached to a kubelet's host
     machine and then exposed to the pod.
   flexVolume <Object>
     FlexVolume represents a generic volume resource that is
     provisioned/attached using an exec based plugin.
   flocker  <Object>
     Flocker represents a Flocker volume attached to a kubelet's host machine
     and exposed to the pod for its usage. This depends on the Flocker control
     service being running
   gcePersistentDisk  <Object>
     GCEPersistentDisk represents a GCE Disk resource that is attached to a
     kubelet's host machine and then exposed to the pod. Provisioned by an
     admin. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
   glusterfs  <Object>
     Glusterfs represents a Glusterfs volume that is attached to a host and
     exposed to the pod. Provisioned by an admin. More info:
     https://examples.k8s.io/volumes/glusterfs/README.md
   hostPath <Object>
     HostPath represents a directory on the host. Provisioned by a developer or
     tester. This is useful for single-node development and testing only!
     On-host storage is not supported in any way and WILL NOT WORK in a
     multi-node cluster. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath
   iscsi  <Object>
     ISCSI represents an ISCSI Disk resource that is attached to a kubelet's
     host machine and then exposed to the pod. Provisioned by an admin.
   local  <Object>
     Local represents directly-attached storage with node affinity
   mountOptions <[]string>
     A list of mount options, e.g. ["ro", "soft"]. Not validated - mount will
     simply fail if one is invalid. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options
   nfs  <Object>
     NFS represents an NFS mount on the host. Provisioned by an admin. More
     info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
   nodeAffinity <Object>
     NodeAffinity defines constraints that limit what nodes this volume can be
     accessed from. This field influences the scheduling of pods that use this
     volume.
   persistentVolumeReclaimPolicy  <string>
     What happens to a persistent volume when released from its claim. Valid
     options are Retain (default for manually created PersistentVolumes), Delete
     (default for dynamically provisioned PersistentVolumes), and Recycle
     (deprecated). Recycle must be supported by the volume plugin underlying
     this PersistentVolume. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming
   photonPersistentDisk <Object>
     PhotonPersistentDisk represents a PhotonController persistent disk attached
     and mounted on kubelets host machine
   portworxVolume <Object>
     PortworxVolume represents a portworx volume attached and mounted on
     kubelets host machine
   quobyte  <Object>
     Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
   rbd  <Object>
     RBD represents a Rados Block Device mount on the host that shares a pod's
     lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md
   scaleIO  <Object>
     ScaleIO represents a ScaleIO persistent volume attached and mounted on
     Kubernetes nodes.
   storageClassName <string>
     Name of StorageClass to which this persistent volume belongs. Empty value
     means that this volume does not belong to any StorageClass.
   storageos  <Object>
     StorageOS represents a StorageOS volume that is attached to the kubelet's
     host machine and mounted into the pod More info:
     https://examples.k8s.io/volumes/storageos/README.md
   volumeMode <string>
     volumeMode defines if a volume is intended to be used with a formatted
     filesystem or to remain in raw block state. Value of Filesystem is implied
     when not included in spec.
   vsphereVolume  <Object>
     VsphereVolume represents a vSphere volume attached and mounted on kubelets
     host machine

一,

emptyDir 本地存储

emptyDir存储卷可以看作是Pod上的一个临时目录,其生命周期和Pod相同,Pod创建时被创建,Pod删除时被删除,通常用于数据缓存和临时存储。

例子:

deploy-nginx.yam

说明:

medium 有两个值,一个是不写就是默认的,这个是在pod运行的节点上的本地目录,一个是Memory,此时的数据是存放到内存的。

sizeLimite 也是有两个值,一个是不写就是默认的,此时不限制空间的使用,如果medium的值是Memory,此时默认是节点的内存一半。(例如,17服务器8G内存,那么,最多缓存4G,也就是最多占用4G内存)

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
        volumeMounts:
        - name: cache-volume
          mountPath: /cache
      volumes:
      - name: cache-volume
        emptyDir:
          medium:
          sizeLimit: 128Mi

假设部署此deployment,查询此pod在192.168.217.17这个节点上,先进入pod的/cache目录echo一个文件,文件内容为hello world:

[root@master ~]# k exec -it  nginx-f9df8c74f-gf9vz -- /bin/bash
root@nginx-f9df8c74f-gf9vz:/# cd cache/
root@nginx-f9df8c74f-gf9vz:/cache# echo "hello world " >test.fiel
root@nginx-f9df8c74f-gf9vz:/cache# 
exit

在192.168.217.17上find此文件,可以看到有这么一个文件,路径比较长:

[root@slave1 ~]# find / -name test.fiel
/var/lib/kubelet/pods/db7976ed-4c86-4dae-ba2a-92d4dbc7b1e0/volumes/kubernetes.io~empty-dir/cache-volume/test.fiel
[root@slave1 ~]# cat /var/lib/kubelet/pods/db7976ed-4c86-4dae-ba2a-92d4dbc7b1e0/volumes/kubernetes.io~empty-dir/cache-volume/test.fiel
hello world 

删除此pod,还是在17服务器上查看,可以看到没有这个文件了:

[root@slave1 ~]# cat /var/lib/kubelet/pods/db7976ed-4c86-4dae-ba2a-92d4dbc7b1e0/volumes/kubernetes.io~empty-dir/cache-volume/test.fiel
cat: /var/lib/kubelet/pods/db7976ed-4c86-4dae-ba2a-92d4dbc7b1e0/volumes/kubernetes.io~empty-dir/cache-volume/test.fiel: No such file or directory

因此,emptyDir这种方式的持久化存储并不持久,只能用于一些临时存储数据和缓存的场景。

二,

hostpath 本地存储

hostPath是将工作节点上的目录或文件关联到Pod上的一种卷类型,类似于Docker的bind mount,hostPath卷的生命周期和工作节点相同。hostPath存储卷在Pod需要访问节点上的文件时很有用。

(a)

hostPath存储卷定义在Pod资源的spec.volumes.hostPathz字段,可嵌套使用的字段有两个:

path <string>:用于指定工作节点上的目录路径
type <string>:用于指定工作节点之上的存储类型

(b)

关于type字段,目前支持的值有下面这些:

DirectoryOrCreate:指定的目录不存在时,自动将其创建为0755权限的空目录,属主和属组都为kubelet
Directory:事先必须存在的目录
FileOrCreate:指定的不存在时,自动将其创建为0644权限的空文件,属主和属组都为kubelet
File:事先必须存在的文件
Socket:事先必须存在的Socket文件
CharDevice:事先必须存在的字符设备路径
BlockDevice:事先必须存在的文件设备路径

(c)

[root@master ~]# k explain deploy.spec.template.spec.volumes.hostPath
KIND:     Deployment
VERSION:  apps/v1
RESOURCE: hostPath <Object>
DESCRIPTION:
     HostPath represents a pre-existing file or directory on the host machine
     that is directly exposed to the container. This is generally used for
     system agents or other privileged things that are allowed to see the host
     machine. Most containers will NOT need this. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath
     Represents a host path mapped into a pod. Host path volumes do not support
     ownership management or SELinux relabeling.
FIELDS:
   path <string> -required-
     Path of the directory on the host. If the path is a symlink, it will follow
     the link to the real path. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath
   type <string>
     Type for HostPath Volume Defaults to "" More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath

最后的网址有比较齐全的官方示例,下面的文件也是通过官方示例改造的。

The supported values for field type are:

Value Behavior
Empty string (default) is for backward compatibility, which means that no checks will be performed before mounting the hostPath volume.
DirectoryOrCreate If nothing exists at the given path, an empty directory will be created there as needed with permission set to 0755, having the same group and ownership with Kubelet.
Directory A directory must exist at the given path
FileOrCreate If nothing exists at the given path, an empty file will be created there as needed with permission set to 0644, having the same group and ownership with Kubelet.
File A file must exist at the given path
Socket A UNIX socket must exist at the given path
CharDevice A character device must exist at the given path
BlockDevice A block device must exist at the given path

示例:

deploy-nginx.yaml  

此pod的挂载目录不需要提前建立,因为Ensure the file directory is created

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
        volumeMounts:
        - mountPath: /var/local/aaa
          name: mydir
        - mountPath: /var/local/aaa/1.txt
          name: myfile
      volumes:
      - name: mydir
        hostPath:
          path: /var/local/aaa
          type: DirectoryOrCreate
      - name: myfile
        hostPath:
          path: /var/local/aaa/1.txt
          type: FileOrCreate

查询该pod运行在192.168.217.17上,进入17服务器的/var/local/aaa目录下,是可以看到1.txt的

[root@slave1 aaa]# pwd
/var/local/aaa
[root@slave1 aaa]# ls
1.txt

三,

local  本地存储

本地持久化存储至少需要两个文件,一个是pv文件,一个是pvc文件,当然,配置本地持久存储就是使用,也就需要部署文件了,并且还需要sc做优化,因此,至多4个文件。

大体规则如下:

  • pv需要设置node亲和,部署文件也需要设置节点亲和,两者亲和是一样的,也就是必须是选择的同一个节点。
  • 官方建议使用StorageClass,也就是sc,sc设置绑定模式为 WaitForFirstConsumer,也就是延迟绑定
  • nginx-pv.yaml   pv文件,pv必须要设置nodeSelector---节点亲和

下面的文件将StorageClass相关注释去掉就可以了,此时一个完整的使用案例就是需要4个文件了。如果保留注释,那么三个文件就可以部署了。

apiVersion: v1
kind: Namespace
metadata:
  name: web
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-pv
  namespace: web
  labels:
    type: local
spec:
  capacity:
    storage: 3Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
#  storageClassName: local-storage
  local:
    path: "/opt/nginx/data"
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key:  kubernetes.io/hostname
          operator: In
          values:
          - k8s-node2

nginx-pvc.yaml   pvc文件

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
  namespace: web
  labels:
    app: nginx-pvc
spec:
  accessModes:
  - ReadWriteOnce #此处需要和pv对应才能匹配
  resources:
    requests:
      storage: 2Gi
#  storageClassName: local-storage #此处需要和StorageClass.yaml匹配

nginx-sc.yaml sc文件

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain

deploy-nginx.yaml 部署文件:

这里使用了两个节点亲和,保留一个就可以啦

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: web
spec:
  containers:
  - name: nginx
    image: nginx:1.18
    volumeMounts:
    - name: nginx-persistent-storage
      mountPath: "/usr/share/nginx/html" #不需要修改,映射到镜像内部目录
  volumes:
    - name: nginx-persistent-storage
      persistentVolumeClaim:
        claimName: nginx-pvc #对应到pvc的名字
  tolerations:
  - operator: Exists
    effect: NoExecute
  nodeName: k8s-node2
  affinity:  #亲和性设置
    nodeAffinity: #申明是node亲和策略
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms:
        - matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签,实际没有设置此标签,所以会匹配失败
          - key: node
            operator: In
            values: ["web","dev"]

四,

nfs持久化存储属于网络存储,这个也是使用比较普遍的一个存储方式

nfs服务安装在192.168.217.18服务器上,nfs服务的安装流程如下(centos服务器为例):

所有节点都安装

yum install nfs rpcbind nfs-utils -y

在18服务器上:

[root@slave2 local]# cat /etc/exports
/data/nfs-sc  10.244.0.0/16(rw,no_root_squash,no_subtree_check) 192.168.217.16(rw,no_root_squash,no_subtree_check) 192.168.217.0/24(rw,no_root_squash,no_subtree_check) *(rw,no_root_squash,subtree_check)
systemctl enable nfs rpcbind
systemctl restart nfs rpcbind
验证:
[root@slave2 local]# showmount -e 192.168.217.18
Export list for 192.168.217.18:
/data/nfs-sc (everyone)

直接使用nfs存储部署一个nginx持久化存储:

nfs存储卷可以将现有的nfs-server上的存储空间挂载到Pod中使用。当删除Pod时,nfs存储卷的内容会被保留,卷仅是被卸载而不是删除。而且NFS是文件系统级共享服务,支持被多个Pod挂载使用。定义NFS存储卷时支持嵌套使用3个字段:
server:NFS Server的地址或域名
path:NFS Server共享的目录
readOnly:是否以只读方式挂载,默认false

部署示例:

deploy-nginx-volume-demo.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: volume-nfs-demo
  namespace: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: volume-nfs-demo
  template:
    metadata:
      labels:
        app: volume-nfs-demo
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: nfs-volume
          mountPath: /usr/share/nginx/html/mysite
      volumes:
      - name: nfs-volume
        nfs:
         server: 192.168.217.18
         path: /data/nfs-sc

测试:

在18服务器上建立测试文件

[root@slave2 nfs-sc]# echo "192.168.217.18" >index.html
[root@slave2 nfs-sc]# pwd
/data/nfs-sc

回到集群,查看是否正确挂载:

[root@master nginx]# k exec -it volume-nfs-demo-6dd859c5fc-8ntzs -n web -- /bin/bash
root@volume-nfs-demo-6dd859c5fc-8ntzs:/# curl localhost/mysite/
192.168.217.18

OK,利用nfs网络存储实现数据持久化我们已经可以比较简单的实现了,但问题也比较多,这么一个持久化存储需要我们自己来维护,磁盘限额,挂载方式,回收策略等等还是需要人工处理,这未免不太合适了,并且可能集群内不会只使用一种存储资源,可能会使用ceph,iscsi等等其他的各种存储资源,因此在k8s中,给我们提供了一个新的对象资源,叫做PV,不同的PV会对应到不用的存储资源,这样我们在部署pod的时候直接调用集群内部的pv,即可完成对存储资源的使用,但是呢,直接调用PV的话,有个问题就是,这个pv是否满足我们的需求,因为我们可能需要的是存储能力比较大存储资源,所以这个时候需要一个一个去对比pv,这样很耗费资源,这个时候又引入了我们的pvc。我们在创建pod的时候会附带一个PVC的请求,PVC的请求相当于就是去寻找一个合适的pv,进行绑定,这样我们的pod就会使用到这个pv了。也就是说让我们的pvc去寻找pv,而不是我们的pod资源去寻找。

注:pv和pvc并不是一一对应的,pvc和pv是一一对应的关系,这个不要搞错了(这个需要反复强调)

 




nfs服务结合pv和pvc的应用

PV和PVC介绍
PV是由k8s集群管理员在全局级别配置的存储卷,它通过支持的存储卷插件及给定的配置参数关联到指定存储系统的存储空间,这个的存储空间可能是ceph rbd-image、nfs共享的目录和cephfs文件系统等等,也就是说PV的数据最终是保存在后端的存储系统上的。PV将存储系统上的存储空间抽象为集群级别的API资源,由管理员负责创建维护。

将PV提供的存储空间用于Pod对象存储卷时,用户需要先在namespace中创建PVC资源声明需要的存储空间大小和访问模式等属性,接下来PV控制器会选择合适的PV与PVC进行绑定。随后,在Pod资源中通过persistenVolumeCliam卷插件指定要使用的PVC对象就可以使用这个PVC绑定的PV的存储空间。

总结来说,PV和PVC就是在用户和存储系统之间添加的一个中间层,管理员事先定义好PV,用户通过PVC声明要使用的存储特性来绑定符合条件的最佳PV,从而实现了用户和存储系统之间的解耦,用户不需要了解存储系统的具体使用方式,只需要定义PVC就可以。

相关概念(pv,pvc):

1、PersistentVolume (PV)
       是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期(pod被删除了,我们的PV依然会被保留,类似于卷)。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。

2、PersistentVolumeClaim (PVC)
       PVC 的全称是PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式,例如,可以以读/写一次或 只读多次模式挂载。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。也就是我们集群中会有一个个的PV,可以被直接挂在到某个pod,也可以被PVC绑定,然后挂载到某个pod。

3、静态 pv
       集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费。

4、动态PV
       当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。此配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为 "" 可以有效地禁用其动态配置。

       要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的DefaultStorageClass [准入控制器]。例如,通过确保 DefaultStorageClass 位于 API server 组件的 --admission-control 标志,使用逗号分隔的有序值列表中,可以完成此操作。

5、绑定PV
       master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的,PVC 跟PV 绑定是一对一的映射

6、持久化卷声明的保护
       PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失。意思就是我们的PV被我们的PVC绑定的时候,某一天我们的pod被删除之后,这个PVC依然会存在我们的系统之中,并且这个PVC依然会跟我们的PV有一个绑定关系,主要是为了防止我们的pod出现丢失之后,PVC被删除了,数据就会丢失,这个肯定是合理的。

       当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的删除将被推迟,直到 PVC 不再被任何 pod 使用。

7、访问模式
       PersistentVolume 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。 如下表所示,提供者(驱动)的能力不同,每个 PV 卷的访问模式都会设置为 对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器 上以只读的方式导出。每个 PV 卷都会获得自身的访问模式集合,描述的是 特定 PV 卷的能力

在命令行接口(CLI)中,访问模式也使用以下缩写形式:

RWO - ReadWriteOnce
ROX - ReadOnlyMany
RWX - ReadWriteMany
RWOP - ReadWriteOncePod
8、PVC 状态
Available(可用)——一块空闲资源还没有被任何声明绑定
Bound(已绑定)——卷已经被声明绑定
Released(已释放)——声明被删除,但是资源还未被集群重新声明
Failed(失败)——该卷的自动回收失败

9,

PV资源的spec字段可以嵌套使用下面这些字段:

<volume-plugin> <Object>:具体存储卷插件配置,用来指定PV关联的存储设备,和Pod直接通过存储卷插件定义卷的参数一致
accessModes <[]string>:指定PV的访问模式,目前支持
capacity <map[string]string>:指定PV的容量
mountOptions <[]string>:挂载选项
nodeAffinity <Object>:节点亲和性,用于限制能访问该PV的节点
persistentVolumeReclaimPolicy <string>:当前PV的回收策略
volumeMode <string>:该PV的卷模型,用于指定此存储卷是被格式化为文件系统使用还是直接作为裸格式块设备使用,默认为Filesystem
storageClassName <string>:此PV所属的存储类名称,默认为空,不属于任何存储类

 

10,

PVC隶属于名称空间级别,定义PVC时可以通过访问模式、标签选择器、PV名称和存储资源需求限制多个匹配方式来筛选PV。其中访问模式和资源需求限制是重要的筛选标准。PVC的spec字段支持嵌套使用下面这些字段:

accessModes <[]string>:PVC的访问模式,可用值必须和PV的访问模式一致
resources <Object>:声明PVC要使用存储空间的需求和限制
dataSource <Object>:用于从指定的数据源恢复该PVC卷,目前支持从卷快照或已存在的PVC恢复
selector <Object>:标签选择器,用于筛选PV
storageClassName <string>:该PVC隶属的存储类
volumeMode <string>:卷模型,用于指定此存储卷是被格式化为文件系统使用还是直接使用裸格式的块设备;默认为Filesystem
volumeName <string>:直接指定要绑定的PV资源名称

先上个静态pv实例:

a,

先在nfs服务器192.168.217.18内增加几个目录,并重启nfs服务

[root@slave2 nfs-sc]# mkdir -p /data/nfs-sc/vm{1..3}
[root@slave2 nfs-sc]# cd /data/nfs-sc/
[root@slave2 nfs-sc]# ls
index.html  vm1  vm2  vm3
systemctl restart nfs rpcbind
[root@slave2 nfs-sc]# showmount -e slave2
Export list for slave2:
/data/nfs-sc/vm3 *
/data/nfs-sc/vm2 *
/data/nfs-sc/vm1 *
/data/nfs-sc     (everyone)

b,

创建三个不同容量的pv---test-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: vm1 #自定义pv名字
spec:
  capacity:
    storage: 100M #定义这个pv的限制存储大小
  accessModes:
    - ReadWriteMany #定义操作的权限
  storageClassName: nfs #自定义定义存储的类名,特定类的PV只能绑定到请求该类的PVC。没有storageClassName的PV没有类,只能绑定到不请求特定类的PVC
  nfs:
    path: /data/nfs-sc/vm1 #绑定主机的的路径
    server: 192.168.217.18 #指定nfs主机的ip地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: vm2 #自定义pv名字
spec:
  capacity:
    storage: 1Gi #定义这个pv的限制存储大小
  accessModes:
    - ReadWriteMany #定义操作的权限
  storageClassName: nfs #自定义定义存储的类名,特定类的PV只能绑定到请求该类的PVC。没有storageClassName的PV没有类,只能绑定到不请求特定类的PVC
  nfs:
    path: /data/nfs-sc/vm2 #绑定主机的的路径
    server: 192.168.217.18 #指定nfs主机的ip地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: vm3 #自定义pv名字
spec:
  capacity:
    storage: 3Gi #定义这个pv的限制存储大小
  accessModes:
    - ReadWriteMany #定义操作的权限
  storageClassName: nfs #自定义定义存储的类名,特定类的PV只能绑定到请求该类的PVC。没有storageClassName的PV没有类,只能绑定到不请求特定类的PVC
  nfs:
    path: /data/nfs-sc/vm3 #绑定主机的的路径
    server: 192.168.217.18 #指定nfs主机的ip地址

执行脚本,查看pv状态,此时状态都是available:

[root@master nginx]# k apply -f test-pv.yaml 
persistentvolume/vm1 unchanged
persistentvolume/vm2 created
persistentvolume/vm3 created
[root@master nginx]# k get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON   AGE
nginx-pv   3Gi        RWO            Retain           Bound       web/nginx-pvc                           3h39m
vm1        100M        RWX            Retain           Available                   nfs                     32s
vm2        1Gi        RWX            Retain           Available                   nfs                     10s
vm3        3Gi        RWX            Retain           Available                   nfs                     10s

c:

创建pvc--test-pvc.yaml

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginx-pvc #这个名字随便了,一哈pod部署的时候会引用这个名字
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2G #定义要申请的空间大小
  storageClassName: nfs #这里要和我们定义pv那里storageClassName一样才行

执行此脚本后,查看pv和pvc的状态:

[root@master nginx]# k get pv,pvc -A
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
persistentvolume/nginx-pv   3Gi        RWO            Retain           Bound       web/nginx-pvc                               3h58m
persistentvolume/vm1        100M       RWX            Retain           Available                       nfs                     19m
persistentvolume/vm2        1Gi        RWX            Retain           Available                       nfs                     19m
persistentvolume/vm3        3Gi        RWX            Retain           Bound       default/nginx-pvc   nfs                     19m
NAMESPACE   NAME                              STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
default     persistentvolumeclaim/nginx-pvc   Bound    vm3        3Gi        RWX            nfs            10m

OK,pvc申请的是2G,因此,只有pv叫vm3的符合,看状态是已经绑定了。下面创建一个nginx测试一哈:

deploy-test-pv.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy-pvc
  name: nginx-deploy-pvc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy-pvc
  template:
    metadata:
      labels:
        app: nginx-deploy-pvc
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts: #这里定义pod中要挂载的路径
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
        - name: html #和上面的挂载目录一致
          persistentVolumeClaim:
            claimName: nginx-pvc #这里要绑定我们创建的pvc

在18服务器上的vm3文件夹下建立测试文件:

[root@slave2 vm3]# pwd
/data/nfs-sc/vm3
[root@slave2 vm3]# echo "test pv and pvc" >index.html
[root@master nginx]# k exec -it nginx-deploy-pvc-98bdcc6cd-25x4w -- /bin/bash
root@nginx-deploy-pvc-98bdcc6cd-25x4w:/# curl localhost 
test pv and pvc

OK,完成目标。以上都是静态持久化存储,那么,动态的持久化存储需要利用nfs-client插件来实现了,动态存储的优点为按需分配,自动创建pv,省去了管理pv的麻烦,可动态扩展存储,使用十分方便。

StorageClass动态存储就不说了,以往的博客做过总结,请看我原来的博客

kubernetes学习之持久化存储StorageClass(4)_zsk_john的博客-CSDN博客

有几点需要补充一哈,关于StorageClass的注解,可以使用storageClassName: managed-nfs-storage来代替,也就是下面的文件可以改写成:

[root@master nfs-sc]# cat test-claim.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  annotations: 
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

改成这样也是OK的:

[root@master nfs-sc]# cat test-claim.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi
  volumeMode: Filesystem
  storageClassName: managed-nfs-storage

当用户声明一个 PVC 时,如果在 PVC 中添加了 StorageClassName 字段,其意图为:当 PVC 在集群中找不到匹配的 PV 时,会根据 StorageClassName 的定义触发相应的 Provisioner 插件创建合适的 PV 供绑定,即创建动态数据卷;动态数据卷时由 Provisioner 插件创建的,并通过 StorageClassName 与 PVC 进行关联。

StorageClass 可译为存储类,表示为一个创建 PV 存储卷的模板;在 PVC 触发自动创建PV的过程中,即使用 StorageClass 对象中的内容进行创建。其内容包括:目标 Provisioner 名字,创建 PV 的详细参数,回收模式等配置。

总结

StorageClassName 也就是sc的名字可在pv和pvc里都定义的哦,如果是动态存储,pv自然是不需要写了,免去了很多麻烦。StorageClassName可以以注解的方式定义,但目前好像是抛弃了此方式。

pvc和将要使用pvc的pod应该是处于一个namespace,这里需要特别注意,否则会报错找不到pvc。

nfs-client插件是有namespace限定的,但,pvc可以与其不是一个namespace。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
1天前
|
Kubernetes Cloud Native 持续交付
云原生之旅:Docker容器化与Kubernetes集群管理
【9月更文挑战第33天】在数字化转型的浪潮中,云原生技术如同一艘航船,带领企业乘风破浪。本篇文章将作为你的航海指南,从Docker容器化的基础讲起,直至Kubernetes集群的高级管理,我们将一起探索云原生的奥秘。你将学习到如何封装应用、实现环境隔离,以及如何在Kubernetes集群中部署、监控和扩展你的服务。让我们启航,驶向灵活、可伸缩的云原生未来。
|
4天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker与Kubernetes入门
【9月更文挑战第30天】在云计算的浪潮中,云原生技术正以前所未有的速度重塑着软件开发和运维领域。本文将通过深入浅出的方式,带你了解云原生的核心组件——Docker容器和Kubernetes集群,并探索它们如何助力现代应用的构建、部署和管理。从Docker的基本命令到Kubernetes的资源调度,我们将一起开启云原生技术的奇妙之旅。
|
1天前
|
Kubernetes Cloud Native Ubuntu
云原生之旅:Kubernetes集群搭建与应用部署
【8月更文挑战第65天】本文将带你进入云原生的世界,通过一步步指导如何在本地环境中搭建Kubernetes集群,并部署一个简单的应用。我们将使用Minikube和Docker作为工具,探索云原生技术的魅力所在。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和实践技巧。
|
5天前
|
Kubernetes Cloud Native Docker
云原生之旅:深入理解容器化与Kubernetes
【9月更文挑战第29天】在云计算的海洋中,云原生技术如同一艘航船带领着企业乘风破浪。本文将作为你的航海图,带你探索云原生的核心——容器化和Kubernetes。我们将从容器的基本概念出发,逐步深入到如何在Kubernetes集群中部署应用,最后探讨这些技术如何助力现代软件开发。文章旨在为读者提供清晰的云原生入门知识,并展示实际操作的步骤,让你能够自信地启航。
|
7天前
|
Cloud Native 云计算 Docker
云原生之旅:从容器化到微服务架构
【9月更文挑战第27天】本文将引领读者进入云原生的世界,探索如何通过容器化技术实现应用的快速部署与扩展,并深入理解微服务架构的设计哲学。我们将一起见证代码如何转化为可在云端无缝运行的服务,同时讨论云原生生态中的最佳实践和面临的挑战。
|
5天前
|
Kubernetes Cloud Native 持续交付
探索云原生架构:打造弹性可扩展的应用
【9月更文挑战第29天】在云计算的浪潮中,云原生架构成为企业追求高效、灵活和可靠服务的关键。本文将深入解析云原生的概念,探讨如何利用容器化、微服务和持续集成/持续部署(CI/CD)等技术构建现代化应用。我们将通过一个简易的代码示例,展示如何在Kubernetes集群上部署一个基于Node.js的应用,从而揭示云原生技术的强大能力和潜在价值。
19 6
|
6天前
|
监控 Cloud Native 持续交付
云原生架构:构建弹性与高效的现代应用##
随着云计算技术的不断成熟,云原生架构逐渐成为企业技术转型的重要方向。本文将深入探讨云原生的核心概念、主要技术和典型应用场景,以及如何通过云原生架构实现高可用性、弹性扩展和快速迭代,助力企业在数字化转型中保持竞争优势。 ##
25 6
|
4天前
|
Cloud Native 持续交付 微服务
云原生时代的微服务架构实践
【9月更文挑战第30天】随着云计算技术的不断进步,云原生已经成为现代软件开发的重要趋势。本文将通过深入浅出的方式,介绍如何在云原生环境下设计并实施微服务架构,以及如何利用容器化技术和自动化工具来提升服务的可维护性和可扩展性。我们将一起探讨微服务架构的核心原则、优势,以及在云平台中部署和管理微服务的最佳实践。无论你是初学者还是有经验的开发者,这篇文章都将成为你探索云原生和微服务世界的一盏明灯。
|
7天前
|
运维 Cloud Native 持续交付
云原生架构:构建未来应用的基石
本文将深入探讨云原生架构的核心概念、主要优势以及实际应用案例,揭示其在现代IT领域的重要性。通过详细解析云原生技术的各个方面,帮助读者更好地理解和应用这一前沿技术。
|
7天前
|
监控 Cloud Native 持续交付
云原生时代的微服务架构设计原则与实践
【9月更文挑战第27天】本文深入探讨了在云原生环境下,如何高效地实施微服务架构。通过分析微服务的基本概念、设计原则和关键技术,结合实际案例,指导读者理解并应用微服务架构于云计算项目之中。文章旨在为软件开发者和架构师提供一条清晰的路径,以实现更加灵活、可扩展且易于维护的系统。
下一篇
无影云桌面