Actuellement, nos agents Jenkins génèrent un fichier docker-compose.yml pour chacun de nos Rails), puis exécutent docker-compose up. Le fichier docker-compose.yml a un conteneur "Web" principal qui a rbenv et toutes nos autres dépendances Rails à l'intérieur. Il est lié à un conteneur de base de données contenant la base de données test Postgres.
Le problème survient lorsque nous devons réellement exécuter les tests et générer des codes de sortie. Notre serveur d'infrastructure ne se déploiera que si le script de test renvoie l'exit 0, mais docker-compose renvoie toujours 0, même si l'une des commandes de conteneur échoue.
L'autre problème est que le conteneur de base de données s'exécute indéfiniment, même après que le conteneur Web ait terminé l'exécution des tests, donc docker-compose up
ne revient jamais.
Existe-t-il un moyen d'utiliser Docker-Compose pour ce processus? Nous devrions pouvoir exécuter les conteneurs, mais quitter une fois le conteneur Web terminé et renvoyer son code de sortie. Pour le moment, nous sommes bloqués manuellement à l'aide de docker pour faire tourner le conteneur de base de données et exécuter le conteneur Web avec l'option --link.
Depuis la version 1.12.0
, vous pouvez utiliser le --exit-code-from
option.
De documentation :
--exit-code-from SERVICE
Renvoie le code de sortie du conteneur de service sélectionné. Implique --abort-on-container-exit.
docker-compose run
est le moyen simple d’obtenir les statuts de sortie que vous désirez. Par exemple:
$ cat docker-compose.yml
roit:
image: busybox
command: 'true'
naw:
image: busybox
command: 'false'
$ docker-compose run --rm roit; echo $?
Removing test_roit_run_1...
0
$ docker-compose run --rm naw; echo $?
Removing test_naw_run_1...
1
Alternativement, vous avez la possibilité de inspecter les conteneurs morts. Vous pouvez utiliser le -f
drapeau pour obtenir uniquement le statut de sortie.
$ docker-compose up
Creating test_naw_1...
Creating test_roit_1...
Attaching to test_roit_1
test_roit_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
$ docker-compose ps -q | xargs docker inspect -f '{{ .Name }} exited with status {{ .State.ExitCode }}'
/test_naw_1 exited with status 1
/test_roit_1 exited with status 0
En ce qui concerne le conteneur de base de données qui ne retourne jamais, si vous utilisez docker-compose up
alors vous aurez besoin de sigkill ce conteneur; ce n'est probablement pas ce que vous voulez. Au lieu de cela, vous pouvez utiliser docker-compose up -d
pour exécuter vos conteneurs démonisés et les supprimer manuellement une fois votre test terminé. docker-compose run
devrait exécuter des conteneurs liés pour vous, mais j'ai entendu des discussions sur SO) à propos d'un bogue empêchant son bon fonctionnement comme prévu en ce moment.
S'appuyant sur la réponse de kojiro:
docker-compose ps -q | xargs docker inspect -f '{{ .State.ExitCode }}' | grep -v '^0' | wc -l | tr -d ' '
Retourne combien de codes de sortie non-0 ont été retournés. Serait 0 si tout est sorti avec le code 0.
Si vous êtes prêt à utiliser docker-compose run
pour lancer manuellement vos tests, en ajoutant le --rm
drapeau, curieusement, force Compose à refléter avec précision le statut de sortie de votre commande.
Voici mon exemple:
$ docker-compose -v
docker-compose version 1.7.0, build 0d7bf73
$ (docker-compose run kpi false) || echo 'Test failed!' # False negative.
$ (docker-compose run --rm kpi false) || echo 'Test failed!' # True positive.
Test failed!
$ (docker-compose run --rm kpi true) || echo 'Test failed!' # True negative.
Utilisation docker wait
pour obtenir le code de sortie:
$ docker-compose -p foo up -d
$ ret=$(docker wait foo_bar_1)
foo
est le "nom du projet". Dans l'exemple ci-dessus, je l'ai spécifié explicitement, mais si vous ne le fournissez pas, c'est le nom du répertoire. bar
est le nom que vous donnez au système testé dans votre fichier docker-compose.yml.
Notez que docker logs -f
fait la bonne chose aussi, sortir quand le conteneur s'arrête. Donc tu peux mettre
$ docker logs -f foo_bar_1
entre le docker-compose up
et le docker wait
afin que vous puissiez regarder vos tests se dérouler.
--exit-code-from SERVICE
et --abort-on-container-exit
ne fonctionne pas dans les scénarios dans lesquels vous devez exécuter tous les conteneurs, mais échouez si l’un d’eux s’est arrêté tôt. Un exemple pourrait être si vous exécutez 2 combinaisons de test simultanément dans des conteneurs différents.
Avec la suggestion de @USSHILH, vous pouvez envelopper docker-compose
dans un script qui échouera si des conteneurs le font.
#!/bin/bash
set -e
# Wrap docker-compose and return a non-zero exit code if any containers failed.
docker-compose "$@"
exit $(docker-compose -f docker-compose.ci.build.yml ps -q | tr -d '[:space:]' |
xargs docker inspect -f '{{ .State.ExitCode }}' | grep -v 0 | wc -l | tr -d '[:space:]')
Ensuite, sur votre serveur CI, changez simplement docker-compose up
à ./docker-compose.sh up
.
Vous pouvez voir le statut exist avec:
echo $(docker-compose ps | grep "servicename" | awk '{print $4}')
docker-Rails vous permet de spécifier le code d'erreur du conteneur renvoyé au processus principal afin que votre serveur CI puisse déterminer le résultat. C'est une excellente solution pour CI et le développement de Rails avec docker.
Par exemple
exit_code: web
dans votre docker-Rails.yml
donnera le code de sortie des conteneurs web
à la suite de la commande docker-Rails ci test
. docker-Rails.yml
est juste une méta-enveloppe autour de la norme docker-compose.yml
qui vous donne le potentiel d’hériter/de réutiliser la même configuration de base pour différents environnements, c’est-à-dire développement vs test vs parallèle_tests.
Dans le cas où vous pourriez exécuter plus de services de composition de docker avec le même nom sur un moteur de docker et dont vous ne connaissez pas le nom exact:
docker-compose up -d
(exit "${$(docker-compose logs -f test-chrome)##* }")
echo %?
- renvoie le code de sortie du service test-chrome
Avantages: