持久卷(PV)与持久卷声明(PVC),创建本地持久化存储

持久卷 PersistentVolume

PersistentVolume(PV)是集群中一块存储资源,由管理员主动创建提供或使用 StorageClass 动态提供。它与节点资源一样,不属于任何命名空间,有着自己独立的生命周期。而用户则通过 PersistentVolumeClaim (PVC) 来申请所需的存储资源。

1. 生命周期

在 Kubernetes 集群中,PV 作为存储资源存在,Pod 通过 PVC 来使用 PV。PV 和 PVC 之间的交互过程有着自己的生命周期,这个生命周期分为5个阶段:

  • 供应(Provisioning):即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass(动态方式);
  • 绑定(Binding):将 PV 分配给 PVC;
  • 使用(Using):Pod 通过 PVC 使用该 Volume;
  • 释放(Releasing):Pod 释放 Volume 并删除 PVC;
  • 回收(Reclaiming):回收 PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除;

根据上述的5个阶段,存储卷的存在下面的 4 种状态:

  • Available:可用状态,处于此状态表明 PV 以及准备就绪了,可以被 PVC 使用了;
  • Bound:绑定状态,表明 PV 已被分配给了 PVC;
  • Released:释放状态,表明 PVC 解绑 PV,但还未执行回收策略;
  • Failed:错误状态,表明 PV 发生错误;

1.1 供应(Provisioning)

供应是为集群提供可用的存储卷,在 Kubernetes 中有两种持久化存储卷的提供方式:静态或者动态,两者区别在于。

1.1.1 静态 (Static)

PV 是由 Kubernetes 的集群管理员创建的,代表真实的存储,可被 Pod 作为真实存储使用。在静态供应的情况下,由集群管理员预先创建 PV,开发者创建 PVC 和 Pod,Pod 通过 PVC 使用 PV 提供的存储。静态供应方式的过程如下图所示:

[图片上传中...(image-5c62e8-1597076467904-3)]

<figcaption></figcaption>

2.1.2 动态(Dynamic)

对于动态的提供方式,当管理员创建的静态 PV 都不能够匹配用户的 PVC 时,集群会尝试自动为 PVC 提供一个存储卷,这种提供方式基于 StorageClass。在动态提供方面,PVC 需要请求一个存储类,但此存储类必须由管理员预先创建和配置。集群管理员需要在 API-Server 中启用 DefaultStorageClass 控制器。动态供应过程如下图所示:

[图片上传中...(image-7fd658-1597076467904-2)]

<figcaption></figcaption>

1.2 绑定(Binding)

Kubernetes 会动态的将 PVC 与可用的 PV 的进行绑定,如果一个 PV 曾经动态供给到了一个新的 PVC,那么 PVC 绑定就是专属的。另外,用户总是能得到它们所要求的存储,但是 volume 可能超过它们的请求。一旦绑定了,PVC绑定就是专属的,无论它们的绑定模式是什么。

如果没有匹配的 PV,那么 PVC 会无限期的处于未绑定状态,直到存在匹配的 PV。比如,就算集群中存在很多的 50G 的 PV,需要 100G 容量的 PVC 也不会匹配满足需求的 PV,直到集群中有 100G 的 PV 时,PVC 才会被绑定。PVC 会基于下面的条件绑定PV,如果下面的条件同时存在,则选择符合所有要求的 PV 进行绑定:

  1. 如果PVC指定了存储类,则只会绑定指定了同样存储类的PV;

  2. 如果PVC设置了选择器,则选择器去匹配符合的PV;

  3. 如果没有指定存储类和设置选取器,PVC会根据存储空间容量大小和访问模式匹配符合的PV。

1.3 使用(Using)

Pod 把 PVC 作为卷来使用,集群会通过 PVC 查找绑定的 PV,并将其挂接至 Pod。对于支持多种访问方式的卷,用户在使用 PVC 作为卷时,可以指定需要的访问方式。一旦用户拥有了一个已经绑定的 PVC,被绑定的 PV 就归该用户所有。用户能够通过在 Pod 的存储卷中包含的 PVC,从而访问所占有的 PV。

1.4释放(Releasing)

当用户完成对卷的使用时,可以通过请求 API-Server 来删除 PVC,删除后还可以重新申请,在删除 PVC 后对应的持久化存储卷被视为“被释放”,但这时还不能给其他的 PVC 使用。之前的 PVC 数据还保存在卷中,要根据策略来进行后续处理。

1.5 回收(Reclaiming)

PV 的回收策略向集群阐述了在 PVC 释放卷时,应如何进行后续工作。目前可以采用三种策略:保留,回收或者删除。保留策略允许重新申请这一资源。在 PVC 能够支持的情况下,删除策略会同时删除卷以及AWS EBS/GCE PD或者Cinder卷中的存储内容。如果插件能够支持,回收策略会执行基础的擦除操作(rm -rf /thevolume/*),这一卷就能被重新申请了。

1.5.1 保留

保留回收策略允许手工回收资源。当 PVC 被删除,PV 将继续存储现有的数据,虽然存储卷被处于已释放的状态,但是它对于其他的 PVC 仍是不可用的。管理员能够通过下面的步骤手工回收存储卷:

  1. 删除 PV:在 PV 被删除后,在外部设施中相关的存储资产仍然还在;

  2. 手工删除遗留在外部存储中的数据;

  3. 手工删除存储资产,如果需要重用这些存储资产,则需要创建新的 PV;

1.5.2 循环

此策略将会被遗弃,建议后续使用动态供应的模式。

循环回收会在存储卷上执行基本擦除命令 rm -rf /thevolume/,使数据对于新的 PVC 可用。

1.5.3 删除

对于支持删除回收策略的存储卷插件,删除即会从 Kubernetes 中移除 PV,也会从相关的外部设施中删除存储资产,例如 AWS EBS, GCE PD, Azure Disk 或者 Cinder 存储卷。

2. 创建持久存储卷

在创建持久卷 PV 时需要指定实际存储类型,类型是作为插件实现的,目前支持以下插件:

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • CSI
  • FC (Fibre Channel)
  • FlexVolume
  • Flocker
  • NFS
  • iSCSI
  • RBD (Ceph Block Device)
  • CephFS
  • Cinder (OpenStack block storage)
  • Glusterfs
  • VsphereVolume
  • Quobyte Volumes
  • HostPath (Single node testing only -- local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
  • Portworx Volumes
  • ScaleIO Volumes
  • StorageOS

下面是一个持久卷的声明 YAML 配置文件。在此配置文件中要求提供 5Gi 的存储空间,存储模式为Filesystem ,访问模式是 ReadWriteOnce,通过 Recycle 回收策略进行持久化存储卷的回收,指定存储类为 slow,使用 nfs 的插件类型。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv
spec:
  capacity: #容量
     storage: 5Gi 
  volumeMode: Filesystem #存储卷模式
  accessModes: #访问模式
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle  #持久化卷回收策略
  storageClassName: slow   #存储类
  mountOptions: #挂接选项
   - hard
   - nfsvers=4.1
  nfs:
     path:/tmp
     server:172.17.0.2 
复制代码

2.1 容量(Capacity)

PV 需通过 capcity 属性指定存储容量,目前 capcity 属性仅有 storage(存储大小)这唯一一个设置。

2.2 存储卷模式(Volume Mode)

存储卷模式的默认值为 Filesystem。在 Kubernetesv1.9 版本后用户可以指定volumeMode 的值,除了支持文件系统(files ystem)外,也支持块设备(raw block devices)。

2.3 访问模式(Access Modes)

访问模式的可选范围如下:

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

即使某个存储卷插件支持多种访问模式,但一次也只能配置一种访问模式。下面是各个存储卷插件支持的访问模式清单:

存储卷插件 ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStore
AzureFile
AzureDisk
CephFS
Cinder
FC
FlexVolume
Flocker
GCEPersistentDisk
Glusterfs
HostPath
iSCSI
PhotonPersistentDisk
Quobyte
NFS
RBD
VsphereVolume – (works when pods are collocated)
PortworxVolume
ScaleIO
StorageOS

2.4 类(Class)

通过 storageClassName 属性指定存储类别,即 StorageClass 资源对象的名称。具有特定类别的 PV 只能与请求了该类别的 PVC 进行绑定。

2.5 回收策略

当前的回收策略可选值包括:

  • Retain -- 持久化卷被释放后,仍保留数据,需要手工进行回收操作;
  • Recycle -- 回收空间,删除 PVC 后,执行基础擦除命令 rm-rf /thevolume/* (NFS、HostPath 存储支持);
  • Delete -- 删除 PVC 后,会删除与 PV 相关的存储数据(AWSEBS、GCE PD 存储支持);

2.6 挂载参数(Mount Options)

当 PV 挂载到一个节点时,可能需要设置额外的挂载参数,可以通过 mountOptions 字段设置。但只有下面的存储卷类型支持挂载参数:

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • NFS
  • iSCSI
  • RBD (Ceph Block Device)
  • CephFS
  • Cinder (OpenStack block storage)
  • Glusterfs
  • VsphereVolume
  • Quobyte Volumes
  • VMware Photon

3. 持久卷声明

下面是一个名称为 myclaim 的持久卷声明 YAML 配置文件,它的访问模式为 ReadWriteOnce,存储卷模式是 Filesystem,需要的存储空间大小为 8Gi,指定的存储类为 slow,并设置了标签选择器和匹配表达式。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc
spec:
  accessModes: #访问模式
    - ReadWriteOnce
  volumeMode: Filesystem #存储卷模式
  resources: #资源
    requests:
      storage: 8Gi
  storageClassName: slow #存储类
  selector: #选择器
    matchLabels:
      release: "stable"
    matchExpressions: #匹配表达式
      - {key: environment, operator: In, values: [dev]}
复制代码

3.1 选择器

在 PVC 中,可以通过标签选择器来进一步的过滤 PV。选择器的有两种:

  • matchLabels: 只有存在与此处的标签一样的 PV 才会被 PVC 选中;
  • matchExpressions :匹配表达式由键、值和操作符组成,操作符包括 In, NotIn, ExistsDoesNotExist,只有符合表达式的 PV 才能被选择;

如果同时设置了 matchLabelsmatchExpressions,则会进行求与(&),即只有同时满足上述匹配要求的 PV 才会被选择。

3.2 存储类

除了使用标签过滤 PV,还可通过 storageClassName 属性指定存储类,PV 只有为该存储类的才能被绑定到 PVC 上。

4. Pod 中使用 PVC

Pod 通过使用 PVC 来访问 PV,Pod 需与 PVC 在同一个命名空间中,PVC 会与集群中合适的 PV 进行绑定,并将 PV 挂载到主机和 Pod 上。

kind: Pod
apiVersion: v1
metadata:
  name: mypod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts: 
    - mountPath: "/var/www/html"
        name: mypd                # 挂载的存储卷的名称
    volumes: 
    - name: mypd
    persistentVolumeClaim: 
        claimName: myclaim  # PVC名称
复制代码

5. 本地持久化存储

本地持久化存储(Local Persistent Volume)就是把数据存储到 Pod 运行的宿主机上,其必须保证 Pod 被调度到具有本地持久化存储的节点上。

为什么需要这种类型的存储呢?有时候你的应用对磁盘 IO 有很高的要求,网络存储性能肯定不如本地的高,尤其是本地使用了SSD这种磁盘。

在非本地持久化存储的场景中,我们会先创建 PV,然后创建 PVC,此时如果两者匹配则会自动进行绑定。即使是动态 PV 创建,Pod 也会先调度到某个节点上,然后根据 PVC 进行创建 PV 最后绑定到 Pod 中。

可是对于本地持久化存储有一个问题就是 PV 必须提前准备好,而且并非每一个集群节点都有该 PV,因此 Pod 不能随意调度 。那么如何保证 Pod 一定被调度到有 PV 的节点上呢?这时就需要在 PV 中声明节点亲和性,且 Pod 被调度的时候还要考虑卷的分布情况。

  1. 下面是 PV 的定义,即使 node02 节点上也有 /data/vol1 目录,但 PV 也不一定会在 node2 上,因为 nodeAffinity 属性设置了亲和主机 node01
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local: # local类型
    path: /data/vol1  # 节点上的具体路径
  nodeAffinity: # 这里就设置了节点亲和
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node01 # 这里我们使用node01节点,该节点有/data/vol1路径
复制代码
  1. 定义存储类:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
复制代码

这里的 volumeBindingMode: WaitForFirstConsumer 很关键,表示为延迟绑定(等待第一个消费者后再进行绑定),该配置会影响 PVC 与 PV 的绑定时机,只有在出现第一个使用指定 PVC 的 Pod 时,才会将 PVC 与 PV 进行绑定。

因为通常 PVC 会在有合适的 PV 时立即绑定,但如果 Pod 被调度到没有该 PV 的节点上,会导致 Pod 一直被挂起。而延迟绑定的作用即 Pod 的调度要参考卷的分布。当调度器开始调度 Pod 的时候会看看它要求的 LPV 在哪里,然后再调度到该节点,进行 PVC 的绑定,最后再挂载到 Pod 中,保证了 Pod 所在的节点一定就是 LPV 所在的节点。所以让 PVC 延迟绑定,就是要等到使用这个 PVC 的 Pod 出现在调度器上之后,根据综合评估在来绑定 PVC。

  1. 定义 PVC:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: local-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: local-storage
复制代码
image

可以看到这个 PVC 是 pending 状态,这也就是延迟绑定,因为此时还没有 Pod。

  1. 定义 Pod:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      appname: myapp
  template:
    metadata:
      name: myapp
      labels:
        appname: myapp
    spec:
      containers:
      - name: myapp
        image: tomcat:8.5.38-jre8
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        volumeMounts:
          - name: tomcatedata
            mountPath : "/data"
      volumes:
        - name: tomcatedata
          persistentVolumeClaim:
            claimName: local-claim
复制代码

此时因为 PV 在 node01 节点上,因此这个 Pod 被调度到该节点上,即使删除在创建该 Pod,依然会被调度到 node01 节点上。并且 PVC 已经为绑定状态。

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,306评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,657评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,928评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,688评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,105评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,024评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,159评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,937评论 0 212
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,689评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,851评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,325评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,651评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,364评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,192评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,985评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,154评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,955评论 2 279