Подтвердить что ты не робот

Использование docker-compose с CI - как работать с кодами выхода и демонтированными связанными контейнерами?

Сейчас наши агенты Jenkins генерируют docker-compose.yml для каждого из наших проектов Rails, а затем запускают сборку докеров. У docker-compose.yml есть основной "веб-контейнер", в котором есть rbenv и все наши другие Rails-зависимости внутри. Он связан с контейнером DB, который содержит тестовую базу Postgres.

Проблема возникает, когда нам нужно фактически запускать тесты и генерировать коды выхода. Наш CI-сервер будет развертываться только в том случае, если тест script возвращает выход 0, но docker-compose всегда возвращает 0, даже если одна из команд контейнера терпит неудачу.

Другая проблема заключается в том, что контейнер DB работает неограниченно, даже после того, как веб-контейнер завершен, поэтому docker-compose up никогда не возвращается.

Есть ли способ, которым мы можем использовать docker-compose для этого процесса? Нам нужно будет иметь возможность запускать контейнеры, но выходить после завершения веб-контейнера и возвращать его код завершения. Прямо сейчас мы застреваем вручную, используя докер, чтобы развернуть контейнер БД и запустить веб-контейнер с опцией -link.

4b9b3361

Ответ 1

docker-compose run - это простой способ получить статусы выхода, которые вы желаете. Например:

$ 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

Кроме того, у вас есть опция inspect мертвых контейнеров. Вы можете использовать флаг -f, чтобы получить только статус выхода.

$ 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

Что касается контейнера db, который никогда не возвращается, если вы используете docker-compose up, тогда вам нужно будет sigkill этот контейнер; что, вероятно, не то, что вы хотите. Вместо этого вы можете использовать docker-compose up -d для демонтажа ваших контейнеров и вручную уничтожить контейнеры, когда ваш тест будет завершен. docker-compose run должен запускать связанные контейнеры для вас, но я слышал болтовню о SO об ошибке, которая препятствует тому, чтобы она работала по назначению прямо сейчас.

Ответ 2

Основываясь на ответе Коджиро:

docker-compose ps -q | xargs docker inspect -f '{{ .State.ExitCode }}' | grep -v 0 | wc -l | tr -d ' '

  • получить идентификаторы контейнера
  • получить последний код выхода для каждого идентификатора контейнера
  • только не-коды состояния
  • подсчитать количество кодов состояния, отличных от 0
  • обрезать пробел.

Возвращает количество возвращаемых кодов, отличных от 0. Было бы 0, если все вышло с кодом 0.

Ответ 3

Начиная с версии 1.12.0, вы можете использовать опцию --exit-code-from.

Из документация:

- exit-code - из SERVICE

Возвращает код выхода выбранного контейнера службы. Подразумевает - выход из контейнера-контейнера.

Ответ 4

Если вы хотите использовать docker-compose run для запуска ваших тестов вручную, добавление флага --rm, как ни странно, заставляет Compose точно отражать статус выхода вашей команды.

Вот мой пример:

$ 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.

Ответ 5

Используйте docker wait, чтобы получить код выхода:

$ docker-compose -p foo up -d
$ ret=$(docker wait foo_bar_1)

foo - это имя проекта. В приведенном выше примере я указал его явно, но если вы его не предоставили, это имя каталога. bar - это имя, которое вы даете тестируемой системе в файле docker-compose.yml.

Обратите внимание, что docker logs -f тоже делает то же самое, когда контейнер останавливается. Таким образом, вы можете поместить

$ docker logs -f foo_bar_1

между docker-compose up и docker wait, чтобы вы могли наблюдать за выполнением ваших тестов.

Ответ 6

docker-rails позволяет указать, какой код ошибки контейнера возвращается основному процессу, поэтому сервер CI может определить результат. Это отличное решение для CI и разработки для рельсов с докером.

Например

exit_code: web

в вашем docker-rails.yml выдает код выхода контейнеров web в результате команды docker-rails ci test. docker-rails.yml - это всего лишь мета-обертка вокруг стандартного docker-compose.yml, который дает вам возможность наследовать/повторно использовать ту же базовую конфигурацию для разных сред, то есть разработки против теста vs parallel_tests.

Ответ 7

--exit-code-from SERVICE и --abort-on-container-exit не работают в сценариях, где вам нужно запустить все контейнеры до завершения, но сбой, если один из них вышел раньше. Например, если вы запускаете 2 тестовых костюма одновременно в разных контейнерах.

С предложением @spenthil вы можете обернуть docker-compose в script, который будет терпеть неудачу, если какие-либо контейнеры.

#!/bin/bash
set -e

# Wrap docker-compose and return a non-zero exit code if any containers failed.

docker-compose "[email protected]"

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:]')

Затем на вашем сервере CI просто измените docker-compose up на ./docker-compose.sh up.

Ответ 8

Вы можете видеть существующий статус с помощью:

echo $(docker-compose ps | grep "servicename" | awk '{print $4}')