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

Log*_*man 76 docker docker-compose

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

当我们需要实际运行测试并生成退出代码时,问题就出现了.我们的CI服务器仅在测试脚本返回exit 0时才会部署,但docker-compose总是返回0,即使其中一个容器命令失败也是如此.

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

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

小智 66

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

来自文档:

--Exit-code-from SERVICE

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

  • 我能够在Travis CI上工作:https://travis-ci.org/coyote-team/coyote/builds/274582053这里是travis.yml:https://github.com/coyote-team/coyote/斑点/主/ .travis.yml#L12 (3认同)
  • 如果您使用 ``docker-compose``` 1.12.0 及更高版本,这应该是正确的方法。也许这也是你的情况。一个例子是:``docker-compose up --exit-code-from test-unit``。请注意,直到我在脚本开头添加 ```set -e``` 后,它才对我起作用。 (2认同)
  • `--exit-code-from` 不适用于 `-d`。它会抛出这些错误:`使用 --exit-code-from 意味着 --abort-on-container-exit` 和 `--abort-on-container-exit 和 -d 不能组合。` (2认同)
  • 文档很糟糕。这与哪些标志兼容?它只是一项服务还是您可以通过多项服务? (2认同)

koj*_*iro 36

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
Run Code Online (Sandbox Code Playgroud)

或者,您可以选择检查死容器.您可以使用该-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
Run Code Online (Sandbox Code Playgroud)

对于永不返回的db容器,如果你使用docker-compose up那么你将需要sigkill那个容器; 这可能不是你想要的.相反,您可以使用docker-compose up -d守护程序运行容器,并在测试完成时手动终止容器.docker-compose run 应该为你运行链接的容器,但我听到有关一个错误的喋喋不休,因为它阻止了它现在按预期工作.


spe*_*hil 23

以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. 计数非0状态代码的数量
  5. 修剪出白色空间

返回返回的非0退出代码的数量.如果所有内容都以代码0退出,则为0.


esm*_*ail 7

如果您愿意使用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.
Run Code Online (Sandbox Code Playgroud)


Bry*_*sen 7

使用docker wait以获取退出代码:

$ docker-compose -p foo up -d
$ ret=$(docker wait foo_bar_1)
Run Code Online (Sandbox Code Playgroud)

foo是"项目名称".在上面的示例中,我明确指定了它,但如果您不提供它,则它是目录名称. bar是您在docker-compose.yml中为待测系统提供的名称.

请注意,docker logs -f当容器停止时,正确的事情也会退出.所以你可以把

$ docker logs -f foo_bar_1
Run Code Online (Sandbox Code Playgroud)

之间的docker-compose updocker wait让您可以观看你的测试运行.


Mat*_*ole 6

--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:]')
Run Code Online (Sandbox Code Playgroud)

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