IBM Cloud Docs
非 root ユーザーが NFS ファイル・ストレージのマウント・パスを所有しているとアプリが失敗するのはなぜですか?

非 root ユーザーが NFS ファイル・ストレージのマウント・パスを所有しているとアプリが失敗するのはなぜですか?

クラシック・インフラストラクチャー

デプロイメントに NFS ストレージを追加した後に、コンテナーのデプロイメントが失敗します。 コンテナーのログを取得すると、以下のようなエラーが表示されることがあります。 ポッドが失敗し、再ロードが繰り返されます。

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

デフォルトでは、非 root ユーザーには、NFS 補助ストレージのボリューム・マウント・パスに対する書き込み権限がありません。 一部の一般的なアプリのイメージ (Jenkins や Nexus3 など) は、マウント・パスを所有する非 root ユーザーを Dockerfile に指定しています。

この Dockerfile からコンテナーを作成すると、マウント・パスに対する非 root ユーザーの権限が不十分なために、コンテナーの作成は失敗します。 書き込み権限を与えるには、マウントパスのパーミッションを変更する前に、一時的に非rootユーザーをrootユーザーグループに追加するようにDockerfileを修正するか、「init コンテナを使用する。

Helmチャートを使用してイメージをデプロイする場合は、Helmデプロイメントを編集して「init コンテナを使用するようにします。

デプロイメントに「init コンテナを含めると、Dockerfileで指定した非rootユーザに、コンテナ内のボリュームマウントパスの書き込み権限を与えることができます。

init コンテナは、アプリのコンテナが開始する前に開始する。 init コンテナは、コンテナ内にボリュームのマウントパスを作成し、マウントパスを正しい(ルートでない)ユーザーが所有するように変更し、終了する。 その後、マウント・パスに書き込む必要がある非 root ユーザーでアプリ・コンテナーが開始されます。 パスは既に非 root ユーザーによって所有されているため、マウント・パスへの書き込みは成功します。 init コンテナを使いたくない場合は、Dockerfileを修正して、NFSファイルストレージへの非rootユーザーアクセスを追加することができる。

始める前に:

init コンテナを使用して、非 root ユーザーにボリューム・マウント・パスへの書 き込み権限を与える

  1. アプリの Dockerfile を開き、ボリューム・マウント・パスに対する書き込み権限を付与するユーザーのユーザー ID (UID) とグループ ID (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 ストレージ・クラスを使用します。 利用可能なストレージクラスを確認するには、'oc 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 を作成します。

    oc 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. ポッドを作成して、PVC をポッドにマウントします。

    oc apply -f my-pod.yaml
    

    init コンテナは失敗しているか? Red Hat OpenShift では、制限されたセキュリティー・コンテキスト制約が設定されるため、chown: /opt/ibm-ucd/server/ext_lib: Operation not permitted などのエラーが発生する場合があります。 デプロイメントで、 操作を許可する SCC を使用chownしてから、もう一度試してください。

  6. ボリュームがポッドに正常にマウントされたことを確認します。 ポッド名と Containers/Mounts パスをメモします。

    oc 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. 前にメモしたポッド名を使用して、ポッドにログインします。

    oc 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) がコンテナー内部のマウント・パスを所有していることを示しています。