Cet article fait suite à Tests End-to-End avec Docker.

Cette 2 ième partie montre comment construire ses propres images avec les Dockerfile  au lieu de provisionner des images officielles par commandes bash.

L’exemple complet est disponible sur github (branche e2e-dockerfile).

Voir le README pour lancer le test E2E, l’exemple a été testé sous Mac OS avec Docker for Mac (l’installation de docker machine n’est plus nécessaire).


Explication de ce qui change par rapport à l’approche sans Dockerfile phase par phase (build, pré-intégration, test, post-intégration)

Build

  •  Build maven et
  • Build images docker des repos mysql, batch et restapp, il faut lancer la commande docker build à la racine de chaque repo.
  • La commande build construit les images en exécutant le Dockerfile présent dans le contexte relatif au repo.
    • docker build -t mysql-sample:latest .
    • docker build -t springbatch-sample:latest .
    • docker build -t spring-boot-sample:latest .

Mysql Dockerfile (voir repo mysql-sample)

FROM mysql:latest

COPY functional-schema.sql /docker-entrypoint-initdb.d/
COPY technical-schema.sql /docker-entrypoint-initdb.d/
COPY healthcheck.sh /healthcheck.sh

EXPOSE 3306

HEALTHCHECK --interval=3s --retries=10 CMD /healthcheck.sh
  • Copie des schémas base de données technique Spring batch et fonctionnelle dans l’image docker à l’emplacement /docker-entrypoint-initdb.d
  • docker-entrypoint-initdb.d est un répertoire standard fourni par l’image officielle mysql (FROM mysql)
  • Les scripts copiés dans /docker-entrypoint-initdb.d sont exécutés au démarrage du container (docker run).
  • Copie du script healthcheck dans l’image
  • Exposition du port standard mysql aux autres containers
  • Déclaration du script healthchek à exécuter au démarrage du container
    • S’exécutera 10 fois maximum à intervalles de 3 secondes jusqu’au succès

Healthcheck mysql

set -e

echo "SELECT 1 FROM USER;" | mysql --user="root" --password="$MYSQL_ROOT_PASSWORD" functional > /dev/null
echo "SELECT 1 FROM BATCH_JOB_SEQ;" | mysql --user="root" --password="$MYSQL_ROOT_PASSWORD" technical > /dev/null

exit $?
  • Sortie du script avec code 0 si les requêtes de test des schémas sont exécutées avec succès.

Batch Dockerfile (voir repo springbatch-sample)

FROM java:8

COPY springbatch-sample/target/springbatch-sample*.jar /springbatch-sample.jar

ENTRYPOINT ["java","-Dbatch.properties.path=file:/properties/batch.properties",
"-Djob.name=alimentationJob","-jar",
"/springbatch-sample.jar","input.file.path=/input/alimentation.csv"]
  • Copie du package au format jar dans l’image docker
  • ENTRYPOINT décrit la commande à exécuter au démarrage du container

Restapp Dockerfile (voir repo spring-boot-sample)

FROM java:8

COPY target/spring-boot-sample*.jar /spring-boot-sample.jar
COPY healthcheck.sh /healthcheck.sh

EXPOSE 8080

HEALTHCHECK --interval=3s --timeout=3s --retries=10 CMD /healthcheck.sh

ENTRYPOINT bash -c "java -jar /spring-boot-sample.jar --spring.config.location=file:/properties/application.properties 2>&1 | tee /var/log/restapp.log"
  • Copie du package au format jar dans l’image docker
  • Copie du healthcheck dans l’image
  • Exposition du port 8080 aux autres containers
  • Déclaration du healthchek à exécuter au démarrage du container
    • curl sur le port 8080
  • ENTRYPOINT décrit la commande à exécuter au démarrage du container

Pré-intégration (voir script docker-run.sh)

  • Lancement container docker mysql-sample
  • Attente du succès du healthcheck mysql
  • Lancement container batch-sample
  • Lancement container spring-boot-sample
  • Attente du succès du healthcheck de la restapp

Script docker-run.sh

work=$1
e2e=$2

cd $work && rm -rf log && mkdir log

docker run --name mysqldb -d -e MYSQL_ROOT_PASSWORD=dba -p 3306:3306 mysql-sample

$e2e/pre-integration/wait/wait.sh mysqldb

docker run --rm  -v $work/configuration/properties:/properties -v $e2e/pre-integration/input:/input springbatch-sample > $work/log/batch.log	

docker run --name webapp -d -v $work/log/:/var/log -v $work/configuration/properties:/properties -p 8080:8080 spring-boot-sample

$e2e/pre-integration/wait/wait.sh webapp

Script wait.sh

while [ $(docker inspect --format='{{.State.Health.Status}}' $1) != "healthy" ];
 do sleep 1; echo -n ".";
done
  • Boucle d’attente sur la commande docker inspect
  • State.Health.Status correspond au path json à filtrer du résultat de la commande inspect
  • State.Health.Status est égal à « healthy » quand le résultat du script déclaré dans HEALTHCHECK est en succès

Test des ressources REST avec CURL

Post-intégration

  • Arrêt et suppression des containers docker
  • Suppressions des images
docker rmi springbatch-sample
docker stop webapp && docker rm webapp && docker rmi spring-boot-sample
docker stop mysqldb && docker rm mysqldb && docker rmi mysql-sample
  • Chaque rebuild d’image avec le même tag latest et la copie d’un jar « snapshot » différent va générer la présence d’une nouvelle image dans l’emplacement local des images (docker images -a)
    • l’exécution de la commande docker rmi s’impose donc sous peine de voir l’espace disque local rapidement saturé !
  • Docker for Mac stocke les images docker dans le fichier ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/Docker.qcow2
  • Voici un lien utile sur l’utilisation de l’outil qmenu-img afin de récupérer de l’espace disque après suppression des images (docker rmi ne suffit pas pour récupérer l’espace !)

Conclusion

  • Nous avons vu un moyen d’exploiter les commandes standard de docker au lieu d’écrire des scripts bash
  • La notion d’image exécutable vs package jar à déployer
  • Cette approche peut être complétée par l’utilisation d’un plugin maven pour docker

 

Publicités