97

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

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

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

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

4

9 回答 9

84

Since version 1.12.0, you can use the --exit-code-from option.

From documentation:

--exit-code-from SERVICE

Return the exit code of the selected service container. Implies --abort-on-container-exit.

于 2017-04-12T10:39:44.830 回答
45

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

或者,您可以选择检查死容器。您可以使用该-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 upthen 您将需要 sigkill 该容器;这可能不是你想要的。相反,您可以使用docker-compose up -d守护进程运行容器,并在测试完成时手动终止容器。docker-compose run 应该为你运行链接的容器,但我听说过关于一个错误,它阻止了它现在按预期工作。

于 2015-04-10T18:36:10.850 回答
25

基于小次郎的回答:

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。

于 2015-10-22T22:04:45.740 回答
12

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

于 2017-08-03T21:52:12.563 回答
11

用于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

在 thedocker-compose up和 the之间,docker wait你可以看到你的测试运行。

于 2017-03-14T19:01:45.463 回答
9

如果您愿意使用docker-compose run手动启动测试,--rm奇怪的是,添加标志会使 Compose 准确反映您的命令的退出状态。

这是我的例子:

$ docker-compose -v
docker-compose version 1.7.0, build 0d7bf73

$ (docker-compose run bash false) || echo 'Test failed!'  # False negative.

$ (docker-compose run --rm bash false) || echo 'Test failed!'  # True positive.
Test failed!

$ (docker-compose run --rm bash true) || echo 'Test failed!'  # True negative.
于 2016-05-12T21:47:15.397 回答
2

您可以通过以下方式查看退出状态:

echo $(docker-compose ps | grep "servicename" | awk '{print $4}')
于 2017-10-29T03:17:27.920 回答
2

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

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

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

好处:

  • 等待确切的服务退出
  • 使用服务名称,而不是容器名称
于 2018-11-08T15:01:58.677 回答
2

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

例如

exit_code: web

在您docker-rails.yml将产生web容器退出代码作为命令的结果docker-rails ci testdocker-rails.yml只是围绕标准的一个元包装器,docker-compose.yml它使您有可能为不同的环境继承/重用相同的基本配置,即开发、测试和并行测试。

于 2015-09-30T16:53:18.260 回答