imagenes - download docker image
Usando docker-compose con CI: ¿cómo lidiar con los códigos de salida y los contenedores enlazados demonizados? (9)
Desde la versión
1.12.0
, puede usar la opción
--exit-code-from
.
De la documentation :
--exit-code-from SERVICE
Devuelve el código de salida del contenedor de servicio seleccionado. Implica --abort-on-container-exit.
En este momento, nuestros agentes Jenkins generan un docker-compose.yml para cada uno de nuestros proyectos de Rails y luego ejecutan docker-compose. Docker-compose.yml tiene un contenedor "web" principal que tiene rbenv y todas nuestras otras dependencias de Rails dentro. Está vinculado a un contenedor de base de datos que contiene la base de datos de prueba de Postgres.
El problema surge cuando necesitamos ejecutar las pruebas y generar códigos de salida. Nuestro servidor CI solo se desplegará si el script de prueba devuelve la salida 0, pero docker-compose siempre devuelve 0, incluso si falla uno de los comandos del contenedor.
El otro problema es que el contenedor de base de datos se ejecuta indefinidamente, incluso después de que el contenedor web haya terminado de ejecutar las pruebas, por lo que
docker-compose up
nunca regresa.
¿Hay alguna manera de usar docker-compose para este proceso? Necesitaríamos poder ejecutar los contenedores, pero salga después de que el contenedor web esté completo y devuelva su código de salida. En este momento estamos atascados manualmente usando Docker para girar el contenedor de DB y ejecutar el contenedor web con la opción --link.
En caso de que pueda ejecutar más servicios de compilación de docker con el mismo nombre en un motor de docker, y no sabe el nombre exacto:
docker-compose up -d
(exit "${$(docker-compose logs -f test-chrome)##* }")
echo %?
- devuelve el código de salida del servicio test-chrome
Beneficios:
- esperar a que salga el servicio exacto
- usa el nombre del servicio, no el nombre del contenedor
Puede ver el estado existente con:
echo $(docker-compose ps | grep "servicename" | awk ''{print $4}'')
Si está dispuesto a utilizar la
docker-compose run
para iniciar manualmente sus pruebas, agregar el indicador
--rm
, por extraño que parezca, hace que Compose refleje con precisión el estado de salida de su comando.
Aquí está mi ejemplo:
$ 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.
Sobre la base de la respuesta de kojiro:
docker-compose ps -q | xargs docker inspect -f ''{{ .State.ExitCode }}'' | grep -v ''^0'' | wc -l | tr -d '' ''
- obtener ID de contenedor
- obtener el código de salida de las últimas ejecuciones para cada ID de contenedor
- solo códigos de estado que no comienzan con ''0''
- cuenta el número de códigos de estado que no son 0
- recortar el espacio en blanco
Devuelve cuántos códigos de salida distintos de 0 se devolvieron. Sería 0 si todo saliera con el código 0.
Use
docker wait
para obtener el código de salida:
$ docker-compose -p foo up -d
$ ret=$(docker wait foo_bar_1)
foo
es el "nombre del proyecto".
En el ejemplo anterior, lo especifiqué explícitamente, pero si no lo proporciona, es el nombre del directorio.
bar
es el nombre que le da al sistema bajo prueba en su docker-compose.yml.
Tenga en cuenta que
docker logs -f
hace lo correcto, saliendo cuando el contenedor se detiene.
Entonces puedes poner
$ docker logs -f foo_bar_1
entre el
docker-compose up
y el
docker wait
para que pueda ver cómo se ejecutan sus pruebas.
docker-rails permite especificar qué código de error del contenedor se devuelve al proceso principal, para que su servidor CI pueda determinar el resultado. Es una gran solución para CI y desarrollo para rieles con docker.
Por ejemplo
exit_code: web
en su
docker-rails.yml
generará el código de salida de los contenedores
web
como resultado del comando
docker-rails ci test
.
docker-rails.yml
es solo un meta envoltorio alrededor del estándar
docker-compose.yml
que le brinda el potencial de heredar / reutilizar la misma configuración base para diferentes entornos, es decir, desarrollo vs prueba vs prueba paralela.
--exit-code-from SERVICE
y
--abort-on-container-exit
no funcionan en escenarios en los que necesita ejecutar todos los contenedores hasta su finalización, pero falla si uno de ellos salió antes.
Un ejemplo podría ser si se ejecutan 2 trajes de prueba al mismo tiempo en diferentes contenedores.
Con la sugerencia de @ employeehil, puede envolver
docker-compose
en un script que fallará si algún contenedor lo hace.
#!/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:]'')
Luego, en su servidor CI, simplemente cambie
docker-compose up
./docker-compose.sh up
.
docker-compose run
es la manera simple de obtener los estados de salida que desea.
Por ejemplo:
$ 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
Alternativamente, tiene la opción de
inspect
los contenedores muertos.
Puede usar la bandera
-f
para obtener solo el estado de salida.
$ 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 cuanto al contenedor db que nunca regresa, si usa
docker-compose up
entonces deberá sigkill ese contenedor;
eso probablemente no sea lo que quieres.
En su lugar, puede usar
docker-compose up -d
para ejecutar sus contenedores daemonizados y eliminar manualmente los contenedores cuando se complete la prueba.
docker-compose run
debería
ejecutar contenedores vinculados para usted, pero he escuchado comentarios sobre SO sobre un error que impide que funcione en este momento.