Kubernetes NFS持久化卷权限被拒绝

26

我有一个在Kubernetes中的POD运行的应用程序。 我想将一些输出文件日志存储在持久化存储卷上。

为了实现这个目的,我创建了一个基于NFS的卷,并通过相关的卷声明将其绑定到POD上。 当我尝试写入或访问共享文件夹时,会收到“权限被拒绝”的消息,因为NFS显然是只读的。

以下是我用来创建卷的json文件:

{
      "kind": "PersistentVolume",
      "apiVersion": "v1",
      "metadata": {
        "name": "task-pv-test"
      },
      "spec": {
        "capacity": {
          "storage": "10Gi"
        },
        "nfs": {
          "server": <IPAddress>,
          "path": "/export"
        },
        "accessModes": [
          "ReadWriteMany"
        ],
        "persistentVolumeReclaimPolicy": "Delete",
        "storageClassName": "standard"
      }
    }
以下是POD配置文件。
kind: Pod
apiVersion: v1
metadata:
    name: volume-test
spec:
    volumes:
        -   name: task-pv-test-storage
            persistentVolumeClaim:
                claimName: task-pv-test-claim
    containers:
        -   name: volume-test
            image: <ImageName>
            volumeMounts:
            -   mountPath: /home
                name: task-pv-test-storage
                readOnly: false

有没有一种方法可以更改权限?


更新

这是 PVC 和 NFS 配置:

PVC:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: task-pv-test-claim
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 3Gi

NFS 配置

{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "nfs-client-provisioner-557b575fbc-hkzfp",
    "generateName": "nfs-client-provisioner-557b575fbc-",
    "namespace": "default",
    "selfLink": "/api/v1/namespaces/default/pods/nfs-client-provisioner-557b575fbc-hkzfp",
    "uid": "918b1220-423a-11e8-8c62-8aaf7effe4a0",
    "resourceVersion": "27228",
    "creationTimestamp": "2018-04-17T12:26:35Z",
    "labels": {
      "app": "nfs-client-provisioner",
      "pod-template-hash": "1136131967"
    },
    "ownerReferences": [
      {
        "apiVersion": "extensions/v1beta1",
        "kind": "ReplicaSet",
        "name": "nfs-client-provisioner-557b575fbc",
        "uid": "3239b14a-4222-11e8-8c62-8aaf7effe4a0",
        "controller": true,
        "blockOwnerDeletion": true
      }
    ]
  },
  "spec": {
    "volumes": [
      {
        "name": "nfs-client-root",
        "nfs": {
          "server": <IPAddress>,
          "path": "/Kubernetes"
        }
      },
      {
        "name": "nfs-client-provisioner-token-fdd2c",
        "secret": {
          "secretName": "nfs-client-provisioner-token-fdd2c",
          "defaultMode": 420
        }
      }
    ],
    "containers": [
      {
        "name": "nfs-client-provisioner",
        "image": "quay.io/external_storage/nfs-client-provisioner:latest",
        "env": [
          {
            "name": "PROVISIONER_NAME",
            "value": "<IPAddress>/Kubernetes"
          },
          {
            "name": "NFS_SERVER",
            "value": <IPAddress>
          },
          {
            "name": "NFS_PATH",
            "value": "/Kubernetes"
          }
        ],
        "resources": {},
        "volumeMounts": [
          {
            "name": "nfs-client-root",
            "mountPath": "/persistentvolumes"
          },
          {
            "name": "nfs-client-provisioner-token-fdd2c",
            "readOnly": true,
            "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
          }
        ],
        "terminationMessagePath": "/dev/termination-log",
        "terminationMessagePolicy": "File",
        "imagePullPolicy": "Always"
      }
    ],
    "restartPolicy": "Always",
    "terminationGracePeriodSeconds": 30,
    "dnsPolicy": "ClusterFirst",
    "serviceAccountName": "nfs-client-provisioner",
    "serviceAccount": "nfs-client-provisioner",
    "nodeName": "det-vkube-s02",
    "securityContext": {},
    "schedulerName": "default-scheduler",
    "tolerations": [
      {
        "key": "node.kubernetes.io/not-ready",
        "operator": "Exists",
        "effect": "NoExecute",
        "tolerationSeconds": 300
      },
      {
        "key": "node.kubernetes.io/unreachable",
        "operator": "Exists",
        "effect": "NoExecute",
        "tolerationSeconds": 300
      }
    ]
  },
  "status": {
    "phase": "Running",
    "hostIP": <IPAddress>,
    "podIP": "<IPAddress>,
    "startTime": "2018-04-17T12:26:35Z",
    "qosClass": "BestEffort"
  }
}

我刚刚从nfs配置中删除了一些状态信息,以使其更短


1
你能发布一下你的nfs配置和pvc吗? - Const
@fragae,你找到解决方案了吗?我也遇到了同样的问题。 - lokanadham100
@LokanadhamMotumarri,在 pod 配置文件中设置正确的组 ID 来设置 SecurityContext 对我有用。 - fragae
5个回答

37
如果您为Pod配置设置了适当的securityContext,则可以确保以正确的权限挂载卷。

例如:

apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  securityContext:
    fsGroup: 2000 
  volumes:
    - name: task-pv-test-storage
      persistentVolumeClaim:
        claimName: task-pv-test-claim
  containers:
  - name: demo
    image: example-image
    volumeMounts:
    - name: task-pv-test-storage
      mountPath: /data/demo
在上述示例中,存储将被挂载到/data/demo,其组ID为2000,由fsGroup设置。通过设置fsGroup,容器的所有进程也将成为附加组ID 2000的一部分,因此您应该可以访问已挂载的文件。 您可以在此处阅读有关Pod安全上下文的更多信息:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

1
该示例不会使用NFS。因此,/data/demo具有2000个gid。 但是,如果我们将PV更改为NFS,我们也会遇到权限错误。 - lokanadham100
2
也尝试了使用NFS,但在fsGroup方面无法正常工作。 可能是因为这个问题:https://github.com/kubernetes/examples/issues/260 - Kutzi
为什么需要查找用户。文档明确说明:...由于指定了fsGroup字段,容器的所有进程也是附加组ID 2000的一部分。卷/data/demo的所有者以及在该卷中创建的任何文件都将是组ID 2000。 - yuranos
你是对的,我已经更新了答案。 - MrBlaise
1
我不知道,伙计,有证据表明 fsGroup 在 NFS 上不起作用,可以看看这个 GitHub 问题:https://github.com/kubernetes/examples/issues/260 - Elouan Keryell-Even
这里运行得非常完美,谢谢! - v1d3rm3

19

感谢白栋天提供的 提示

例如,如果pod的 securityContext 被设置为:

securityContext:
  runAsUser: 1000
  fsGroup: 1000

您需要 SSH 连接到 NFS 主机并运行以下命令:

chown 1000:1000 -R /some/nfs/path

如果您不知道用户:组或许多 Pod 将挂载它,则可以运行

chmod 777 -R /some/nfs/path

3
从安全角度来看,我不确定chmod 777是一个好的方法,但至少对我来说这是一个解决方案(在经历了许多令人沮丧的小时之后)。有趣的是,使用动态/托管的配置( https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client ),这根本不是一个问题。无论如何,感谢您的建议,这对我的homelab是足够的。 - gimlichael
2
@gimlichael 看起来动态提供程序确实可以做到这一点,chmod 777:https://github.com/kubernetes-incubator/external-storage/blob/master/nfs-client/cmd/nfs-client-provisioner/provisioner.go#L72 - Philipp Nowak
如果您像上面的示例一样设置了“runAsUser: 1000”,那么chmod 755应该可以工作。如果您设置“fsGroup: 1000”,而没有像之前的答案中那样同时设置用户,则至少需要770(或775),因为用户只会使用指定的GID运行。 - Sebastien Martin

2
一种简单的方法是访问nfs存储,然后使用chmod 777或在volume-test容器中使用用户ID进行chown。请注意保留HTML标签。

我尝试使用来自volume-test容器配置文件的用户ID更改所有者,但是我收到了一个无效用户消息。该ID看起来像:“uid”:“923ca461-4ec9-11e8-8ab3-8aaf7effe4a0”。那是正确的吗? - fragae
用户ID由位于dockerfile末尾的USER决定,默认设置为0(root)。如果您不知道用户ID(可以通过在容器中执行“id”来获取),那么只需使用chmod +R 777。 - 白栋天
我不确定为什么有人会对此进行负投票。这个问题是关于NFS的,显然正如上面指出的那样,NFS主机需要设置权限,因为Kubernetes无法管理NFS主机的权限。 - AlaskaJoslin

0

我有点困惑你尝试完成任务的方式,无论如何,如果我理解正确,请参考以下示例:

  volumeClaimTemplates:
  - metadata:
      name: data
      namespace: kube-system
      labels:
        k8s-app: something
        monitoring: something
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi

然后可能有一个初始化容器来执行某些操作:

initContainers:
        - name: prometheus-init
          image: /something/bash-alpine:1.5
          command:
            - chown
            - -R
            - 65534:65534
            - /data
          volumeMounts:
            - name: data
              mountPath: /data

或者你错过了volumeMounts:
volumeMounts:
            - name: config-volume
              mountPath: /etc/config
            - name: data
              mountPath: /data

我的最后一条评论是要注意容器,我认为你只能写入/tmp,还是只针对CoreOS?我需要查一下。


-9

您是否已经检查了目录的权限?请确保所有人都有读取访问权限。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接