web-dev-qa-db-fra.com

Exécuter la commande dans Docker Container uniquement au premier démarrage

J'ai une image Docker qui utilise un script (/bin/bash /init.sh) comme Entrypoint. Je voudrais exécuter ce script uniquement au premier démarrage d'un conteneur. Il doit être omis lorsque les conteneurs sont redémarrés ou redémarrés après un crash du démon docker.

Y at-il un moyen de faire cela avec docker lui-même, ou le faire s’il doit implémenter une sorte de vérification dans le script?

17
john.dough

Le point d'entrée d'un conteneur de menu fixe indique au démon de menu ce qu'il doit exécuter lorsque vous souhaitez "exécuter" ce conteneur spécifique. Posons les questions suivantes: "Que doit contenir le conteneur lorsqu’il est démarré une deuxième fois?" ou "ce que le conteneur doit exécuter après avoir été redémarré?"

Probablement, ce que vous faites est de suivre la même approche que vous utilisez pour les mécanismes de provisioning «old school». Votre script "installe" les scripts nécessaires et vous exécuterez votre application en tant que service systemd/upstart, n'est-ce pas? Si vous faites cela, vous devriez changer cela en une définition plus "dockerisée". 

Le point d'entrée de ce conteneur doit être un script qui lance réellement votre application au lieu de tout configurer. Supposons que Java soit installé pour pouvoir exécuter votre application. Ainsi, dans le fichier docker, vous configurez le conteneur de base pour installer tout ce dont vous avez besoin, par exemple:

FROM Alpine:Edge

RUN apk --update upgrade && apk add openjdk8-jre-base
RUN mkdir -p /opt/your_app/ && adduser -HD userapp

ADD target/your_app.jar /opt/your_app/your-app.jar
ADD scripts/init.sh /opt/your_app/init.sh

USER userapp
EXPOSE 8081

CMD ["/bin/bash", "/opt/your_app/init.sh"]

Nos conteneurs, dans l'entreprise pour laquelle je travaille, avant d'exécuter l'application dans le script init.sh, ils extraient les configs de consul (au lieu de fournir un point de montage et de placer les configs dans l'hôte ou de les incorporer dans le conteneur). Le script ressemblera à quelque chose comme:

#!/bin/bash

echo "Downloading config from consul..."
confd -onetime -backend consul -node $CONSUL_URL -prefix /cfgs/$CONSUL_APP/$CONSUL_ENV_NAME
echo "Launching your-app..."
Java -jar /opt/your_app/your-app.jar

Un conseil que je peux vous donner est (compte tenu de ma très courte expérience de travail avec des conteneurs) de traiter vos conteneurs comme s’ils étaient sans état une fois qu’ils sont provisionnés (toutes les commandes que vous exécutez avant le point d’entrée).

10
Samuel García

J'ai eu le même problème, voici une procédure simple (c'est-à-dire une solution de contournement) pour le résoudre:

Étape 1:

Créez un script "myStartupScript.sh" contenant ce code:

CONTAINER_ALREADY_STARTED="CONTAINER_ALREADY_STARTED_PLACEHOLDER"
if [ ! -e $CONTAINER_ALREADY_STARTED ]; then
    touch $CONTAINER_ALREADY_STARTED
    echo "-- First container startup --"
    # YOUR_JUST_ONCE_LOGIC_HERE
else
    echo "-- Not first container startup --"
fi

Étape 2:

Remplacez la ligne "# YOUR_JUST_ONCE_LOGIC_HERE" par le code que vous souhaitez exécuter uniquement au premier démarrage du conteneur.

Étape 3:

Définissez le script comme point d’entrée de votre fichier Docker:

ENTRYPOINT ["/myStartupScript.sh"]

En résumé, la logique est assez simple, il vérifie si un fichier spécifique est présent dans le système de fichiers; sinon, il le crée et exécute votre code juste-une fois. Au prochain démarrage de votre conteneur, le fichier est dans le système de fichiers et le code n'est donc pas exécuté.

6
Francesco Cina

Je devais faire cela et j'ai fini par créer un docker run -d qui vient de créer un conteneur détaché et de démarrer bash (en arrière-plan) suivi d'un docker exec, qui a effectué l'initialisation nécessaire. voici un exemple

docker run -itd --name=myContainer myImage /bin/bash
docker exec -it myContainer /bin/bash -c /init.sh

Maintenant, quand je redémarre mon conteneur, je peux juste faire

docker start myContainer
docker attach myContainer

Cela peut ne pas être idéal mais fonctionne bien pour moi.

2
Vijay Baiyya

Je voulais faire la même chose sur le conteneur Windows. Cela peut être réalisé à l'aide du planificateur de tâches sous Windows. L'équivalent Linux pour le planificateur de tâches est cron. Vous pouvez l'utiliser dans votre cas. Pour ce faire, éditez le fichier docker et ajoutez la ligne suivante à la fin. 

WORKDIR /app 
COPY myTask.ps1 . 
RUN schtasks /Create /TN myTask /SC ONSTART /TR "c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\app\myTask.ps1" /ru SYSTEM

This Crée une tâche avec le nom myTask l’exécute ONSTART et sa tâche consiste à exécuter un script powershell placé dans "c:\app\myTask.ps1".

Ce script myTask.ps1 effectuera l'initialisation nécessaire au démarrage du conteneur. Assurez-vous de supprimer cette tâche une fois qu'elle a été exécutée avec succès, sinon elle sera exécutée à chaque démarrage. Pour le supprimer, vous pouvez utiliser la commande suivante à la fin du script myTask.ps1.

schtasks /Delete /TN myTask /F
1
Umer Javaid