What is the alternative to condition form of depends_on in docker-compose Version 3?

docker-compose 2.1 offers the nice feature to specify a condition with depends_on. The current docker-compose documentation states:

Version 3 no longer supports the condition form of depends_on.

Unfortunately the documentation does not explain, why the condition form was removed and is lacking any specific recommondation on how to implement that behaviour using V3 upwards.

84353 次浏览

在撰写中指定容器依赖性已经有所改变。它们仅在启动时有效,并且在运行时重新启动依赖容器时不起作用。相反,每个容器都应该包含一种机制,以便在连接被删除时重新尝试连接到依赖服务。许多连接到数据库或 REST API 服务的库都具有可配置的内置重试。我会调查的。无论如何,生产代码都需要它。

有一些外部工具可以让您模仿这种行为。例如,使用 停工工具,您可以用 dockerize -wait包装 CMDENTRYPOINT,这将阻止运行您的应用程序,直到指定的服务准备就绪。

如果你的文件看起来像这样:

version: '2.1'
services:
kafka:
image: spotify/kafka
healthcheck:
test: nc -z localhost 9092
webapp:
image: foo/bar # your image
healthcheck:
test: curl -f http://localhost:8080
tests:
image: bar/foo # your image
command: YOUR_TEST_COMMAND
depends_on:
kafka:
condition: service_healthy
webapp:
condition: service_healthy

然后你可以像这样在你的 v3作文文件中使用 dockerize:

version: '3.0'
services:
kafka:
image: spotify/kafka
webapp:
image: foo/bar # your image
tests:
image: bar/foo # your image
command: dockerize -wait tcp://kafka:9092 -wait web://webapp:8080 YOUR_TEST_COMMAND

我只是想在运行 postgres 时添加我的解决方案,并在启动前需要应用程序等待 init sql 脚本完成的地方通过 docker-compose 添加应用程序。

Dockerize 似乎在等待 db 端口可用(端口5432) ,这与可以在 docker 3中使用的 depends_on是等价的:

version: '3'


services:
app:
container_name: back-end
depends_on:
- postgres
postgres:
image: postgres:10-alpine
container_name: postgres
ports:
- "5432:5432"
volumes:
- ./docker-init:/docker-entrypoint-initdb.d/

问题:

如果您有一个大的 init 脚本,应用程序将在完成之前启动,因为 depends_on只等待数据库端口。

虽然我同意这个解决方案应该在应用程序逻辑中实现,但是我们的问题仅仅是当我们想要运行测试并用测试数据预填充数据库时,所以在代码之外实现一个解决方案更有意义,因为我不喜欢引入“让测试工作”的代码

解决方案:

对 postgres 容器执行一个 healthcheck。 对我来说,这意味着检查 pid 1的命令是 postgres,因为当 init db 脚本运行时,它将在 pid 1上运行另一个命令

在应用程序端编写一个脚本,等待 postgres变成 healthy:

#!/bin/bash
function check {
STATUS=\`curl -s --unix-socket /var/run/docker.sock http:/v1.24/containers/postgres/json | python -c 'import sys, json; print json.load('sys.stdin')["State"]["Health"]["Status"]'\`


if [ "$STATUS" = "healthy" ]; then
return 0
fi
return 1
}


until check; do
echo "Waiting for postgres to be ready"
sleep 5
done


echo "Postgres ready"

然后 docker-compose 应该挂载脚本的目录,这样我们就不会为应用程序编辑 Dockerfile,如果我们使用自定义 postgres 图像,这样我们就可以继续为您发布的图像使用 docker 文件。

我们还将覆盖应用程序的 docker 文件中定义的入口点,以便在应用程序启动之前运行等待脚本

version: '3'


services:
app:
container_name: back-end
entrypoint: ["/bin/sh","-c","/opt/app/wait/wait-for-postgres.sh && <YOUR_APP_START_SCRIPT>"]
depends_on:
- postgres
volumes:
- //var/run/docker.sock:/var/run/docker.sock
- ./docker-scripts/wait-for-postgres:/opt/app/wait
postgres:
image: postgres:10-alpine
container_name: postgres
ports:
- "5432:5432"
volumes:
- ./docker-init:/docker-entrypoint-initdb.d/
- ./docker-scripts/postgres-healthcheck:/var/lib
healthcheck:
test: /var/lib/healthcheck.sh
interval: 5s
timeout: 5s
retries: 10

与其依赖另一个容器启动,不如考虑在尝试访问可能没有处于就绪状态的容器时,如果接收到连接错误,故意从容器化的应用程序中退出。

这种策略与容器的适当重新启动策略一起使用,将重新启动应用程序容器,直到连接可用或重新启动策略满足终止条件为止。

或者,如果您愿意等待特定的时间,也可以使用一些像 等等这样的好实用程序。下面是对 mssql 容器使用 wait-for-it 的一个很好的 例子

1.27.0中,2.x 和3.x 与 COMOSE _ SPEC模式合并。

Version 现在是可选的。因此,您可以像之前一样删除它并指定一个 情况:

services:
web:
build: .
depends_on:
redis:
condition: service_healthy
redis:
image: redis
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 30

我到达这个页面,因为一个容器不会等待一个取决于,我必须运行一个 docker system prune让它工作。有一个 orphaned container错误提示我运行 prune