为什么无法将非 root 用户访问权添加到持久存储器?

经典基础设施

即使配置了访问权限,非 root 用户也无法写入文件存储。

添加非根用户对持久存储的访问权限 或部署指定了非根用户 ID 的 Helm 图表后,用户就无法写入挂载的存储。

应用程序部署或 Helm 图表配置为 pod 的 fsGroup (组 ID)和 runAsUser (用户 ID)指定了 安全上下文。 通常,pod 的缺省安全上下文会设置 runAsNonRoot,以便 pod 无法以 root 用户身份运行。 由于 fsGroup 设置不是为共享存储(如 NFS 文件存储)设计的,因此不支持 fsGroup 设置,而 runAsUser 设置会自动设置为 2020。 这些缺省设置不允许其他非 root 用户写入已安装的存储器。

解决问题

要允许非 root 用户对文件存储设备进行读写访问,必须在存储类中分配 补充组标识,在 PVC 中引用此存储类,并使用自动添加到补充组标识的 runAsUser 值来设置 pod 的安全上下文。 当您授予对文件存储器的补充组标识读写访问权时,将授予属于组标识 (包括 pod) 的任何非 root 用户对文件存储器的访问权。

您可以使用其中一个提供的 gid 存储类 或创建自己的存储类来定义自己的补充组标识。

仅单专区集群支持为文件存储设备的非 root 用户分配补充组标识,并且不能在多专区集群中使用。

  1. 选择其中一个 提供的 gid 存储类,以将缺省组标识 65531 分配给要读写文件存储器的非 root 用户。 如果要分配定制组标识,请为定制存储类创建 YAML 文件。 在定制存储类 YAML 文件中,包含 gidAllocate: "true" 参数,并在 gidFixed 参数中定义组标识。

    分配默认组 ID 的存储类示例 65531

    • ibmc-file-bronze-gid
    • ibmc-file-silver-gid
    • ibmc-file-gold-gid

    指定不同组 ID 的自定义存储类示例:

    apiVersion: storage.k8s.io/v1beta1
    kind: StorageClass
    metadata:
      name: ibmc-file-bronze-gid-custom
      labels:
        kubernetes.io/cluster-service: "true"
    provisioner: ibm.io/ibmc-file
    parameters:
      type: "Endurance"
      iopsPerGB: "2"
      sizeRange: "[1-12000]Gi"
      mountOptions: nfsvers=4.1,hard
      billingType: "hourly"
      reclaimPolicy: "Delete"
      classVersion: "2"
      gidAllocate: "true"
      gidFixed: "65165"
    

    要在集群中创建存储类,请运行 kubectl apply -f storageclass.yaml

  2. 为使用您创建的存储类的 PVC 创建 YAML 文件。

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: gid-pvc
      labels:
        billingType: "monthly"
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 20Gi
      storageClassName: ibmc-file-bronze-gid
    
  3. 在集群中创建 PVC。

    kubectl apply -f pvc.yaml
    
  4. 等待几分钟,以便供应文件存储器和 PVC 更改为 Bound 状态。

    如果在多区群集中创建了 PVC,则 PVC 将保持 pending 状态。

    kubectl get pvc
    

    示例输出:

    NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS           AGE
    gid-pvc   Bound    pvc-5e4acab4-9b6f-4278-b53c-22e1d3ffa123   20Gi       RWX            ibmc-file-bronze-gid   2m54s
    
  5. 为安装您创建的 PVC 的部署创建 YAML 文件。 在 spec.template.spec.securityContext.runAsUser 字段中,指定要使用的非 root 用户标识。 此用户标识将自动添加到存储类中定义的补充组标识,以获取对文件存储器的读写访问权。

    创建 node-hello 部署的示例:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gid-deployment
      labels:
        app: gid
    spec:
      selector:
        matchLabels:
          app: gid
      template:
        metadata:
          labels:
            app: gid
        spec:
          containers:
          - image: gcr.io/google-samples/node-hello:1.0
            name: gid-container
            volumeMounts:
            - name: gid-vol
              mountPath: /myvol
          securityContext:
            runAsUser: 2020
          volumes:
          - name: gid-vol
            persistentVolumeClaim:
              claimName: gid-pvc
    
  6. 在集群中创建部署。

    kubectl apply -f deployment.yaml
    
  7. 确认 pod 处于运行状态。

    kubectl get pods
    

    示例输出:

    NAME                              READY   STATUS    RESTARTS   AGE
    gid-deployment-5dc86db4c4-5hbts   2/2     Running   0          69s
    
  8. 登录到 pod。

    kubectl exec <pod_name> -it -- bash
    

验证非 root 用户的读和写许可权

  1. 列出 pod 中当前用户的用户标识和组标识。 如果非 root 用户标识列示为 uid,并且在存储类中定义的补充组标识列示在 groups 下,那么设置正确。

    id
    

    示例输出:

    uid=2020 gid=0(root) groups=0(root), 65531
    
  2. 列出您在部署中定义的卷安装目录的许可权。 如果您在存储类中定义的补充组标识在卷安装目录中以读写许可权列出,那么设置正确。

    ls -l /<volume_mount_path>
    

    示例输出:

    drwxrwxr-x 2 nobody 65531 4096 Dec 11 07:40 .
    drwxr-xr-x 1 root   root  4096 Dec 11 07:30 ..
    
  3. 在挂载目录中创建一个文件。

    echo "Able to write to file storage with my non-root user." > /myvol/gidtest.txt
    
  4. 列出卷安装目录中文件的许可权。

    ls -al /myvol/
    

    示例输出:

    drwxrwxr-x 2 nobody      65531 4096 Dec 11 07:40 .
    drwxr-xr-x 1 root        root  4096 Dec 11 07:30 ..
    -rw-r--r-- 1 2020   4294967294   42 Dec 11 07:40 gidtest.txt .
    

    在 CLI 输出中,将列出对您创建的文件具有读和写访问权的非 root 用户标识。

  5. 退出 pod。

    exit
    

如果需要从 nobody 更改挂载路径的所有权,请参阅“当非 root 用户拥有 NFS 文件存储挂载路径时,应用程序会失败”。