动态卷供应

动态卷供应

一.简介

动态卷供应允许按需创建存储卷。

如果没有动态供应,集群管理员必须手动创建新的存储卷, 然后在 Kubernetes 集群创建 PersistentVolume 对象来表示这些卷。 动态供应功能消除了集群管理员预先配置存储的需要。 相反,它在用户请求时自动供应存储。

动态卷供应的实现基于 storage.k8s.io API 组中的 StorageClass API 对象。

集群管理员可以根据需要定义多个 StorageClass 对象,每个对象指定一个卷插件(又名 provisioner), 卷插件向卷供应商提供在创建卷时需要的数据卷信息及相关参数。

集群管理员可以在集群中定义和公开多种存储(来自相同或不同的存储系统),每种都具有自定义参数集。 该设计也确保终端用户不必担心存储供应的复杂性和细微差别,但仍然能够从多个存储选项中进行选择。

动态与静态区别:

静态:Pod ——> PVC——> PV (如果没有匹配的PV,那么PVC会一直处于pending状态)
动态:Pod——> PVC——> StorageClass——> PV (当PVC创建时,会自动创建对应的PV去绑定)

二. StorageClass 资源

要启用动态供应功能,集群管理员需要为用户预先创建一个或多个 StorageClass 对象。

每个 StorageClass 都包含 provisionerparametersreclaimPolicy 字段, 这些字段会在 StorageClass 需要动态分配 PersistentVolume 时会使用到。

StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。

provisioner(存储制备器)

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

你可以指定"内置" 制备器(其名称前缀为 “kubernetes.io” 并打包在 Kubernetes 中)。也可以运行和指定外部制备器,这些独立的程序遵循由 Kubernetes 定义的 规范

外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括 Flex)等。

代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。你可以访问代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驱动列表。

例如,NFS 没有内部制备器,但可以使用外部制备器。 也有第三方存储供应商提供自己的外部制备器。

示例:

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

回收策略

由 StorageClass 动态创建的 PersistentVolume 会在类的 reclaimPolicy 字段中指定回收策略,可以是 Delete 或者 Retain

如果 StorageClass 对象被创建时没有指定 reclaimPolicy,它将默认为 Delete

通过 StorageClass 手动创建并管理的 PersistentVolume 会使用它们被创建时指定的回收政策。

允许卷扩展

特性状态: Kubernetes v1.11 [beta]

PersistentVolume 可以配置为可扩展。将此功能设置为 true 时,允许用户通过编辑相应的 PVC 对象来调整卷大小。

当下层 StorageClass 的 allowVolumeExpansion 字段设置为 true 时,以下类型的卷支持卷扩展。

卷类型 Kubernetes 版本要求
gcePersistentDisk 1.11
awsElasticBlockStore 1.11
Cinder 1.11
glusterfs 1.11
rbd 1.11
Azure File 1.11
Azure Disk 1.11
Portworx 1.11
FlexVolume 1.13
CSI 1.14 (alpha), 1.16 (beta)

说明: 此功能仅可用于扩容卷,不能用于缩小卷。

挂载选项

由 StorageClass 动态创建的 PersistentVolume 将使用类中 mountOptions 字段指定的挂载选项。

如果卷插件不支持挂载选项,却指定了挂载选项,则制备操作会失败。 挂载选项在 StorageClass 和 PV 上都不会做验证,如果其中一个挂载选项无效,那么这个 PV 挂载操作就会失败。

卷绑定模式

volumeBindingMode 字段控制了卷绑定和动态制备 应该发生在什么时候。

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

集群管理员可以通过指定 WaitForFirstConsumer 模式来解决此问题。 该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。 PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或制备。这些包括但不限于 资源需求节点筛选器pod 亲和性和互斥性、 以及污点和容忍度

以下插件支持动态供应的 WaitForFirstConsumer 模式:

以下插件支持预创建绑定 PersistentVolume 的 WaitForFirstConsumer 模式:

说明:

如果你选择使用 WaitForFirstConsumer,请不要在 Pod 规约中使用 nodeName 来指定节点亲和性。 如果在这种情况下使用 nodeName,Pod 将会绕过调度程序,PVC 将停留在 pending 状态。

相反,在这种情况下,你可以使用节点选择器作为主机名,如下所示

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  nodeSelector:
    kubernetes.io/hostname: kube-01
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage

parameters(卷参数)

Storage Classes 的参数描述了存储类的卷。取决于制备器,可以接受不同的参数。

例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。 当参数被省略时,会使用默认值。

AWS EBS

provisioner: kubernetes.io/aws-ebs

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "10"
  fsType: ext4

GCE PD

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
   fstype: ext4
  replication-type: none

NFS

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: example-nfs
provisioner: example.com/external-nfs
parameters:
  server: nfs-server.example.com
  path: /share
  readOnly: "false"
  • server:NFS 服务器的主机名或 IP 地址。
  • path:NFS 服务器导出的路径。
  • readOnly:是否将存储挂载为只读的标志(默认为 false)。

Kubernetes 不包含内部 NFS 驱动。你需要使用外部驱动为 NFS 创建 StorageClass。 这里有些例子:

Ceph RBD

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/rbd
parameters:
  monitors: 10.16.153.105:6789
  adminId: kube
  adminSecretName: ceph-secret
  adminSecretNamespace: kube-system
  pool: kube
  userId: kube
  userSecretName: ceph-secret-user
  userSecretNamespace: default
  fsType: ext4
  imageFormat: "2"
  imageFeatures: "layering"

Local (本地)

特性状态: Kubernetes v1.14 [stable]

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

本地卷还不支持动态制备,但是还是需要创建 StorageClass 以延迟卷绑定, 直到完成 Pod 的调度。这是由 WaitForFirstConsumer 卷绑定模式指定的。

延迟卷绑定使得调度器在为 PersistentVolumeClaim 选择一个合适的 PersistentVolume 时能考虑到所有 Pod 的调度限制。

三.使用动态卷供应

启用动态卷供应

要启用动态供应功能,集群管理员需要为用户预先创建一个或多个 StorageClass 对象。 [详细见[StorageClass](#二. StorageClass 资源)]

StorageClass 对象定义当动态供应被调用时,哪一个驱动将被使用和哪些参数将被传递给驱动。

以下清单创建了一个 “fast” 存储类,它提供类似 SSD 的永久磁盘。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd

使用动态卷供应

用户通过在 PersistentVolumeClaim 中包含存储类来请求动态供应的存储。

在 Kubernetes v1.9 之前,这通过 volume.beta.kubernetes.io/storage-class 注解实现。然而,这个注解自 v1.6 起就不被推荐使用了。

用户现在能够而且应该使用 PersistentVolumeClaim 对象的 storageClassName 字段。 这个字段的值必须能够匹配到集群管理员配置的 StorageClass 名称(见[[StorageClass](#二. StorageClass 资源)])。

例如,要选择 “fast” 存储类,用户将创建如下的 PersistentVolumeClaim:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim1
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast 
  resources:
    requests:
      storage: 30Gi

该声明会自动供应一块类似 SSD 的永久磁盘。 在删除该声明后,这个卷也会被销毁。

设置默认值的行为

可以在集群上启用动态卷供应,以便在未指定存储类的情况下动态设置所有声明。

集群管理员可以通过以下方式启用此行为:

管理员可以通过向其添加 storageclass.kubernetes.io/is-default-class 注解来将特定的 StorageClass 标记为默认。

当集群中存在默认的 StorageClass 并且用户创建了一个未指定 storageClassNamePersistentVolumeClaim 时, DefaultStorageClass 准入控制器会自动向其中添加指向默认存储类的 storageClassName 字段。

请注意,集群上最多只能有一个 默认 存储类,否则无法创建没有明确指定 storageClassNamePersistentVolumeClaim

拓扑感知

多区域集群中,Pod 可以被分散到多个区域。 单区域存储后端应该被供应到 Pod 被调度到的区域。 这可以通过设置卷绑定模式来实现。

四. 创建NFS动态卷

使用 NFS 远程存储,为托管的 pod 提供了动态存储服务,pod 创建者无需关心数据以何种方式存在哪里,只需要提出需要多大空间的申请即可。

Kubernetes 不包含内部 NFS 驱动,使用github上提供的NFS subdir 外部驱动

总体流程是:

  1. 创建 NFS 服务器
  2. 创建 Service Account,用来管控 NFS provisioner 在k8s集群中运行的权限
  3. 创建 StorageClass,负责创建 PVC 并调用 NFS provisioner 进行预定的工作,并关联 PV 和 PVC
  4. 创建 NFS provisioner,有两个功能,一个是在NFS共享目录下创建挂载点(volume), 二是建立 PV 并将 PV 与 NFS 挂载点建立关联

创建RBAC授权

下载rbac资源清单

wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml

查看 rbac.yaml 内容:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

进行apply部署

kubectl apply -f rbac.yaml

创建nfs制备器

下载部署nfs制备器的 deployment 资源清单

wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml

修改nfs server和path 参数,改为自己nfs服务器地址和共享目录

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: docker.io/simple11618/nfs-subdir-external-provisioner:v4.0.2  ## 改为国内服务器镜像地址
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner  #此为storageclass中Provisioner 引用值
            - name: NFS_SERVER
              value: 10.42.0.1  #自己的nfs服务地址
            - name: NFS_PATH
              value: /nfs/share  #自己的nfs共享目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.42.0.1  #自己的nfs服务地址
            path: /nfs/share #自己的nfs共享目录

查看运行情况

kubectl get pods

NAME                                     READY   STATUS    RESTARTS      AGE
nfs-client-provisioner-65845c4f8-4vjgc   1/1     Running   0             4m4s

创建 Storageclass

下载 存储类清单

wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml

查看内容

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  archiveOnDelete: "false"

进行部署

kubectl apply -f class.yaml

查看部署情况

kubectl get sc
NAME                   PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
nfs-client             k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate              false                  2m21s

测试

创建PVC

vi pvc-test.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-test
spec:
  storageClassName: nfs-client
  accessModes: ReadWriteMany
  resources:
    requests:
      storage: 1G

创建

kubectl apply -f pvc-test.yaml

查看 pv 和 pvc状态

# 使用动态供应,会自动创建pv与 pvc进行绑定

kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-ef9ca3f1-110c-44bf-b1bf-a7548fa5801a   1G         RWX            Delete           Bound    default/pvc-test    nfs-client              21s


kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-test    Bound    pvc-ef9ca3f1-110c-44bf-b1bf-a7548fa5801a   1G         RWX            nfs-client     2m10s

创建POD

vi nfs-pod-test.yaml

# 将前面创建的pvc挂在到 容器内 /mnt下,并在挂在目录下创建一个 nfs-test 文件,之后到nfs目录下进行验证
apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod-test
spec:
  volumes:
  - name: nfs-pvc
    persistentVolumeClaim:
      claimName: pvc-test
  containers:
  - name: nfs-pod-test
    image: busybox
    command:
    - "/bin/sh"
    args:
    - "-c"
    - "touch /mnt/nfs-test && exit 0 || exit 1"
    volumeMounts:
    - name: nfs-pvc
      mountPath: "/mnt"
  restartPolicy: "Never"

验证

# 查看 pod状态
kubectl get pods
NAME                                     READY   STATUS      RESTARTS      AGE
nfs-pod-test                             0/1     Completed   0             10s


# 查看nfs共享目录下是否有nfs-test文件
[root@tengxun nfs]# cd /nfs/share/
[root@tengxun share]# ls
default-pvc-test-pvc-ef9ca3f1-110c-44bf-b1bf-a7548fa5801a
[root@tengxun share]# cd default-pvc-test-pvc-ef9ca3f1-110c-44bf-b1bf-a7548fa5801a/
[root@tengxun default-pvc-test-pvc-ef9ca3f1-110c-44bf-b1bf-a7548fa5801a]# ls
nfs-test


# 查看到nfs-test 文件,表示nfs动态卷使用成功

猜你喜欢

转载自blog.csdn.net/wq1205750492/article/details/125282613