非 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ユーザーアクセスを追加することができる。
始める前に:
- 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.yaml
init
コンテナは失敗しているか? 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
) がコンテナー内部のマウント・パスを所有していることを示しています。