Utilisation de Docker (2/2)
Des images paramétrées
Nous avons vu, dans la séances précédentes, que l'image MySQL est paramétrée (MYSQL_DATABASE par exemple). Nous allons faire de même pour notre application Spring-Boot avec la directive ENV :
## Créer un répertoire mkdir myapp-env ## Préparer le WAR dans le répertoire wget http://tinyurl.com/jlmassat2/cca/spring-app.war mv -v spring-app.war myapp-env ## Créer le script de démarrage cat > myapp-env/start.sh <<FIN echo "Log \$MYAPP_NAME in \$MYAPP_LOG" java -jar spring-app.war &> \$MYAPP_LOG FIN ## Créer le dockerfile cat > myapp-env/Dockerfile <<FIN FROM my-java:latest LABEL desc="My SpringBoot App with Env" WORKDIR /app COPY spring-app.war start.sh /app/ ENV MYAPP_LOG="/var/tmp/myapp.log" ENV MYAPP_NAME="myapp" EXPOSE 8081 ENTRYPOINT ["/bin/bash", "/app/start.sh"] FIN ## Construire une image docker build -t myapp-env:latest myapp-env docker images
## Tester en mode démon
docker run --name myapp-env -dt -p 9100:8081 \
-e MYAPP_NAME=moviesapp \
-e MYAPP_LOG=/tmp/moviesapp.log \
myapp-env:latest
## Vérifier le nouveau fichier de trace
sleep 10s
docker exec myapp-env cat /tmp/moviesapp.log | head
## Stopper
docker stop myapp-env
docker rm myapp-env
Surveiller les conteneurs
Dans les exercices précédents nous avons surveillé le bon lancement d'un conteneur avec le script wait-for-it. C'est un bricolage (bien pratique) mais il est préférable que le conteneur surveille et déclare lui-meme sont état de santé. Commençons par ajouter une clause HEALTHCHECK au dockerfile et reconstruisons l'image.
## Ajouter au dockerfile cat >> myapp-env/Dockerfile <<FIN HEALTHCHECK --interval=4s --timeout=3s --retries=100 \ CMD curl -f http://localhost:8081/movies/ || exit 1 FIN ## Reconstruire une image docker image rm myapp-env:latest docker build -t myapp-env:latest myapp-env docker images
## Tester en mode démon
docker run --name myapp-env -dt -p 9100:8081 \
-e MYAPP_NAME=moviesapp \
-e MYAPP_LOG=/tmp/moviesapp.log \
myapp-env:latest
## Attendre que le conteneur soit healthy - a la main
until [ "$status" = healthy ]; do
echo waiting; sleep 2s
status="$(docker inspect --format='{{.State.Health.Status}}' myapp-env)"
done
## Un outil pour attendre
wget https://github.com/jordyv/wait-for-healthy-container/raw/refs/heads/master/wait-for-healthy-container.sh
mv -v wait-for-healthy-container.sh /usr/bin/wait-for-healthy-container
chmod a+x /usr/bin/wait-for-healthy-container
## Attendre que le conteneur soit healthy - plus simple
wait-for-healthy-container myapp-env
## Stopper
docker stop myapp-env
docker rm myapp-env
Les volumes
Nous avons stocké les traces, mais quand le conteneur s'arrête, les données sont perdues. Nous allons prévoir un volume de stockage ( docker volume) afin d'externaliser les traces et ainsi les conserver.
## Créer un volume partagé
docker volume create my-logs
ls -l /var/lib/docker/volumes/my-logs
## Lister les volumes
docker volume ls
## Tester en mode démon -- avec le volume
docker run --name myapp-env -dt -p 9100:8081 \
-v my-logs:/mnt \
-e MYAPP_NAME=moviesapp \
-e MYAPP_LOG=/mnt/moviesapp.log \
myapp-env:latest
## Attendre que le conteneur soit healthy
wait-for-healthy-container myapp-env
## Verifier localement les logs
tail -5 < /var/lib/docker/volumes/my-logs/_data/moviesapp.log
## La même chose en docker
docker run --name my-cat -v my-logs:/mnt alpine cat /mnt/moviesapp.log |
tail -5
## Stopper
docker stop myapp-env my-cat
docker rm myapp-env my-cat
## Supprimer le volume
docker volume rm my-logs
Démarrage automatique
Il est absolument nécessaire de pouvoir faire démarrer automatiquement un conteneur (pour que le service soit opérationnel). Nous pourrions un service (au sens de systemd, mais la solution ci-dessous est plus simple :
## Redémarrage automatique (si le conteneur est déjà lancé) docker update --restart always myapp-env ## ou bien lancement avec redémarrage automatique docker run -d --restart always myapp-env
Limiter les ressources
Dans docker, nous pouvons restreindre les ressources allouées à un conteneur (plus d'informations). Dans l'exemple ci-dessous, nous limitons la CPU (option --cpus) :
## Boucle consommatrice de CPU - à régler pour 5 secondes LOOP='for((x=0;x<5000000;x++)); do true; done' ## Boucle dans la machine invitée time bash -c "$LOOP" ## Boucle dans docker time docker run -it almalinux bash -c "$LOOP" ## Boucle avec 1/2 CPU time docker run -it --cpus="0.5" almalinux bash -c "$LOOP"
## Boucle consommatrice de CPU - à régler pour 5 secondes
LOOP='for((x=0;x<5000000;x++)); do true; done'
## Deux boucles en //
DLOOP="{ $LOOP &} ; { $LOOP &}; wait; wait; echo fini"
## Deux boucles avec 1 CPU
time docker run -it --cpus="1.0" almalinux bash -c "$DLOOP"
## Deux boucles avec 1,5 CPU
time docker run -it --cpus="1.5" almalinux bash -c "$DLOOP"