IBM Cloud Docs
当非 root 用户拥有 NFS 文件存储器安装路径时,为什么我的应用程序会失败?

当非 root 用户拥有 NFS 文件存储器安装路径时,为什么我的应用程序会失败?

经典基础结构

向部署添加 NFS 存储器后,容器的部署失败。 检索容器的日志时,您可能会看到如下所示的错误。 pod 发生故障,并且卡在重新装入循环中。

write-permission
don't have required permission
can't create directory '/bitnami/mariadb/data': Permission denied

缺省情况下,非 root 用户对 NFS支持的存储器的卷安装路径没有写许可权。 一些公共应用程序映像(例如,Jenkins 和 Nexus3)会在 Dockerfile 中指定拥有安装路径的非 root 用户。

通过此 Dockerfile 创建容器时,由于安装路径上非 root 用户的许可权不足,创建容器会失败。 要授予写许可权,您可以修改 Dockerfile 以在更改安装路径许可权之前临时将非 root 用户添加到 root 用户组,或者使用 init 容器。

如果使用 Helm Chart 来部署映像,请编辑 Helm 部署以使用 init 容器。

在部署中包含 init 容器 时,您可以为容器内卷安装路径提供 Dockerfile 写许可权中指定的非 root 用户。

init 容器在应用程序容器启动之前启动。 init 容器在容器内创建卷安装路径,将安装路径更改为由正确 (非 root) 用户拥有,然后关闭。 随后,应用程序容器将以必须写入安装路径的非 root 用户身份启动。 由于该路径已由非 root 用户拥有,因此写入安装路径成功。 如果您不想使用 init 容器,那么可以修改 Dockerfile 以向 NFS 文件存储器添加非 root 用户访问权。

开始之前: 登录到您的帐户。 如果适用,请将相应的资源组设定为目标。 设置集群的上下文。

  1. 打开应用程序的 Dockerfile,并从要向其授予卷安装路径的写入者许可权的用户获取用户标识 (UID) 和组标识 (GID)。 在来自 Jenkins Dockerfile 的示例中,信息为:

    • UID:1000
    • GID:1000

    示例 Dockerfile

    FROM openjdk:8-jdk
    
    RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
    
    ARG user=jenkins
    ARG group=jenkins
    ARG uid=1000
    ARG gid=1000
    ARG http_port=8080
    ARG agent_port=50000
    
    ENV JENKINS_HOME /var/jenkins_home
    ENV JENKINS_SLAVE_AGENT_PORT ${agent_port}
    ...
    
  2. 通过创建持久卷声明 (PVC) 将持久性存储器添加到应用程序。 此示例使用 ibmc-file-bronze 存储类。 要查看可用存储类,请运行 kubectl get sc

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mypvc
      annotations:
        volume.beta.kubernetes.io/storage-class: "ibmc-file-bronze"
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 20Gi
    
  3. 创建 PVC。

    kubectl apply -f mypvc.yaml
    
  4. 在部署 .yaml 文件中,添加 init 容器。 包含您先前检索到的 UID 和 GID。

    initContainers:
    - name: initcontainer # Or replace the name
      image: alpine:latest
      command: ["/bin/sh", "-c"]
      args:
        - chown <UID>:<GID> /mount; # Replace UID and GID with values from the Dockerfile
      volumeMounts:
      - name: volume # Or you can replace with any name
        mountPath: /mount # Must match the mount path in the args line
    

    查看以下示例 Jenkins 部署。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-pod
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: jenkins      
      template:
        metadata:
          labels:
            app: jenkins
        spec:
          containers:
          - name: jenkins
            image: jenkins
            volumeMounts:
            - mountPath: /var/jenkins_home
              name: volume
          volumes:
          - name: volume
            persistentVolumeClaim:
              claimName: mypvc
          initContainers:
          - name: permissionsfix
            image: alpine:latest
            command: ["/bin/sh", "-c"]
            args:
              - chown 1000:1000 /mount;
            volumeMounts:
            - name: volume
              mountPath: /mount
    
  5. 创建 pod 并将 PVC 安装到该 pod。

    kubectl apply -f my-pod.yaml
    
  6. 验证卷是否已成功安装到 pod。 记下 pod 名称和 Containers/Mounts 路径。

    kubectl describe pod <my-pod>
    

    示例输出

    Name:       mypod-123456789
    Namespace:    default
    ...
    Init Containers:
    ...
    Mounts:
        /mount from volume (rw)
        /var/run/secrets/kubernetes.io/serviceaccount from default-token-cp9f0 (ro)
    ...
    Containers:
        jenkins:
        Container ID:
        Image:        jenkins
        Image ID:
        Port:          <none>
        State:        Waiting
            Reason:        PodInitializing
        Ready:        False
        Restart Count:    0
        Environment:    <none>
        Mounts:
            /var/jenkins_home from volume (rw)
            /var/run/secrets/kubernetes.io/serviceaccount from default-token-cp9f0 (ro)
    ...
    Volumes:
        myvol:
        Type:    PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
        ClaimName:    mypvc
        ReadOnly:      false
    
    
  7. 使用先前记下的 pod 名称登录到 pod。

    kubectl exec -it <my-pod-123456789> /bin/bash
    
  8. 验证容器安装路径的许可权。 在示例中,安装路径为 /var/jenkins_home

    ls -ln /var/jenkins_home
    

    示例输出

    jenkins@mypod-123456789:/$ ls -ln /var/jenkins_home
    total 12
    -rw-r--r-- 1 1000 1000  102 Mar  9 19:58 copy_reference_file.log
    drwxr-xr-x 2 1000 1000 4096 Mar  9 19:58 init.groovy.d
    drwxr-xr-x 9 1000 1000 4096 Mar  9 20:16 war
    

    此输出显示 Dockerfile 中的 GID 和 UID(在此示例中为 10001000)拥有容器内的安装路径。