使用docker-compose和CI - 如何处理退出代码和守护链接容器?

时间:2015-04-10 18:27:04

标签: docker docker-compose

现在我们的Jenkins代理为每个Rails项目生成一个docker-compose.yml,然后运行docker-compose。 docker-compose.yml有一个主要的" web"容器里面有rbenv和我们所有其他Rails依赖项。它链接到包含测试Postgres DB的数据库容器。

当我们需要实际运行测试并生成退出代码时,问题就出现了。我们的CI服务器将仅在测试脚本返回出口0时进行部署,但即使其中一个容器命令失败,docker-compose也始终返回0。

另一个问题是DB容器无限期运行,即使在Web容器运行完测试后也是如此,因此docker-compose up永远不会返回。

我们有没有办法在这个过程中使用docker-compose?我们需要能够运行容器,但在Web容器完成后退出并返回它的退出代码。现在,我们手动使用docker来启动数据库容器并使用--link选项运行Web容器。

9 个答案:

答案 0 :(得分:55)

从版本1.12.0开始,您可以使用--exit-code-from选项。

来自documentation

  

- 退出代码 - 来自SERVICE

     

返回所选服务容器的退出代码。意味着 - 在容器上退出。

答案 1 :(得分:34)

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 为您运行链接容器,但我已经听到过关于一个错误的喋喋不休,该错误阻止了它现在按预期工作。

答案 2 :(得分:22)

以kojiro的回答为基础:

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

  1. 获取容器ID
  2. 获取每个容器ID的最后一次运行退出代码
  3. 仅限不以' 0'
  4. 开头的状态代码
  5. 计算非0状态代码的数量
  6. 修剪空白
  7. 返回返回的非0退出代码的数量。如果所有内容都以代码0退出,则为0。

答案 3 :(得分:6)

如果您愿意使用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.

答案 4 :(得分:6)

使用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 updocker wait之间,以便您可以观看测试。

答案 5 :(得分:5)

--exit-code-from SERVICE--abort-on-container-exit无法在需要运行所有容器以完成的情况下工作,但如果其中一个容器提前退出,则会失败。一个例子可能是如果在不同的容器中同时运行2个测试套件。

使用@ spenthil的建议,您可以将docker-compose包装在一个脚本中,如果有任何容器,它将会失败。

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

然后在您的CI服务器上,只需将docker-compose up更改为./docker-compose.sh up

答案 6 :(得分:2)

您可以通过以下方式查看存在状态:

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

答案 7 :(得分:1)

docker-rails允许您指定将哪个容器的错误代码返回给主进程,因此CI服务器可以确定结果。对于带有docker的rails,CI和开发是一个很好的解决方案。

例如

exit_code: web
作为docker-rails.yml命令的结果,web中的

将产生docker-rails ci test容器退出代码。 docker-rails.yml只是标准docker-compose.yml的元包装,它使您有可能为不同的环境继承/重用相同的基本配置,即开发与测试对比parallel_tests。

答案 8 :(得分:0)

如果您可能在一个docker引擎上运行更多具有相同名称的docker-compose服务,但您不知道确切名称:

docker-compose up -d
(exit "${$(docker-compose logs -f test-chrome)##* }")

echo %?-从test-chrome服务返回退出代码

好处:

  • 等待确切的服务退出
  • 使用服务名称,而不是容器名称