k8s 入门 7:Volume

容器中的文件在磁盘上是临时存放的,这给在容器中运行较重要的应用带来一些问题。 当容器崩溃或停止时会出现一个问题。此时容器状态未保存, 因此在容器生命周期内创建或修改的所有文件都将丢失。 在崩溃期间,kubelet 会以干净的状态重新启动容器。 当多个容器在一个 Pod 中运行并且需要共享文件时,会出现另一个问题。 跨所有容器设置和访问共享文件系统具有一定的挑战性。

卷要解决的问题:

1、 文件的持久化存储

2、多个容器在一个 Pod 中运行需要共享文件

卷的分类

卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的内容。

卷主要可以分为以下几类。

临时卷(Ephemeral Volume)

临时卷的生命周期和 Pod 想同。

有些应用程序需要额外的存储,但并不关心数据在重启后是否仍然可用。 例如,缓存服务经常受限于内存大小,而且可以将不常用的数据转移到比内存慢的存储中,对总体性能的影响并不大。

另有些应用程序需要以文件形式注入的只读数据,比如配置数据或密钥。

临时卷 就是为此类用例设计的。因为卷会遵从 Pod 的生命周期,与 Pod 一起创建和删除, 所以停止和重新启动 Pod 时,不会受持久卷在何处可用的限制。

临时卷主要有以下几种分类:

持久卷(Persistent Volume)

持久卷的生命周期长于 Pod,Pod 销毁后持久卷依然存在。

持久卷有两个核心概念:PV 和 PVC:

持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存)。同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以挂载为 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod, 请参阅访问模式)。

投射卷**(Projected Volumes)**

projected 卷可以将若干现有的卷源映射到同一个目录之上。

PV、PVC 和 SC

PV 和 PVC 的关系

PV 将存储系统之上的存储空间抽象为 Kubernetes 系统全局级别的 API 资源,由集群管理员负责管理和维护。

将PV提供的存储空间用于 Pod 对象的存储卷时,用户需要事先使用 PVC在名称空间级别声明所需要的存储空间大小及访问模式并提交给Kubernetes API Server,接下来由PV控制器负责查找与之匹配的PV资源并完成绑定。

PV 和 PVC 是一对一的关系:一个 PVC 仅能绑定一个 PV,而一个 PV 在某一时刻也仅可被一个 PVC 所绑定。为了能够让用户更精细地表达存储需求,PV 资源对象的定义支持存储容量、存储类、卷模型和访问模式等属性维度的约束。相应地,PVC 资源能够从访问模式、数据源、存储资源容量需求和限制、标签选择器、存储类名称、卷模型和卷名称等多个不同的维度向PV资源发起匹配请求并完成筛选。

静态预配(static provisioning)

PVC 及 PV 将存储资源管理与使用的职责分离至用户和集群管理员两类不同的人群之上,简化了用户对存储资源的使用机制,但也对二者之间的协同能力提出了要求。管理员需要精心预测和规划集群用户的存储使用需求,提前创建出多种规格的PV,以便于在用户声明PVC后能够由PV控制器在集群中找寻到合适的甚至是最佳匹配的PV进行绑定。

这种通过管理员手动创建 PV 来满足 PVC 需求的静态预配(static provisioning)存在着不少的问题。

第一,集群管理员难以预测出用户的真实需求,很容易导致某些类型的PVC无法匹配到PV而被挂起,直到管理员参与到问题的解决过程中。
第二,那些能够匹配到PV的PVC也很有可能存在资源利用率不佳的状况,例如一个声明使用5G存储空间的PVC绑定到一个20GB的PV之上。

解决方案是一种称为动态预配、按需创建PV的机制。

动态预配

动态卷制备允许按需创建存储卷。

集群管理员要做的仅是事先借助存储类(StorageClass)的API资源创建出一到多个“PV 模板”,并在模板中定义好基于某个存储系统创建 PV 所依赖的存储组件(例如 Ceph RBD 存储映像或 CephfFS 文件系统等)时需要用到的配置参数。创建 PVC 时,用户需要为其指定要使用 PV 模板(StorageClass 资源),而后PV控制器会自动连接相应存储类上定义的目标存储系统的管理接口,请求创建匹配该 PVC 需求的存储组件,并将该存储组件创建为 Kubernetes 集群上可由该 PVC 绑定的 PV 资源。

如果没有动态制备,集群管理员必须手动地联系他们的云或存储提供商来创建新的存储卷, 然后在 Kubernetes 集群创建 PV 对象来表示这些卷。 动态制备功能消除了集群管理员预先配置存储的需要。相反,它在用户请求时自动制备存储。

动态卷制备的实现基于 storage.k8s.io API 组中的 StorageClass API 对象。 集群管理员可以根据需要定义多个 StorageClass 对象,每个对象指定一个卷插件(又名 provisioner), 卷插件向卷制备商提供在创建卷时需要的数据卷信息及相关参数。

参数解读

PV

配置示例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
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

ACESS MODES

  • RWO:卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式仍然可以在同一节点上运行的多个 Pod 访问该卷。
  • ROX:卷可以被多个节点以只读方式挂载。
  • RWX:卷可以被多个节点以读写方式挂载。
  • RWOP:卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。

RECLAIM POLICY

  • Retain:手动回收
  • Recycle:简单擦除(rm -rf /thevolume/*)
  • Delete:删除存储卷

STATUS

  • Available:卷是一个空闲资源,尚未绑定到任何申领
  • Bound:该卷已经绑定到某申领
  • Released:所绑定的申领已被删除,但是关联存储资源尚未被集群回收
  • Failed:卷的自动回收操作失败

VOLUME MODE

针对 PV 持久卷,Kubernetes 支持两种卷模式(volumeModes):Filesystem(文件系统)Block(块)volumeMode 是一个可选的 API 参数。 如果该参数被省略,默认的卷模式是 FilesystemvolumeMode 属性设置为 Filesystem 的卷会被 Pod 挂载(Mount) 到某个目录。 如果卷的存储来自某块设备而该设备目前为空,Kuberneretes 会在第一次挂载卷之前在设备上创建文件系统。

PVC

配置示例:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"
    matchExpressions:
      - {key: environment, operator: In, values: [dev]}

ACESS MODES:同 PV。

VOLUME MODE:同 PV。

SC

配置示例:

kind: StorageClass
metadata:
  name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
  - debug
volumeBindingMode: Immediate

PROVISIONER

每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。

PARAMETERS

Storage Classes 的参数描述了存储类的卷。

RECLAIMPOLICY

由 StorageClass 动态创建的 PersistentVolume 会在类的 reclaimPolicy 字段中指定回收策略,可以是 Delete 或者 Retain。 如果 StorageClass 对象被创建时没有指定 reclaimPolicy,它将默认为 Delete

VOLUMEBINDINGMODE

控制了卷绑定和动态制备应该发生在什么时候。 当未设置时,默认使用 Immediate 模式。

Immediate 模式表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态制备。 对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume 会在不知道 Pod 调度要求的情况下绑定或者制备。

集群管理员可以通过指定 WaitForFirstConsumer 模式来解决此问题。 该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。

如何配置

使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。

挂载 PVC

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

挂载 ConfigMap

使用 ConfigMap 填充卷

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        # 提供包含要添加到容器中的文件的 ConfigMap 的名称
        name: special-config
  restartPolicy: Never

参考

[1] Kubernetes 之 PV 和 PVC

[2] Kubernetes 存储卷

[3] k8s volumes

[4] 配置 Pod 以使用 PersistentVolume 作为存储

[5] 配置 Pod 使用 ConfigMap