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
- Idem partie 1 de l’article
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