非 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 ユーザーの権限が不十分なために、コンテナーの作成は失敗します。 書き込み権限を付与するには、Dockerfile を修正して、マウントパスの権限を変更する前に非rootユーザーを一時的にrootユーザーグループに追加するか、 init コンテナを使用することができます。
Helm チャートを使用してイメージをデプロイする場合は、 Helm のデプロイ設定を編集し、 init コンテナを使用するようにしてください。
デプロイメントに init コンテナを含める場合、Dockerfileで指定した非rootユーザーに対して、コンテナ内のボリュームマウントパスへの書き込み権限を付与することができます。
init コンテナは、アプリコンテナが起動する前に起動します。 init コンテナは、コンテナ内にボリュームのマウントパスを作成し、そのマウントパスの所有者を適切な(root以外の)ユーザーに変更してから、終了します。 その後、マウント・パスに書き込む必要がある非 root ユーザーでアプリ・コンテナーが開始されます。 パスは既に非 root ユーザーによって所有されているため、マウント・パスへの書き込みは成功します。 init コンテナを使用したくない場合は、Dockerfileを修正して、 NFS のファイルストレージへの非rootユーザーによるアクセス権を追加することができます。
始める前に:
- Red Hat OpenShift クラスターにアクセスします。
- デプロイメントで 操作を実行できるセキュリティー・コンテキスト制約 (SCC)
chownを選択します。
init コンテナを使用して、root以外のユーザーにボリュームのマウントパスへの書き込み権限を付与するには:
-
アプリの 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} ... - UID:
-
永続ボリューム請求 (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 -
PVC を作成します。
oc apply -f mypvc.yaml -
デプロイメントの
.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 -
ポッドを作成して、PVC をポッドにマウントします。
oc apply -f my-pod.yamlinitコンテナに障害が発生していますか? Red Hat OpenShift では、制限されたセキュリティー・コンテキスト制約が設定されるため、chown: /opt/ibm-ucd/server/ext_lib: Operation not permittedなどのエラーが発生する場合があります。 デプロイメントで、 操作を許可する SCC を使用chownしてから、もう一度試してください。 -
ボリュームがポッドに正常にマウントされたことを確認します。 ポッド名と 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 -
前にメモしたポッド名を使用して、ポッドにログインします。
oc exec -it <my-pod-123456789> /bin/bash -
コンテナーのマウント・パスの権限を確認します。 この例では、マウント・パスは
/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 (この例では
1000と1000) がコンテナー内部のマウント・パスを所有していることを示しています。