容器服务 Kubernetes 版CSI支持subpath方式和filesystem方式两种类型的NAS动态存储卷挂载,您可以通过kubectl进行挂载。本文介绍如何使用阿里云NAS动态存储卷,以及如何验证NAS存储卷的持久化存储与共享存储特性。
前提条件
使用场景
对磁盘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的
reclaimPolicy
为Delete
时,即使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设置
allowVolumeExpansion
为true
时才会生效。此时,CSI将按照PVC容量设置NAS目录配额。NAS目录配额单位为GiB,实际设置的容量上限为PVC容量按GiB单位向上取整。NAS配额的生效是异步的,即PV动态创建后,目录配额不能保证立即生效,且快速连续写入大量数据可能会超出设置的容量上限。关于NAS目录配额的更多信息,请参见目录配额。
若您在应用模板中配置了securityContext.fsgroup参数,kubelet在存储卷挂载完成后会执行
chmod
或chown
操作,导致挂载时间延长。如需减少挂载时间,请参见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文件系统和挂载点。
创建NAS文件系统和挂载点。
创建StorageClass。
创建并复制以下内容到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
可选
subpath
、filesystem
,分别表示创建子目录类型的PV和文件系统类型的PV。server
表示创建子目录类型的PV时,NAS文件系统的挂载点地址。
重要此处需替换为实际的挂载点地址,关于如何查看挂载点地址,请参见查看挂载点地址。
provisioner
驱动类型。本例中取值为
nasplugin.csi.alibabacloud.com
,表示使用阿里云NAS CSI插件。reclaimPolicy
PV的回收策略,默认为
Delete
,支持Retain
。Delete模式:需配合
archiveOnDelete
一起使用。当
archiveOnDelete
为true
时,删除PVC时,PV和NAS文件只会被重命名,不会被删除。当
archiveOnDelete
为false
时,删除PVC时,PV和NAS文件会被真正删除。
Retain模式:删除PVC的时候,PV和NAS文件系统不会被删除,需要您手动删除。
如果数据安全性要求高,推荐使用
Retain
方式以免误删数据。archiveOnDelete
表示在
reclaimPolicy
为Delete
时,是否删除后端存储。因为NAS为共享存储,添加此选项进行双重确认。在参数parameters
下配置。默认为
true
,表示不会真正删除目录或文件,而是将其重命名,格式为archived-{pvName}.{timestamp}
。若配置为
false
,表示会真正删除后端对应的存储资源。
说明业务流量非常大时,不建议配置为false。更多信息,请参见使用NAS动态存储卷时Controller的任务队列已满且无法创建新的PV。
执行以下命令创建StorageClass。
kubectl create -f alicloud-nas-subpath.yaml
执行以下命令创建PVC。
创建并复制以下内容到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
,也可选择ReadWriteOnce
或ReadOnlyMany
。storageClassName
StorageClass的名称,用于绑定StorageClass。
storage
声明应用存储使用量。
重要此处设置的容量值不会限制应用实际可以使用的容量,且不会自动扩容。仅当使用通用型NAS,且StorageClass的
allowVolumeExpansion
为true时,才会为NAS目录设置配额。执行以下命令创建PVC。
kubectl create -f pvc.yaml
执行以下命令创建应用。
创建应用nginx-1和nginx-2共享NAS存储卷的同一个子目录。
创建并复制以下内容到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。
创建并复制以下内容到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。
执行以下命令创建应用nginx-1和nginx-2。
kubectl create -f nginx-1.yaml -f nginx-2.yaml
执行以下命令查看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-1和nginx-1以及pvc-2和nginx-2。
通过kubectl使用filesystem类型的NAS动态存储卷
filesystem类型的NAS动态卷在删除时默认保留文件系统和挂载点,如需在释放PV资源的同时释放NAS文件系统和挂载点,则需要同时设置StorageClass中的reclaimPolicy
为Delete
且deleteVolume
的值为true
。
使用filesystem类型NAS存储卷的Pod只能创建一个文件系统和一个挂载点。
仅ACK专有集群需执行以下全部步骤,其他类型集群从步骤2开始执行至结束。
可选: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: ""
创建StorageClass。
创建并复制以下内容到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的回收策略。当值为Delete且deleteVolume为true时,才会在删除PVC的时候将NAS文件系统删除。
执行以下命令创建StorageClass。
kubectl create -f alicloud-nas-fs.yaml
创建PVC和Pod挂载NAS存储卷。
创建并复制以下内容到pvc.yaml文件中。
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: nas-csi-pvc-fs spec: accessModes: - ReadWriteMany storageClassName: alicloud-nas-fs resources: requests: storage: 20Gi
创建并复制以下内容到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
执行以下命令创建PVC和Pod。
kubectl create -f pvc.yaml -f nginx.yaml
这种场景下,CSI会在PVC创建时动态新建NAS文件系统和挂载点,PVC删除时动态删除挂载点和文件系统。
验证NAS的存储特性
您可以通过以下示例,分别验证NAS的持久化存储和共享存储特性。
验证NAS的持久化存储
NAS提供了持久化存储服务,当某个Pod被删除时,重新部署的Pod将自动同步之前Pod的所有数据。根据以下示例验证NAS的持久化存储特性:
查看部署应用的Pod和NAS文件。
执行以下命令,查看部署的应用所在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
执行以下命令,查看任意一个Pod/data路径下的文件,本文以名为
deployment-nas-1-5b5cdb85f6-n****
的Pod为例。kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data
无返回结果,表明/data路径下无文件。
执行以下命令,在名为
deployment-nas-1-5b5cdb85f6-n****
的Pod/data路径下创建文件nas。kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- touch /data/nas
执行以下命令,查看名为
deployment-nas-1-5b5cdb85f6-n****
的Pod/data路径下的文件。kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data
预期输出:
nas
执行以下命令,删除Pod。
kubectl delete pod deployment-nas-1-5b5cdb85f6-n****
同时在另一个窗口中,执行以下命令,查看Pod删除及Kubernetes重建Pod的过程。
kubectl get pod -w -l app=nginx
验证删除Pod后,NAS里创建的文件是否还存在。
执行以下命令,查看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
执行以下命令,查看名为
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存储卷的共享存储特性:
查看部署的应用所在的Pod和NAS文件。
执行以下命令,查看应用所在的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路径下的文件。
kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data kubectl exec deployment-nas-2-c5bb4746c-4**** -- ls /data
执行以下命令,在任意一个Pod的/data路径下创建文件nas。
kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- touch /data/nas
执行以下命令,查看2个Pod/data路径下的文件。
执行以下命令,查看名为
deployment-nas-1-5b5cdb85f6-n****
的Pod/data路径下的文件。kubectl exec deployment-nas-1-5b5cdb85f6-n**** -- ls /data
预期输出:
nas
执行以下命令,查看名为
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的用户或用户组进行隔离。
使用以下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
执行以下命令,在容器中启动
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
命令。执行以下命令,验证在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用户。