Warum schlägt meine App fehl, wenn ein Benutzer ohne Rootberechtigung den Anhängepfad für den NFS-Dateispeicher besitzt?
Fehlerbehebung bei Problemen mit dem Einbinden von Nicht-Root- NFS en für die Dateispeicherung.
Klassische Infrastruktur
Nach dem Hinzufügen von NFS-Speicher zu Ihrer Bereitstellung schlägt die Bereitstellung Ihres Containers fehl. Wenn Sie die Protokolle für Ihren Container abrufen, werden möglicherweise Fehler wie die folgenden angezeigt. Der Pod schlägt fehl und bleibt in einer Neuladeschleife stecken.
write-permission
don't have required permission
can't create directory '/bitnami/mariadb/data': Permission denied
Standardmäßig haben Benutzer ohne Rootberechtigung keinen Schreibzugriff auf den Datenträgermountpfad für NFS-gestützten Speicher. Einige allgemeine App-Images, wie z. B. Jenkins und Nexus3, geben einen Benutzer ohne Rootberechtigung an, der Eigner des Mountpfads in der Dockerfile ist.
Wenn Sie einen Container aus dieser Dockerfile erstellen, schlägt die Erstellung des Containers aufgrund unzureichender Berechtigungen für den Benutzer ohne Rootberechtigung auf dem Mountpfad fehl. Um Schreibrechte zu gewähren, können Sie die
Dockerfile-Datei so anpassen, dass der Nicht-Root-Benutzer vorübergehend zur Root-Benutzergruppe hinzugefügt wird, bevor die Berechtigungen für den Einhängepfad geändert werden, oder Sie können einen init Container verwenden.
Wenn Sie zur Bereitstellung des Images ein Helm-Diagramm verwenden, bearbeiten Sie die Bereitstellung unter Helm so, dass ein Container init verwendet wird.
Wenn Sie einen Container init in Ihre Bereitstellung einbinden, können Sie einem in Ihrer Dockerfile angegebenen Nicht-Root-Benutzer
Schreibrechte für den Volume-Mount-Pfad innerhalb des Containers erteilen.
Der Container init wird gestartet, bevor Ihr App-Container gestartet wird. Der Container init erstellt den Einhängepfad für das Volume innerhalb des Containers, ändert den Einhängepfad so, dass er dem richtigen (nicht-root-)Benutzer
gehört, und schließt ihn. Anschließend wird Ihr App-Container mit dem Benutzer ohne Rootberechtigung gestartet, der in den Mountpfad schreiben muss. Da der Benutzer ohne Rootberechtigung bereits Eigner des Pfads ist, ist das Schreiben in den
Mountpfad erfolgreich. Wenn Sie keinen Container init verwenden möchten, können Sie die Dockerfile-Datei so anpassen, dass der Zugriff auf den Dateispeicher NFS auch für Nicht-Root-Benutzer möglich ist.
Vorbereitende Schritte:
- Rufen Sie Ihren Red Hat OpenShift-Cluster auf.
- Wählen Sie eine Sicherheitskontexteinschränkung aus, die die Ausführung von Operationen
chownin Ihrer Bereitstellung zulässt.
So verwenden Sie einen Container init, um einem Nicht-Root-Benutzer Schreibrechte für den Mount-Pfad des Volumes zu erteilen:
-
Öffnen Sie die Dockerfile für Ihre App und rufen Sie die Benutzer-ID (UID) und die Benutzer-ID (GID) von dem Benutzer ab, dem Sie Schreibzugriff auf den Datenträgermountpfad erteilen möchten. Im Beispiel einer Jenkins-Dockerfile lautet die Information:
- Benutzer-ID:
1000 - Gruppen-ID:
1000
Beispiel-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} ... - Benutzer-ID:
-
Fügen Sie persistenten Speicher zu Ihrer App hinzu, indem Sie einen PVC (Persistent Volume Claim) erstellen. Dieses Beispiel verwendet die Speicherklasse
ibmc-file-bronze. Um die verfügbaren Speicherklassen anzuzeigen, führen Sie folgenden Befehl aus: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 -
Erstellen Sie den PVC.
oc apply -f mypvc.yaml -
Fügen Sie in Ihrer Bereitstellungsdatei
.yamlden Containerinithinzu. Beziehen Sie die UID und GID ein, die Sie zuvor abgerufen haben.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 lineSehen Sie sich das folgende Beispiel einer Jenkins-Bereitstellung an.
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 -
Erstellen Sie den Pod und hängen Sie den PVC an Ihren Pod an.
oc apply -f my-pod.yamlWeist der Container
initeine Störung auf? Da Red Hat OpenShift Sicherheitskontexteinschränkungen festlegt, werden möglicherweise Fehler wie z. B.chown: /opt/ibm-ucd/server/ext_lib: Operation not permittedangezeigt. Verwenden Sie für Ihre Bereitstellung eine Sicherheitskontexteinschränkung, diechown-Operationen zulässt, und wiederholen Sie den Versuch. -
Überprüfen Sie, ob der Datenträger erfolgreich an Ihren Pod angehängt wurde. Notieren Sie den Namen des Pod und den Containers/Mounts-Pfad.
oc describe pod <my-pod>Beispielausgabe
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 -
Melden Sie sich beim Pod an, indem Sie den Podnamen verwenden, den Sie zuvor notiert haben.
oc exec -it <my-pod-123456789> /bin/bash -
Überprüfen Sie die Berechtigungen des Mountpfads Ihres Containers. In dem Beispiel ist der Mountpfad
/var/jenkins_home.ls -ln /var/jenkins_homeBeispielausgabe
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 warDiese Ausgabe zeigt, dass die GID und UID von Ihrer Dockerfile (in diesem Beispiel
1000und1000) Eigner des Mountpfads innerhalb des Containers sind.