【问题标题】:Kubernetes: how to set VolumeMount user group and file permissionsKubernetes:如何设置 VolumeMount 用户组和文件权限
【发布时间】:2017-09-18 13:18:15
【问题描述】:

我正在使用 kops 在 AWS 上运行 Kubernetes 集群。我已将 EBS 卷安装到容器上,它在我的应用程序中可见,但它是只读的,因为我的应用程序没有以 root 身份运行。如何以 root 以外的用户身份挂载 PersistentVolumeClaimVolumeMount 似乎没有任何选项来控制挂载路径的用户、组或文件权限。

这是我的部署 yaml 文件:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: notebook-1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: notebook-1
    spec:
      volumes:
      - name: notebook-1
        persistentVolumeClaim:
          claimName: notebook-1
      containers:
      - name: notebook-1
        image: jupyter/base-notebook
        ports:
        - containerPort: 8888
        volumeMounts:
        - mountPath: "/home/jovyan/work"
          name: notebook-1

【问题讨论】:

    标签: amazon-web-services docker kubernetes persistent-volume-claims


    【解决方案1】:

    Pod 安全上下文支持设置fsGroup,它允许您设置拥有该卷的组 ID,从而设置谁可以写入它。文档中的示例:

    apiVersion: v1
    kind: Pod
    metadata:
      name: hello-world
    spec:
      containers:
      # specification of the pod's containers
      # ...
      securityContext:
        fsGroup: 1234
    

    更多信息请联系here

    【讨论】:

    • 还要注意 volumes.*.defaultMode 字段以设置安全位 - v1-7.docs.kubernetes.io/docs/concepts/configuration/secret/…
    • 嗨,不能解决当您的软件需要时您需要对某些文件设置只读权限的用例。我正在努力解决这个问题,试图避免创建一个允许的 PSP,愿意保留 RunAsUser: MustRunAsNonRoot,因为这将适用于 pod 中的所有容器。我正在考虑使用 sudoers 特定规则创建一个自定义图像,以便为非 root 用户使用 sudo 执行 chmod/chown,我将其称为 initContainer image 。欢迎任何更好/可行的想法。
    • 很棒的答案!泰!
    • securityContext 是执行此操作的有效方法,但是当它需要 spec 时,您可以在 spec.container 中使用它。注意:spec.container 中有一个securityContext,但这与规范级别的不同。 fsGroup 在容器级别不可用 securityContext
    【解决方案2】:

    对于 k8s 1.10+ 版本,添加了runAsGroup,它与fsGroup 类似,但工作方式不同。

    可在此处跟踪实施情况:https://github.com/kubernetes/features/issues/213

    【讨论】:

    • 当您指定runAsGroup 时,容器将作为该组启动,但卷的所有权不会改变。所以它们是不同的,我用两者来使我的卷可写。
    • 同时添加 fsgroup。添加 fsgroup 上下文后,只有它还会看到 runasgroup 上下文来设置文件夹的所有权。您可以将与 runasgroup 相同的用户添加到 fsgroup 或将补充用户组添加到 fsgroup。
    【解决方案3】:

    我最终得到了一个 initContainer,它与主容器具有相同的 volumeMount,以便为自定义 Grafana 图像设置适当的权限。

    当 pod 中的容器以 root 以外的用户身份运行并且需要对已挂载的卷具有写入权限时,这是必需的。

    initContainers:
    - name: take-data-dir-ownership
      image: alpine:3
      # Give `grafana` user (id 472) permissions a mounted volume
      # https://github.com/grafana/grafana-docker/blob/master/Dockerfile
      command:
      - chown
      - -R
      - 472:472
      - /var/lib/grafana
      volumeMounts:
      - name: data
        mountPath: /var/lib/grafana
    

    【讨论】:

    • 您不是必须以 root 用户身份运行 initContainer 吗?否则它怎么会有权限向非 root 用户 chown?
    • @Oliver:在此示例中,initContainer 隐式以 root 身份运行。主容器将使用映像本身中指定的用户运行,除非 container.securityContext.runAsUsercontainer.securityContext.runAsNonRoot(或其他)已明确设置为其他内容。 ref
    • 你拯救了我的一天
    • 当我部署 grafana 时(和你一样)securityContextfsGroup: 472 就足够了。
    • 谁会想到这个?像魅力一样工作!
    【解决方案4】:

    当您必须以非 root 用户身份在容器内运行进程时,这是 Kubernetes 部署/StatefulSets 面临的挑战之一。但是,当您将卷挂载到 pod 时,它始终会在 root:root 的许可下挂载。

    因此,非 root 用户必须有权访问它要读取和写入数据的文件夹。

    请按照以下步骤操作。

    1. 在 Dockerfile 中创建用户组并分配组 ID。
    2. 使用用户 ID 创建用户并添加到 Dockerfile 中的组。
    3. 递归更改用户进程想要读取/写入的文件夹的所有权。
    4. 在 pod spec 上下文中的 Deployment/StatefulSet 中添加以下行。

      spec:
        securityContext:
          runAsUser: 1099
          runAsGroup: 1099
          fsGroup: 1099
      

    runAsUser

    指定对于 Pod 中的任何容器,所有进程都以用户 ID 1099 运行。

    runAsGroup

    为 Pod 的任何容器中的所有进程指定主组 ID 1099。

    如果省略此字段,则容器的主要组 ID 将为 root(0)

    当指定runAsGroup 时,创建的任何文件也将归用户 1099 和组 1099 所有。

    fsGroup

    指定任何附加卷的所有者将是组 ID 1099 的所有者。

    在其下创建的任何文件都将拥有nonrootgroup:nonrootgroup 的权限。

    【讨论】:

    • 做上帝的工作!谢谢! fsGroup 正是我所需要的!谢谢好心的先生!
    • 当你的图片是FROM scratch,不能真正添加​​用户或组。
    【解决方案5】:

    要更改文件系统权限,请在实际容器启动之前运行initcontainer

    这里是弹性搜索 pod 的示例

    initContainers:
          - command:
            - sh
            - -c
            - chown -R 1000:1000 /usr/share/elasticsearch/data
            - sysctl -w vm.max_map_count=262144
            - chgrp 1000 /usr/share/elasticsearch/data
            image: busybox:1.29.2
            imagePullPolicy: IfNotPresent
            name: set-dir-owner
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:                         #Volume mount path
            - mountPath: /usr/share/elasticsearch/data
              name: elasticsearch-data
    

    更改容器中的用户组

    spec:
          containers:
          securityContext:
              privileged: true
              runAsUser: 1000
    

    【讨论】:

    • 嗨,Harsh,您使用了两次“特权”指令,这在这里毫无用处,而且是绝对糟糕的 [安全] 做法。
    • @tisc0 很抱歉,但是更新后的答案不需要在 init 容器中使用。
    • @tisc0 非常感谢您指出并纠正我希望它对其他人也有帮助。
    • 不客气。不过,我在您的代码的第二部分“更改容器中的用户组”中,您仍在使用特权,而且我没有看到 runAsGroup 或 fsGroup 之类的东西。 (不想打扰,只是彻底)。
    【解决方案6】:

    请参考本期:https://github.com/kubernetes/kubernetes/issues/2630

    如果是emptydir,则可以使用spec中的securityContext

    spec:
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
    containers: ...
    

    如果卷是hostpathinitContainer 可用于卷中的chown 路径:

    initContainers:
        - name: example-c
          image: busybox:latest
          command: ["sh","-c","mkdir -p /vol-path && chown -R 1000:1000 /vol-path"]
          resources:
            limits:
              cpu: "1"
              memory: 1Gi
          volumeMounts:
            - name: vol-example
              mountPath: /vol-path
    

    【讨论】:

      【解决方案7】:

      经过几次迭代,我最终使用了

      {{- $root := . }}
      ...
            initContainers:
            - name: volume-mount-hack
              image: busybox
              command: ["sh", "-c", "find /data -user root -exec chown 33:33 {} \\;"]
              volumeMounts:
      {{- range $key,$val := .Values.persistence.mounts }}
              - name: data
                mountPath: /data/{{ $key }}
                subPath: {{ $root.Values.projectKey }}/{{ $key }}
      {{- end }}
      

      与其他解决方案相比,它更加简洁和可配置。此外,它更快 - find 命令只更改实际属于 root 用户的文件/目录的权限。

      当您装载包含大量文件的卷时,这可能会对您的容器启动/加载时间(几秒钟甚至几分钟!)产生重大影响。

      尝试比较执行时间

      chown www-data:www-data ./ -R

      find /data -user root -exec chown 33:33 {} \\;

      你可能会感到惊讶!

      【讨论】:

        【解决方案8】:
        • 在 minikube 中,它在以 root 用户身份运行 initContainers 后工作,通过设置 runAsUser: 0
            initContainers:
              - name: change-ownership-container
                image: busybox
                command: ["/bin/chown","-R","1000:1000", "/home/jovyan/work"]
                securityContext:
                  runAsUser: 0
                  privileged: true
                volumeMounts:
                - name: notebook-data
                  mountPath: /home/jovyan/work 
        

        所以整个 Yaml 文件看起来像这样

        apiVersion: apps/v1
        kind: StatefulSet
        metadata:
          name: jupyter
          labels:
            release: jupyter
        spec:
          replicas:
          updateStrategy:
            type: RollingUpdate
          serviceName: jupyter-headless
          podManagementPolicy: Parallel
          selector:
            matchLabels:
              release: jupyter
          template:
            metadata:
              labels:
                release: jupyter
              annotations:
            spec:
              restartPolicy: Always
              terminationGracePeriodSeconds: 30
              securityContext:
                runAsUser: 1000
                fsGroup: 1000
              containers:
              - name: jupyter
                image: "jupyter/base-notebook:ubuntu-20.04"
                imagePullPolicy: IfNotPresent
                ports:
                - name: http
                  containerPort: 8888
                  protocol: TCP
                - name: blockmanager
                  containerPort: 7777
                  protocol: TCP
                - name: driver
                  containerPort: 2222
                  protocol: TCP
                volumeMounts:
                - name: notebook-data
                  mountPath: /home/jovyan/work
                resources:
                  limits:
                    cpu: 200m
                    memory: 300Mi
                  requests:
                    cpu: 100m
                    memory: 200Mi
              initContainers:
              - name: change-ownership-container
                image: busybox
                command: ["/bin/chown","-R","1000:1000", "/home/jovyan/work"]
                securityContext:
                  runAsUser: 0
                  privileged: true
                volumeMounts:
                - name: notebook-data
                  mountPath: /home/jovyan/work
              volumes:
              - name: notebook-data
                persistentVolumeClaim:
                  claimName: jupyter-pvc  
        

        【讨论】:

          【解决方案9】:

          在我的例子中,我使用scratch 作为基础映像并将用户设置为 65543。我需要对目录的写入权限。我通过使用emptyDir 音量来做到这一点,

          spec:
            containers:
              ...
              volumeMounts:
                - mountPath: /tmp
                  name: tmp
                  # readOnly: true
            volumes:
            - name: tmp
              emptyDir: {}
          

          【讨论】:

            猜你喜欢
            • 2020-05-19
            • 1970-01-01
            • 2016-03-08
            • 2013-12-03
            • 1970-01-01
            • 2021-02-12
            • 2019-07-25
            • 1970-01-01
            • 2013-12-22
            相关资源
            最近更新 更多