¿Por qué falla mi app cuando un usuario no root es propietario de la vía de acceso de montaje de almacenamiento de archivos NFS?
Solucionar problemas de montaje de NFS sin privilegios de root para el almacenamiento de archivos.
Infraestructura clásica
Después de añadir almacenamiento NFS a su despliegue, el despliegue de su contenedor falla. Al recuperar los registros del contenedor, podría ver errores como los siguientes. El pod falla y queda atascado en un ciclo de recarga.
write-permission
don't have required permission
can't create directory '/bitnami/mariadb/data': Permission denied
De forma predeterminada, los usuarios no root no tienen permiso de escritura en la vía de acceso de montaje de volumen para el almacenamiento respaldado por NFS. Algunas imágenes comunes de app, como por ejemplo Jenkins y Nexus3, especifican un usuario no root que posee la vía de acceso de montaje en Dockerfile.
Cuando se crea un contenedor desde este Dockerfile, la creación del contenedor falla debido a permisos insuficientes del usuario no root en la vía de acceso de montaje. Para conceder permisos de escritura, puede modificar el archivo Dockerfile
para añadir temporalmente al usuario no root al grupo de usuarios root antes de que cambie los permisos de la ruta de montaje, o bien utilizar un contenedor init.
Si utilizas un gráfico de Helm para implementar la imagen, edita la implementación de Helm para utilizar un contenedor init.
Al incluir un en init contenedor tu implementación, puedes otorgar a un usuario que no sea root, especificado en tu
Dockerfile, permisos de escritura para la ruta de montaje del volumen dentro del contenedor.
El contenedor init se inicia antes de que se inicie el contenedor de tu aplicación. El contenedor init crea la ruta de montaje del volumen dentro del propio contenedor, cambia la ruta de montaje para que sea propiedad
del usuario correcto (que no sea root) y se cierra. A continuación, se inicia el contenedor de la app con el usuario no root que debe escribir en la vía de acceso de montaje. Dado que la vía de acceso ya es propiedad del usuario no root, la
escritura en la vía de acceso de montaje se realiza correctamente. Si no quieres utilizar un init contenedor, puedes modificar el archivo Dockerfile para añadir acceso de usuario no root al almacenamiento de archivos NFS.
Antes de empezar:
- Acceda al clúster de Red Hat OpenShift.
- Elegir una restricción de contexto de seguridad (SCC) que permita a su despliegue realizar operaciones
chown.
Para utilizar un contenedor init con el fin de conceder a un usuario que no sea root permisos de escritura en la ruta de montaje del volumen:
-
Abra el Dockerfile para la app y obtenga el ID de usuario (UID) y el ID de grupo (GID) del usuario al que desea dar permiso de escritura en la vía de acceso de montaje del volumen. En el ejemplo de un Dockerfile de Jenkins, la información es la siguiente:
- UID:
1000 - GID:
1000
Dockerfile de ejemplo
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:
-
Añada almacenamiento persistente a la app creando una reclamación de volumen persistente (PVC). En este ejemplo se utiliza la clase de almacenamiento
ibmc-file-bronze. Para consultar las clases de almacenamiento disponibles, ejecuteoc 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 -
Cree la PVC.
oc apply -f mypvc.yaml -
En tu archivo
.yamlde implementación, añade elinitcontenedor. Incluya el UID y el GID que ha recuperado anteriormente.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 lineRevise el siguiente ejemplo de despliegue 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 -
Cree el pod y monte la PVC en el pod.
oc apply -f my-pod.yaml¿Se está fallando el contenedor
init? Debido a que Red Hat OpenShift establece restricciones de contexto de seguridad restringidas, es posible que vea un error comochown: /opt/ibm-ucd/server/ext_lib: Operation not permitted. Para el despliegue, utilice una SCC que permita operacioneschowne inténtelo de nuevo. -
Verifique que el volumen se ha montado correctamente en el pod. Anote el nombre de pod y la vía de acceso de Containers/Mounts.
oc describe pod <my-pod>Salida de ejemplo
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 -
Inicie la sesión en el pod utilizando el nombre de pod que ha anotado anteriormente.
oc exec -it <my-pod-123456789> /bin/bash -
Verifique los permisos de la vía de acceso de montaje del contenedor. En el ejemplo, la vía de acceso de montaje es
/var/jenkins_home.ls -ln /var/jenkins_homeSalida de ejemplo
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 warEsta salida muestra que el GID y el UID del Dockerfile (en este ejemplo,
1000y1000) poseen la vía de acceso de montaje dentro del contenedor.