使用NAS动态存储卷

容器服务 Kubernetes 版CSI支持subpath方式和filesystem方式两种类型的NAS动态存储卷挂载,您可以通过kubectl进行挂载。本文介绍如何使用阿里云NAS动态存储卷,以及如何验证NAS存储卷的持久化存储与共享存储特性。

前提条件

  • 已创建ACK Serverless集群。具体操作,请参见创建集群

  • CSI组件已升级至最新版本。更多信息,请参见管理CSI组件

使用场景

  • 对磁盘I/O要求较高的应用。

  • 读写性能相对于对象存储OSS更高。

  • 实现跨主机文件共享,例如可作为文件服务器。

使用限制及说明

  • NAS为共享存储,可以同时为多个Pod提供共享存储服务,即一个PVC可以同时被多个Pod使用。

  • CSI插件不支持SMB挂载。

  • 数据卷挂载协议推荐使用NFSv3。

  • NAS卷只能挂载到相同VPC的ECS实例,不支持不同VPC网络的挂载。

  • 通用NAS与极速NAS在挂载连通性、文件系统数量及协议类型等方面存在相应约束条件。更多信息,请参见使用限制

  • 使用NAS数据卷前,建议将CSI存储插件升级到最新版本。

  • NAS挂载点创建后,等待一定时间,待挂载点状态可用后方可使用。

  • 在没有卸载NAS文件系统前,务必不要删除NAS挂载点,否则会造成操作系统无响应。

  • ACK Serverless集群中,subpath类型的PV删除后,相应子目录的不会自动删除。也就意味着,当PV的reclaimPolicyDelete时,即使PV删除,NAS中实际的目录文件也并不会被删除。如需删除,需在手动挂载后执行删除。

注意事项

  • NAS为共享存储,可以同时为多个Pod提供共享存储服务,即一个PVC可以同时被多个应用使用。关于NAS并发写入的一些限制条件,请参见如何避免多进程或多客户端并发写同一日志文件可能出现的异常?如何解决向NFS文件系统中写入数据延迟问题?

  • 在使用极速NAS文件系统时,配置动态存储卷StorageClass中的path需要以/share为父目录。例如,0cd8b4a576-g****.cn-hangzhou.nas.aliyuncs.com:/share/subpath表示Pod挂载的NAS文件系统子目录为/share/subpath

  • NAS PVC的容量仅在文件系统类型为通用型NAS,且StorageClass设置allowVolumeExpansiontrue时才会生效。此时,CSI将按照PVC容量设置NAS目录配额。NAS目录配额单位为GiB,实际设置的容量上限为PVC容量按GiB单位向上取整。

    NAS配额的生效是异步的,即PV动态创建后,目录配额不能保证立即生效,且快速连续写入大量数据可能会超出设置的容量上限。关于NAS目录配额的更多信息,请参见目录配额

  • 若您在应用模板中配置了securityContext.fsgroup参数,kubelet在存储卷挂载完成后会执行chmodchown操作,导致挂载时间延长。如需减少挂载时间,请参见NAS存储卷挂载时间延长

使用NAS动态存储卷

CSI插件支持使用subpath方式和filesystem方式挂载NAS动态存储卷,您可以通过kubectl进行挂载。

subpath方式:支持通过kubectl命令行方式挂载。

当多个应用或者Pod需要挂载相同的NAS存储卷共享数据时,或者不同的Pod挂载相同的NAS文件系统的不同子目录时,您可以使用subpath方式进行挂载。

filesystem方式:仅支持通过kubectl命令行方式挂载。

当您的Kubernetes应用需要动态创建和删除NAS文件系统和挂载点时,您可以使用filesystem方式进行挂载。

sharepath方式:已废弃。如果您需要多个Pod挂载同一个NAS目录,请直接使用NAS静态存储卷

通过kubectl使用subpath类型的NAS动态存储卷

NAS动态存储卷的挂载方式为subpath类型时,您需要手动创建NAS文件系统和挂载点。

  1. 创建NAS文件系统和挂载点。

    1. 登录NAS控制台

    2. 创建NAS文件系统。具体操作,请参见创建文件系统

      说明

      若需要加密NAS存储卷中的数据,请在创建NAS文件系统时配置加密类型。

    3. 添加挂载点,并且该挂载点与集群节点在同一VPC内。具体操作,请参见管理挂载点

  2. 创建StorageClass。

    1. 创建并复制以下内容到alicloud-nas-subpath.yaml文件中。

      allowVolumeExpansion: true
      apiVersion: storage.k8s.io/v1
      kind: StorageClass
      metadata:
        name: alicloud-nas-subpath
      mountOptions:
      - nolock,tcp,noresvport
      - vers=3
      parameters:
        volumeAs: subpath
        server: "0cd8b4a576-g****.cn-hangzhou.nas.aliyuncs.com:/k8s/"
      provisioner: nasplugin.csi.alibabacloud.com
      reclaimPolicy: Retain

      参数

      描述

      allowVolumeExpansion

      仅通用型NAS文件系统支持设置此参数。开启时,该StorageClass动态创建的PV将会被配置NAS目录配额,并支持通过编辑PVC进行卷容量扩容。

      mountOptions

      挂载NAS的options参数在mountOptions中配置,包括NFS协议版本。

      volumeAs

      可选subpathfilesystem,分别表示创建子目录类型的PV和文件系统类型的PV。

      server

      表示创建子目录类型的PV时,NAS文件系统的挂载点地址。

      重要

      此处需替换为实际的挂载点地址,关于如何查看挂载点地址,请参见查看挂载点地址

      provisioner

      驱动类型。本例中取值为nasplugin.csi.alibabacloud.com,表示使用阿里云NAS CSI插件。

      reclaimPolicy

      PV的回收策略,默认为Delete,支持Retain

      • Delete模式:需配合archiveOnDelete一起使用。

        • archiveOnDeletetrue时,删除PVC时,PV和NAS文件只会被重命名,不会被删除。

        • archiveOnDeletefalse时,删除PVC时,PV和NAS文件会被真正删除。

      • Retain模式:删除PVC的时候,PV和NAS文件系统不会被删除,需要您手动删除。

      如果数据安全性要求高,推荐使用Retain方式以免误删数据。

      archiveOnDelete

      表示在reclaimPolicyDelete时,是否删除后端存储。因为NAS为共享存储,添加此选项进行双重确认。在参数parameters下配置。

      • 默认为true,表示不会真正删除目录或文件,而是将其重命名,格式为archived-{pvName}.{timestamp}

      • 若配置为false,表示会真正删除后端对应的存储资源。

      说明

      业务流量非常大时,不建议配置为false。更多信息,请参见使用NAS动态存储卷时Controller的任务队列已满且无法创建新的PV

    2. 执行以下命令创建StorageClass。

      kubectl create -f alicloud-nas-subpath.yaml
  3. 执行以下命令创建PVC。

    1. 创建并复制以下内容到pvc.yaml文件中。

      kind: PersistentVolumeClaim
      apiVersion: v1
      metadata: 
        name: nas-csi-pvc
      spec:
        accessModes:
        - ReadWriteMany 
        storageClassName: alicloud-nas-subpath
        resources: 
          requests:
            storage: 20Gi

      参数

      说明

      name

      PVC的名称。

      accessModes

      配置访问模式。默认为ReadWriteMany,也可选择ReadWriteOnceReadOnlyMany

      storageClassName

      StorageClass的名称,用于绑定StorageClass。

      storage

      声明应用存储使用量。

      重要

      此处设置的容量值不会限制应用实际可以使用的容量,且不会自动扩容。仅当使用通用型NAS,且StorageClass的allowVolumeExpansion为true时,才会为NAS目录设置配额。

    2. 执行以下命令创建PVC。

      kubectl create -f pvc.yaml
  4. 执行以下命令创建应用。

    创建应用nginx-1nginx-2共享NAS存储卷的同一个子目录。

    1. 创建并复制以下内容到nginx-1.yaml文件中。

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: deployment-nas-1
        labels:
          app: nginx-1
      spec:
        selector:
          matchLabels:
            app: nginx-1
        template:
          metadata:
            labels:
              app: nginx-1
          spec:
            containers:
            - name: nginx
              image: nginx:1.7.9
              ports:
              - containerPort: 80
              volumeMounts:
                - name: nas-pvc
                  mountPath: "/data"
            volumes:
              - name: nas-pvc
                persistentVolumeClaim:
                  claimName: nas-csi-pvc
      • mountPath:NAS在容器中挂载的位置。

      • claimName:PVC的名称,用于绑定PVC。本例中为nas-csi-pvc

    2. 创建并复制以下内容到nginx-2.yaml文件中。

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: deployment-nas-2
        labels:
          app: nginx-2
      spec:
        selector:
          matchLabels:
            app: nginx-2
        template:
          metadata:
            labels:
              app: nginx-2
          spec:
            containers:
            - name: nginx
              image: nginx:1.7.9
              ports:
              - containerPort: 80
              volumeMounts:
                - name: nas-pvc
                  mountPath: "/data"
            volumes:
              - name: nas-pvc
                persistentVolumeClaim:
                  claimName: nas-csi-pvc
      • mountPath:NAS在容器中挂载的位置。本例为/data

      • claimName:输入与nginx-1应用相同的PVC名称,本例为nas-csi-pvc

    3. 执行以下命令创建应用nginx-1nginx-2

      kubectl create -f nginx-1.yaml -f nginx-2.yaml
  5. 执行以下命令查看Pod信息。

    kubectl get pod

    预期输出:

    NAME                                READY   STATUS    RESTARTS   AGE
    deployment-nas-1-5b5cdb85f6-n****   1/1     Running   0          32s
    deployment-nas-2-c5bb4746c-4****    1/1     Running   0          32s
    说明

    NAS存储卷的0cd8b4a576-g****.cn-hangzhou.nas.aliyuncs.com:/share/nas-79438493-f3e0-11e9-bbe5-00163e09****会同时挂载到deployment-nas-1-5b5cdb85f6-n****deployment-nas-2-c5bb4746c-4****/data目录下。其中:

    • /share:StorageClass中指定的subpath。

    • nas-79438493-f3e0-11e9-bbe5-00163e09****:PV的名称。

    如果您需要为不同的Pod挂载同一个NAS文件系统的不同子目录,则需要分别创建pvc-1nginx-1以及pvc-2nginx-2

通过kubectl使用filesystem类型的NAS动态存储卷

重要

filesystem类型的NAS动态卷在删除时默认保留文件系统和挂载点,如需在释放PV资源的同时释放NAS文件系统和挂载点,则需要同时设置StorageClass中的reclaimPolicyDeletedeleteVolume的值为true

使用filesystem类型NAS存储卷的Pod只能创建一个文件系统和一个挂载点。

ACK专有集群需执行以下全部步骤,其他类型集群从步骤2开始执行至结束。

  1. 可选:RAM Policy设置和授予。

    如果您的集群是ACK专有集群,则需要执行本步骤。

    filesystem类型的NAS存储卷涉及NAS文件系统和挂载点的动态创建与删除,ACK专有集群需要授予csi-provisioner相应的权限,RAM Policy的最小集合如下。

    {
        "Action": [
            "nas:DescribeMountTargets",
            "nas:CreateMountTarget",
            "nas:DeleteFileSystem",
            "nas:DeleteMountTarget",
            "nas:CreateFileSystem"
        ],
        "Resource": [
            "*"
        ],
            "Effect": "Allow"
    }

    您可以通过以下任意一种方式进行授权:

    • 编辑ACK专有集群的Master RAM角色中的自定义策略内容,添加以上NAS相关的权限设置。请参见修改自定义权限策略内容和备注自定义授权

    • 创建RAM用户并授权以上RAM Policy并生成AccessKey,配置到csi-provisioner的env变量中。

      env:
      - name: CSI_ENDPOINT
        value: unix://socketDir/csi.sock
      - name: ACCESS_KEY_ID
        value: ""
      - name: ACCESS_KEY_SECRET
        value: ""
  2. 创建StorageClass。

    1. 创建并复制以下内容到alicloud-nas-fs.yaml文件中。

      apiVersion: storage.k8s.io/v1
      kind: StorageClass
      metadata:
        name: alicloud-nas-fs
      mountOptions:
      - nolock,tcp,noresvport
      - vers=3
      parameters:
        volumeAs: filesystem
        fileSystemType: standard
        storageType: Performance
        regionId: cn-beijing
        zoneId: cn-beijing-e
        vpcId: "vpc-2ze2fxn6popm8c2mzm****"
        vSwitchId: "vsw-2zwdg25a2b4y5juy****"
        accessGroupName: DEFAULT_VPC_GROUP_NAME
        deleteVolume: "false"
      provisioner: nasplugin.csi.alibabacloud.com
      reclaimPolicy: Retain

      参数

      描述

      volumeAs

      定义创建数据的类型,可选filesystem和subpath两种类型:

      • filesystem表示Provisioner自动创建NAS文件系统,一个PV对应一个NAS文件系统。

      • subpath类型表示一个PV对应一个NAS文件系统的子目录,Provisioner自动创建NAS文件系统的子目录。

      fileSystemType

      定义创建NAS文件系统的类型。可选standard和extreme两种类型:

      • standard:通用型NAS。

      • extreme:极速型NAS。

      默认为通用型NAS。

      storageType

      定义创建NAS文件系统的存储规格类型。

      • 当fileSystemType=standard时,可选Performance(性能型)和Capacity(容量型)两种类型,默认为性能型。

      • 当fileSystemType=extreme时,可选standard(标准型)和advanced(高级型)两种类型,默认为标准型。

      regionId

      定义创建NAS文件系统所在地域。

      zoneId

      定义创建NAS文件系统所在可用区。

      vpcId

      定义创建NAS文件系统对应挂载点所在VPC。

      vSwitchId

      定义创建NAS文件系统对应挂载点所在vSwitch ID。

      accessGroupName

      定义创建NAS文件系统对应挂载点所用的AccessGroup。默认为DEFAULT_VPC_GROUP_NAME

      deleteVolume

      定义数据卷删除时处理NAS文件系统策略,由于NAS为共享文件系统,安全起见需要同时配置。

      provisioner

      驱动类型。本例中取值为nasplugin.csi.alibabacloud.com,表示使用阿里云NAS CSI插件。

      reclaimPolicy

      PV的回收策略。当值为DeletedeleteVolumetrue时,才会在删除PVC的时候将NAS文件系统删除。

    2. 执行以下命令创建StorageClass。

      kubectl create -f alicloud-nas-fs.yaml
  3. 创建PVC和Pod挂载NAS存储卷。

    1. 创建并复制以下内容到pvc.yaml文件中。

      kind: PersistentVolumeClaim
      apiVersion: v1
      metadata:
        name: nas-csi-pvc-fs
      spec:
        accessModes:
          - ReadWriteMany
        storageClassName: alicloud-nas-fs
        resources:
          requests:
            storage: 20Gi
    2. 创建并复制以下内容到nginx.yaml文件中。

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: deployment-nas-fs
        labels:
          app: nginx
      spec:
        selector:
          matchLabels:
            app: nginx
        template:
          metadata:
            labels:
              app: nginx
          spec:
            containers:
            - name: nginx
              image: nginx:1.7.9
              ports:
              - containerPort: 80
              volumeMounts:
                - name: nas-pvc
                  mountPath: "/data"
            volumes:
              - name: nas-pvc
                persistentVolumeClaim:
                  claimName: nas-csi-pvc-fs
    3. 执行以下命令创建PVC和Pod。

      kubectl create -f pvc.yaml -f nginx.yaml

这种场景下,CSI会在PVC创建时动态新建NAS文件系统和挂载点,PVC删除时动态删除挂载点和文件系统。

验证NAS的存储特性

您可以通过以下示例,分别验证NAS的持久化存储和共享存储特性。

验证NAS的持久化存储

NAS提供了持久化存储服务,当某个Pod被删除时,重新部署的Pod将自动同步之前Pod的所有数据。根据以下示例验证NAS的持久化存储特性:

  1. 查看部署应用的Pod和NAS文件。

    1. 执行以下命令,查看部署的应用所在Pod的名称。

      kubectl get pod 

      预期输出:

      NAME                                READY   STATUS    RESTARTS   AGE
      deployment-nas-1-5b5cdb85f6-n****   1/1     Running   0          32s
      deployment-nas-2-c5bb4746c-4****    1/1     Running   0          32s
    2. 执行以下命令,查看任意一个Pod/data路径下的文件,本文以名为deployment-nas-1-5b5cdb85f6-n****的Pod为例。

      kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data

      无返回结果,表明/data路径下无文件。

  2. 执行以下命令,在名为deployment-nas-1-5b5cdb85f6-n****的Pod/data路径下创建文件nas。

    kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- touch /data/nas
  3. 执行以下命令,查看名为deployment-nas-1-5b5cdb85f6-n****的Pod/data路径下的文件。

    kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data

    预期输出:

    nas
  4. 执行以下命令,删除Pod。

    kubectl delete pod deployment-nas-1-5b5cdb85f6-n****
  5. 同时在另一个窗口中,执行以下命令,查看Pod删除及Kubernetes重建Pod的过程。

    kubectl get pod -w -l app=nginx
  6. 验证删除Pod后,NAS里创建的文件是否还存在。

    1. 执行以下命令,查看Kubernetes重建的Pod名称。

      kubectl get pod

      预期输出:

      NAME                                READY   STATUS    RESTARTS   AGE
      deployment-nas-1-5b5cdm2g5-m****    1/1     Running   0          32s
      deployment-nas-2-c5bb4746c-4****    1/1     Running   0          32s
    2. 执行以下命令,查看名为deployment-nas-1-5b5cdm2g5-m****的Pod/data路径下的文件。

      kubectl exec deployment-nas-1-5b5cdm2g5-m**** -- ls /data

      预期输出:

      nas

      nas文件仍然存在,说明NAS的数据可持久化保存。

验证NAS的共享存储

NAS存储卷支持同时被多个Pod挂载,当某个Pod修改数据时,其余Pod将自行实现数据的同步,根据以下示例验证NAS存储卷的共享存储特性:

  1. 查看部署的应用所在的Pod和NAS文件。

    1. 执行以下命令,查看应用所在的Pod名称。

      kubectl get pod 

      预期输出:

      NAME                                READY   STATUS    RESTARTS   AGE
      deployment-nas-1-5b5cdb85f6-n****   1/1     Running   0          32s
      deployment-nas-2-c5bb4746c-4****    1/1     Running   0          32s
    2. 执行以下命令,查看2个Pod/data路径下的文件。

      kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data
      kubectl exec deployment-nas-2-c5bb4746c-4**** -- ls /data
  2. 执行以下命令,在任意一个Pod的/data路径下创建文件nas。

     kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- touch /data/nas
  3. 执行以下命令,查看2个Pod/data路径下的文件。

    1. 执行以下命令,查看名为deployment-nas-1-5b5cdb85f6-n****的Pod/data路径下的文件。

      kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data

      预期输出:

      nas
    2. 执行以下命令,查看名为deployment-nas-2-c5bb4746c-4****的Pod /data路径下的文件。

      kubectl exec deployment-nas-2-c5bb4746c-4**** -- ls /data

      预期输出:

      nas

      在任意一个Pod的/data下创建的文件,两个Pod下的/data路径下均存在此文件,说明两个Pod共享一个NAS。

如何实现NAS的用户或用户组隔离

为确保不同用户和用户组之间数据的安全性,您可以参考以下操作对NAS的用户或用户组进行隔离。

  1. 使用以下YAML内容,在容器组内使用nobody用户启动进程,创建的目录UID和GID为65534。

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: nas-sts
    spec:
      selector:
        matchLabels:
          app: busybox
      serviceName: "busybox"
      replicas: 1
      template:
        metadata:
          labels:
            app: busybox
        spec:
          securityContext:
            fsGroup: 65534    #创建目录/文件时,UID/GID为65534(nobody用户)。
            fsGroupChangePolicy: "OnRootMismatch"    #只有根目录的属主与访问权限与卷所期望的权限不一致时, 才改变其中内容的属主和访问权限。
          containers:
          - name: busybox
            image: busybox
            command:
            - sleep
            - "3600"
            securityContext:
              runAsUser: 65534    #所有容器内的进程都使用用户ID为65534(nobody用户)来运行。
              runAsGroup: 65534   #所有容器中的进程都以主组ID为65534(nobody用户)来运行。
              allowPrivilegeEscalation: false
            volumeMounts:
            - name: nas-pvc
              mountPath: /data
      volumeClaimTemplates:
      - metadata:
          name: nas-pvc
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "alicloud-nas-subpath"
          resources:
            requests:
              storage: 100Gi
  2. 执行以下命令,在容器中启动top命令,查看USER是否为nobody。

    kubectl exec nas-sts-0 -- "top"

    预期输出:

    Mem: 11538180K used, 52037796K free, 5052K shrd, 253696K buff, 8865272K cached
    CPU:  0.1% usr  0.1% sys  0.0% nic 99.7% idle  0.0% io  0.0% irq  0.0% sirq
    Load average: 0.76 0.60 0.58 1/1458 54
      PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
       49     0 nobody   R     1328  0.0   9  0.0 top
        1     0 nobody   S     1316  0.0  10  0.0 sleep 3600

    预期输出表明,是nobody用户执行的top命令。

  3. 执行以下命令,验证在NAS挂载目录下创建的目录和文件是否为nobody

    kubectl exec nas-sts-0 -- sh -c "touch /data/test; mkdir /data/test-dir; ls -arlth /data/"

    预期输出:

    total 5K
    drwxr-xr-x    1 root     root        4.0K Aug 30 10:14 ..
    drwxr-sr-x    2 nobody   nobody      4.0K Aug 30 10:14 test-dir
    -rw-r--r--    1 nobody   nobody         0 Aug 30 10:14 test
    drwxrwsrwx    3 root     nobody      4.0K Aug 30 10:14 .

    预期输出表明,在/data下创建的test文件和test-dir目录中,UID和GID对应的用户均为nobody用户。