当测试容器完成时终止Docker Compose

71

我目前正在运行一个docker-compose堆栈,用于基本的集成测试,其中包括protractor测试运行程序、提供网页服务的nodejs服务器和提供java后端的wildfly服务器。

该堆栈从我的构建服务器(concourse ci)中的dind(docker in docker)容器中运行。

但是似乎容器在完成protractor测试后并没有终止。

因此,由于wildfly和nodejs的容器仍在运行,构建任务永远无法结束...

如何使compose在测试完成时以成功或失败的方式结束?

# Test runner
test-runner:
  image: "${RUNNER_IMG}"
  privileged: true
  links:
    - client
    - server
  volumes:
  - /Users/me/frontend_test/client-devops:/protractor/project
  - /dev/shm:/dev/shm
  entrypoint:
    - /entrypoint.sh
    - --baseUrl=http://client:9000/dist/
    - /protractor/conf-dev.js
    - --suite=remember
# Client deployment
client:
  image: "${CLIENT_IMG}"
  links:
    - server
# Server deployment
server:
  image: "${SERVER_IMG}"
7个回答

147

你可以使用以下docker-compose参数来实现此目的:

--abort-on-container-exit 如果任何容器停止,则停止所有容器。

--exit-code-from 返回所选服务容器的退出代码。

例如,有这样的docker-compose.yml文件:

version: '2.3'

services:
  elasticsearch:
    ...
  service-api:
    ...
  service-test:
    ...
    depends_on:
      - elasticsearch
      - service-api
以下命令确保在service-test容器结束后,elasticsearchservice-api也会停止,并返回service-test容器的退出代码。
docker-compose -f docker-compose.yml up \
    --abort-on-container-exit \
    --exit-code-from service-test

17
非常感谢您!我读了一半的互联网才找到您的解决方案 :-) - rafalkasa
7
同意,那真是出乎意料的难以搜索。 - Tom Malkin
3
确实。标星并点赞以确保它不会再丢失了。 - Adam Matan
1
非常...琐碎的答案。我希望这个答案能够成为最顶端,这样大家在搜索时就不会错过它。 - hqt
我在StackOverflow上得到的最佳答案!! - pradeepchhetri
6
好的回答!顺便说一下,你可以省略 --abort-on-container-exit。 https://docs.docker.com/compose/reference/up/ - Shota Tamura

46

Compose已经添加了--exit-code-from {container}标志到docker-compose up,这使得操作更加便捷。

docker-compose up --exit-code-from test-runner

查看Michael Spector的回答以获取更详细的信息。


原始回答

类似于这个rspec q/a,您需要将测试作为独立任务运行,并将退出状态报告给您的CI。

您可以将测试运行器分离成自己的yaml文件,或者修改测试运行器以默认为无操作命令/入口点。

分离测试运行器

单独指定test-runner配置(您可能需要升级到版本2的networks,而不是使用links来跨多个compose文件工作)。

docker-compose up -d
docker-compose -f test-runner.yml run test-runner
rc=$?
docker-compose down
exit $rc

无操作测试运行器

test-runner默认设置为无操作入口点/命令,然后手动运行测试命令。

services:
  test-runner:
    image: "${RUNNER_IMG}"
    command: 'true'

那么

docker-compose up -d
docker-compose run test-runner /launch-tests.sh
rc=$?
docker-compose down
exit $rc

返回代码

如果您的 CI 具有“后置任务”概念,则可以跳过rc捕获,并在测试运行器 CI 任务完成后运行docker-compose down。您的 CI 也可能会为您清理容器。


能否在docker-compose文件中编写像--exit-code-from test-runner这样的内容? - Serhii Kushchenko
@SerhiiKushchenko 在规范中没有像exit-code-from这样的东西。 - Matt

27

我认为最优雅的解决方案是在您的docker-compose.yml文件中使用depends_on

services:
  dynamodb:
  ...
  test_runner:
    ...
    depends_on:
      - dynamodb
现在你可以使用 docker-compose run --rm test_runner,它会设置你的依赖项,运行你的测试,清理一切,并传播返回代码。
docker-compose run test_runner false
Starting test_dynamodb_1 ... done
echo $?
1
docker-compose run test_runner true
Starting test_dynamodb_1 ... done
echo $?

5
不确定为什么这篇文章没有得到更多的赞 - 在我看来,它比被采纳的答案更好地解决了问题。 - DaveyDaveDave
2
请注意,这不会拆除依赖项,与 https://dev59.com/k1gR5IYBdhLWcg3wvPmM#49485880 相反。 - Adam Matan

2
我尝试了这个讨论中提供的解决方案,但问题仍然存在。
情况1:docker-compose up -d
你可以使用docker-compose up -d,通过test-runner进行测试,然后通过docker-compose down终止,但是当你使用docker-compose up -d时,你将不再看到标准输出的日志
情况2:docker-compose up --exit-code-from a service 如果你使用--exit-code-from <service>(意味着--abort-on-container-exit),你可以查看docker日志,但是当服务成功完成时,它不会发送退出命令。因此,在发送docker-compose down停止它们之前,你需要捕获你的容器已经完成测试。
终止日志之前查看日志的解决方案之一是使用 --tail=1000 -f点击此处查看日志
docker-compose up -d
docker-compose logs --tail=1000 -f test-runner
docker-compose down
exit $rc

还有一种使用nohup的解决方案,但您需要等待进程完全完成,然后打开输出日志文件,所以上述方法应该更容易。

0

我的docker compose up命令中使用了一些标志(例如--build),这些标志阻止了所有服务容器在触发--abort-on-container-exit时停止运行。

例如以下命令:

docker compose up \
  --build service1 \
  --attach service1 --attach service2 \
  --abort-on-container-exit

这将启动service1service2,但仅在因为Docker只负责构建service1而中止时停止service1,它拒绝假设service2不存在——即使它在相同的docker-compose.yml中定义并与depends_on链接,并且它只是刚刚启动了它。它只会让service2保持运行状态。1

要解决这个问题,我只需要确保在docker compose up之后运行docker compose down

可以使用trap来确保它始终运行,即使docker compose up失败并且会提前退出脚本:

#!/usr/bin/env sh

cleanup() {
  docker compose down
}
trap cleanup EXIT  # will always run when the script exits

docker compose up \
  --build service1 \
  --attach service1 --attach service2 \
  --abort-on-container-exit

脚注

1:这是一个问题,因为我的service1预期其service2处于初始状态。


-1

为了避免使用单独的配置文件,您可以更新docker-compose配置,使用depends_on选项来介绍服务之间的依赖关系,该选项从版本2格式及以上可用。结果是test-runner的启动将启动客户端的运行。

请注意,如果您需要等待测试的服务内部实际的Web服务器启动一段时间,您可以使用wait-for-it.sh脚本等待直到服务器可用。

# Test runner
test-runner:
  image: "${RUNNER_IMG}"
  privileged: true
  links:
    - client
    - server
  volumes:
  - /Users/me/frontend_test/client-devops:/protractor/project
  - /dev/shm:/dev/shm
  depends_on:
    - client
  entrypoint:
    - wait-for-it.sh
    - client
    - -t
    - '180'
    - --
    - /entrypoint.sh
    - --baseUrl=http://client:9000/dist/
    - /protractor/conf-dev.js
    - --suite=remember
# Client deployment
client:
  image: "${CLIENT_IMG}"
  depends_on:
    - server
  links:
    - server
# Server deployment
server:
  image: "${SERVER_IMG}"

在更新配置后,只需执行简单的docker-compose up test-runner即可触发相关服务的启动。


-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接