• Docker
  • [Resolu] Faire quelques verifications avant de lancer un conteneur docker

Salut,

Je voudrais lancer un conteneur docker uniquement après que certaines vérifications aient été faite (sur la machine, pas dans le conteneur lui même - une des vérifications est l'existence d'un point de montage), mais j'ai du mal à trouver comment.
J'ai cherché un peu du coté de wait mais c'est une vérification qui est faite après le lancement du conteneur, afin de retarder le lancement du point d’entrée (entrypoint) jusqu’à ce que des prérequis soient atteints. Ce qui m’intéresse c'est en quelque sorte de lancer les vérifications (un script) qui à la fin lancera le conteneur. L’idéal serait de pouvoir le faire directement dans le fichier de conf de docker-compose.
Sinon, je pensais aussi désactiver le service docker et le lancer à partir du script une fois que les vérifications sont OK, mais du coup ça impacterait tous les conteneurs et je ne cherche à faire les vérifications que pour un seul conteneur (les autres peuvent se lancer au démarrage sans problème).
Sinon, 3eme scenario, désactiver le lancement automatique du conteneur dans docker-compose (pas regardé encore si c'est possible) et le lancer à partir du script quand les prérequis sont atteints.
Vous feriez comment?
Merci de me prévenir si ce n'est pas clair, je reformulerais.

  • @Merrick
    Merci pour les suggestions. En cherchant plus, je me suis rendu compte que le problème pouvait être résolu beaucoup plus simplement et sans nécessiter un autre conteneur que celui pour lequel il est nécessaire de faire les vérifications.

    Il faut tout simplement remplacer le point d’entrée du conteneur par un point d’entrée invoquant le script de vérification puis le point d’entrée d'origine.
    Du coup, ça donne ça :
    Dans le docker-compose.yml il faut préciser (/config est un volume partage entre l’hôte et le conteneur) :

    entrypoint: bash -c '/config/wait-for-mount.sh && /init'
    restart: unless-stopped

    Avec dans ce cas "/init" comme point d’entrée d'origine (ça se trouve dans le dockerfile du conteneur disponible sur le DockerHub) et "/config/wait-for-mount.sh" mon script qui ressemble à ça :

    #!/bin/bash
    # wait-for-mount.sh
    
    sleep 10
    
    [ -d "/mnt/complet/Films" ] || exit 1
    [ -d "/mnt/incomplet/Films" ] || exit 1
    

    Et puis c'est tout.
    Donc si un des 2 points de montage NFS n'est pas disponible au lancement du conteneur, celui-ci est arrêté (exit 1) et sera relancé... ceci jusqu’à ce que les points de montage NFS soient disponible et que le "/init" d'origine prenne la main.

    Simple, rapide et fiable (testé à plusieurs reprises).

    Merci pour les suggestions car c'est comme ça que je suis tombé sur cette solution.

Hello, si ce conteneur est le seul à avoir besoin de condition, tu peux créer un fichier docker-compose dédié et faire un boucle if qui test ton point de montage, si le répertoire est bien monté (oO) tu lances ton docker-compose
#!/bin/bash
myfile=/path/to/docker-compose.yml
if [ -d "/path/to/dir" ]
then
docker-compose -f $myfile
else
exit 1
fi

    sizeur
    Effectivement, j'avais pas pense à ça. Mais du coup dans mon fichier docker-compose dédié, je devrais retirer le paramètre "restart : always" pour éviter que le conteneur ne soit lancé au démarrage de docker... sauf que du coup, en cas de pépin, le conteneur n'est pas automatiquement relancé et je devrais donc avoir un script qui tourne en permanence (ou lancé par cron) pour vérifier que le conteneur est bien démarré.
    Ça ce tente... j'aurais bien évidemment préféré un paramètre à fournir dans le docker-compose qui lance mon script et attente une sortie 0 pour lancer le conteneur, mais bon on ne peut pas tout avoir 🙂

    C'est quoi le type de pépin ? Un montage rClone qui se fait la malle et tu veux par exemple relancer ton ruTorrent que si le montage est effectif ? Donc soit en cas de plantage de ton rClone soit en cas de reboot de la machine ?

    Si c'est ça en se basant sur le BASH plus haut et pour faire vite j'aurais juste ajouté un BASH en cron (* * * * *) qui check si le container est lancé et si "non" alors il lance le script cité.

    #!/bin/bash
    container="rutorrent"
    
    if docker ps | grep -q "$container"
    then 
        echo "ok"
        break
    else
        echo "on relance"
        ./tonscriptderelance.sh
        exit 1
    fi

      Aerya
      Il s'agit d'un montage NFS sur la VM necessaire au conteneur (Transmission) et il est deja arrive qu'au demarrage de la VM, le conteneur soit lance avant que le montage NFS n'ait lieu, du coup Transmission n'avait pas acces aux fichiers. Et je penses aussi a la situation ou le serveur NFS n'est pas disponible (a cause d'un probleme technique par exemple) lors du demarrage de la VM.
      J'esperais a une solution directement integree dans le docker-compose permettant de lancer mon script avant de lancer le conteneur, mais je vais mettre ca en place directement avec mon script qui lancera le docker-compose.
      Merci pour les suggestions.

      A ma connaissance ça n'existe pas dans docker-compose en effet.

      Alors, ta question me turlupine depuis quelques jours, et j'ai peut être un début de solution 😀

      tu fais un Dockerfile, qui checke si le nfs est monté, si oui, il reste lancé (tu fais une boucle qui ne fait rien), sinon, il attend X secondes et sort en erreur, et tu crée ton container (par exemple "verif")

      Dans ton docker-compose, tu lances le docker "verif" en restart; always, et tu mets ton container secondaire en depends on: verif
      Comme ça le secondaire ne devrait pas se lancer tant que "verif" n'est pas up.

        Merrick
        Ouaaaaaaah, l’idée de génie 🙂
        Je vais tenter ça, même si jusque là je n'ai jamais fais de Dockerfile, mais du coup c'est 2 fois plus intéressant.
        Je reviendrais poster ici quand j'aurais eu le temps de tester (pas simple ces jours-ci avec le boulot, mais on verra).
        Merci en tout cas pour l’idée.

        J'ai eu un peu de temps pour tester, c'est prometteur mais pas encore ça... j'explique.

        J'ai créé 2 conteneurs grâce à 2 dockerfiles. Le premier qu'on va appeler "check" permet de faire les vérifications (présence de 2 dossiers sur la machine hôte) et pour celui-la j'aurais un healthcheck mis en place pour connaître son état. Le second qu'on va appeler "principal" est mon conteneur principal qui fait tourner le service dont j'ai besoin (pour le test c'est un conteneur simple avec un sleep 3600).

        Dockerfile "check" :

        FROM debian:latest
        
        RUN mkdir /config && mkdir /mnt/complet && mkdir /mnt/incomplet
        
        WORKDIR /config/
        
        VOLUME /config
        VOLUME /mnt/complet
        VOLUME /mnt/incomplet
        
        ENTRYPOINT /config/wait-for-mount.sh

        Dockerfile "principal" :

        FROM debian:latest
        
        ENTRYPOINT sleep 3600

        Docker-compose pour les 2 conteneurs :

        ---
        version: "2.1"
        services:
          check:
            image: check
            container_name: check
            volumes:
              - /home/user/docker/check/config:/config:ro
              - /mnt/complet:/mnt/complet:ro
              - /mnt/incomplet:/mnt/incomplet:ro
            restart: unless-stopped
            healthcheck:
              test: ["CMD-SHELL", "ls -l /tmp/healthy"]
              interval: 30s
              timeout: 10s
              retries: 3
        
          principal:
            image: principal
            container_name: principal
            depends_on:
              check:
                condition: service_healthy

        Le script utilisé en entrypoint pour le conteneur "check" (wait-for-mount.sh) :

        #!/bin/bash
        # wait-for-mount.sh
        
        sleep 10
        
        while true
        do
        	[ -d "/mnt/complet/Films" ] || exit 1
        	[ -d "/mnt/incomplet/Films" ] || exit 1
        done
        
        if [ ! -f "/tmp/healthy" ]
        then
        	touch /tmp/healthy
        fi
        
        sleep 15
        done

        Donc si on résume :

        • mon conteneur "principal" dépend de l’état du conteneur "check" (celui-ci doit être "healthy")
        • mon conteneur "check", lorsqu'il est lancé, vérifie la présence de 2 dossiers qui doivent exister lorsque les partages NFS sont montés dans /mnt/complet/ et /mnt/incomplet/
        • si 1 des dossiers n'existe pas alors le conteneur "check" est redémarré (exit 1)
        • si tout est bon, alors le script crée un fichier "/tmp/healthy" dans le conteneur qui permet lors du healthcheck de dire que tout va bien, ce qui ensuite lance le conteneur "principal"

        J'ai fais quelques tests et ça à l'air de marcher à première vue. MAIS, parce que s'il n'y avait pas de "mais", je n'aurais pas écris ce gros pâté 🙂
        Si mon conteneur "check" devient "unhealthy" à cause d'un des dossiers qui n'existe plus, le conteneur "principal" continue de tourner comme si de rien n’était. J'en déduis que le "depend_on" n'est effectivement pris en compte que lors du lancement du conteneur "principal" et plus du tout après. Est-ce correct? Si c'est ça, c'est embêtant, parce que je voulais continuer à vérifier la présence des 2 dossiers durant le fonctionnement des 2 conteneurs pour, en cas de problème sur l'un des dossiers, que le conteneur "check" soit redémarré (grâce au "exit 1" dans le script) et que le conteneur "principal" soit arrêté (par Docker, puis-ce que le conteneur "check" est "unhealthy") jusqu’à ce que le conteneur "check" redevienne "healthy". Dans le cas où le healthcheck n'est vérifié qu'au lancement, je n'ai plus aucune utilité pour le conteneur "check" ensuite (il pourrait donc arrêter de tourner)...
        Mes suppositions sont-elles bonnes? Avez-vous une autre vision ou une autre idée pour que le "depend_on" soit pris en compte tout au long du cycle de vie du conteneur "principal"?

        Ah oui, le depends on ne sert qu'au lancement. Je vais voir si je peux trouver une autre méthode.

        Alors... idée à la va vite :
        tu mappes un lecteur pour ton "check" pour que le /tmp/healthy soit lisible depuis l'autre conteneur
        Sur le container principal, tu rajoute un healthcheck qui vérifie que ce fichier existe, et tu utilises une solution de restart des containers unhealthy (par exemple https://github.com/willfarrell/docker-autoheal)

        @Merrick
        Merci pour les suggestions. En cherchant plus, je me suis rendu compte que le problème pouvait être résolu beaucoup plus simplement et sans nécessiter un autre conteneur que celui pour lequel il est nécessaire de faire les vérifications.

        Il faut tout simplement remplacer le point d’entrée du conteneur par un point d’entrée invoquant le script de vérification puis le point d’entrée d'origine.
        Du coup, ça donne ça :
        Dans le docker-compose.yml il faut préciser (/config est un volume partage entre l’hôte et le conteneur) :

        entrypoint: bash -c '/config/wait-for-mount.sh && /init'
        restart: unless-stopped

        Avec dans ce cas "/init" comme point d’entrée d'origine (ça se trouve dans le dockerfile du conteneur disponible sur le DockerHub) et "/config/wait-for-mount.sh" mon script qui ressemble à ça :

        #!/bin/bash
        # wait-for-mount.sh
        
        sleep 10
        
        [ -d "/mnt/complet/Films" ] || exit 1
        [ -d "/mnt/incomplet/Films" ] || exit 1
        

        Et puis c'est tout.
        Donc si un des 2 points de montage NFS n'est pas disponible au lancement du conteneur, celui-ci est arrêté (exit 1) et sera relancé... ceci jusqu’à ce que les points de montage NFS soient disponible et que le "/init" d'origine prenne la main.

        Simple, rapide et fiable (testé à plusieurs reprises).

        Merci pour les suggestions car c'est comme ça que je suis tombé sur cette solution.

        Malakai a renommé le titre en [Resolu] Faire quelques verifications avant de lancer un conteneur docker.

        Ah oui, effectivement beaucoup plus simple, et je retiens, ça peut servir 🙂

        Répondre…