IBM Cloud Docs
Pourquoi mon application échoue-t-elle si un utilisateur non root détient le chemin de montage du stockage de fichiers NFS ?

Pourquoi mon application échoue-t-elle si un utilisateur non root détient le chemin de montage du stockage de fichiers NFS ?

Infrastructure classique

Une fois que vous ajoutez du stockage NFS dans votre déploiement, le conteneur ne parvient pas à se déployer. Lorsque vous extrayez les journaux de votre conteneur, vous pourrez voir les messages d'erreur suivants. On observer l'échec du pod qui est bloqué dans un cycle de rechargement.

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

Par défaut, les utilisateurs non root n'ont pas le droit d'écriture sur le chemin de montage du volume pour le stockage sauvegardé par NFS. Certaines images d'application courantes, telles que Jenkins et Nexus3, spécifient un utilisateur non root qui est le propriétaire du chemin de montage dans le fichier Dockerfile.

Lorsque vous créez un conteneur à partir de ce fichier Dockerfile, la création échoue car l'utilisateur non root ne dispose pas des droits nécessaires pour accéder au chemin de montage. Pour accorder l'autorisation d'écriture, vous pouvez modifier le fichier Docker pour ajouter temporairement l'utilisateur non root au groupe d'utilisateurs root avant de modifier les autorisations du chemin de montage, ou utiliser un conteneur 'init

Si vous utilisez un diagramme Helm pour déployer l'image, modifiez le déploiement Helm pour utiliser un conteneur 'init

Lorsque vous incluez un conteneur 'init dans votre déploiement, vous pouvez donner à un utilisateur non root spécifié dans votre Dockerfile des droits d'écriture sur le chemin de montage du volume à l'intérieur du conteneur.

Le conteneur 'init démarre avant le conteneur de votre application. Le conteneur " init crée le chemin de montage du volume à l'intérieur du conteneur, modifie le chemin de montage pour qu'il appartienne à l'utilisateur correct (non root) et se ferme. Ensuite, le conteneur de votre application avec l'utilisateur non root qui doit écrire dans le chemin de montage démarre. Comme le chemin est déjà détenu par l'utilisateur non root, l'écriture dans le chemin de montage aboutit. Si vous ne souhaitez pas utiliser un conteneur 'init, vous pouvez modifier le fichier Docker pour ajouter l'accès d'un utilisateur non root au stockage de fichiers NFS.

Avant de commencer :

Pour utiliser un conteneur 'init afin de donner à un utilisateur non root des droits d'écriture sur le chemin de montage du volume :

  1. Ouvrez le fichier Dockerfile de votre application et récupérez l'ID utilisateur (UID) et l'ID du groupe (GID) de l'utilisateur auquel vous voulez accorder les droits en écriture sur le chemin de montage du volume. Dans l'exemple d'un fichier Dockerfile Jenkins, les informations sont :

    • ID utilisateur :1000
    • ID groupe :1000

    Exemple de document 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. Ajoutez du stockage persistant à votre application en créant une réservation de volume persistant (PVC). Cet exemple utilise la classe de stockage ibmc-file-bronze. Pour passer en revue les classes de stockage disponibles, exécutez '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. Créez le PVC (circuit virtuel permanent).

    oc apply -f mypvc.yaml
    
  4. Dans votre fichier de déploiement " .yaml, ajoutez le conteneur " init Insérez les identificateurs UID et GID que vous avez récupérés précédemment.

    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
    

    Consultez l'exemple de déploiement de Jenkins suivant.

    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. Créez le pod et montez la PVC dessus.

    oc apply -f my-pod.yaml
    

    Le conteneur " init est-il défaillant ? Etant donné qu'Red Hat OpenShift définit des contraintes de contexte de sécurité restreintes, vous pouvez obtenir une erreur de ce type : chown: /opt/ibm-ucd/server/ext_lib: Operation not permitted. Pour votre déploiement, utilisez une contrainte de contexte de sécurité qui autorise des opérations chown et renouvelez votre demande.

  6. Vérifiez que le montage du volume sur votre pod a réussi. Notez le nom du pod et le chemin Containers/Mounts.

    oc describe pod <my-pod>
    

    Exemple de sortie

    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. Connectez-vous au pod en utilisant le nom du pod que vous avez noté précédemment.

    oc exec -it <my-pod-123456789> /bin/bash
    
  8. Vérifiez les droits octroyés pour le chemin de montage de votre conteneur. Dans l'exemple, le chemin de montage est /var/jenkins_home.

    ls -ln /var/jenkins_home
    

    Exemple de sortie

    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
    

    Cette sortie montre que les identificateurs GID et UID de votre fichier Dockerfile (dans cet exemple, 1000 et 1000) sont propriétaires du chemin de montage à l'intérieur du conteneur.