问题描述
在使用Docker Compose时,遇到了一个问题。在下面的docker-compose.yml
文件中,服务”bar”依赖于服务”foo”,但它们位于不同的profiles中。现在,当我只激活”profile bar”而不激活”profile foo”时,我希望服务”foo”也会启动,但实际上并没有发生。这是一个bug还是预期的行为?如果是预期的行为,原因是什么?是否有其他方法可以自动确保所有依赖项也会启动,或者我必须手动确保所选的profiles不会违反我的依赖关系?我使用的是Docker版本20.10.17和Docker Compose版本2.10.0。
services:
foo:
build: ./foo
profiles: ["foo"]
bar:
build: ./bar
profiles: ["bar"]
depends_on:
foo:
condition: service_completed_successfully
P.S.:正如@larsks所指出的,官方文档中提到:
但请记住,docker compose仅会自动启用命令行上的服务的profiles,而不会自动启用任何依赖项的profiles。这意味着目标服务所依赖的所有服务必须具有与之相同的profile,始终启用(通过省略profiles)或显式启用匹配的profile。
然而,示例代码中包含了以下内容:
# this will fail because profile "dev" is disabled
$ docker compose up phpmyadmin
“fail”这个词对我来说意味着docker compose up bar
将无法启动,或者至少会打印出错误或警告,但实际上这两者都没有发生。
以下是一个最小化的示例:
services:
foo:
image: hello-world
profiles: ["foo"]
bar:
image: hello-world
depends_on:
foo:
condition: service_completed_successfully
$ docker compose up
日志显示它并没有失败,它只是静默地执行了bar而没有执行foo,也没有失败或打印任何消息。
P.P.S.:我在https://github.com/docker/compose/issues/9795上创建了一个问题。
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
根据Docker Compose的文档,服务的profiles只有在命令行上启用时才会自动启用,而不会自动启用任何依赖项的profiles。这就是为什么在你的情况下,即使你只激活了”profile bar”,”foo”服务也不会自动启动的原因。
为了解决这个问题,你可以考虑将依赖关系与profiles分离,以确保它们始终启动。以下是一种可能的解决方案:
- 将”foo”服务的profile设置为空,这样它将始终启动。
- 在”bar”服务的depends_on部分,删除condition属性,这样它将始终依赖于”foo”服务。
下面是修改后的docker-compose.yml
文件的示例:
services:
foo:
build: ./foo
profiles: []
bar:
build: ./bar
depends_on:
- foo
通过这样的修改,无论你激活哪个profile,”foo”服务都将始终启动,并且”bar”服务将始终依赖于”foo”服务。
方案2
另一种解决方案是使用脚本或工具来管理容器的启动顺序。你可以编写一个脚本来手动控制容器的启动顺序,或者使用一些第三方工具来管理容器的依赖关系。
以下是一个简单的bash脚本示例,可以在容器”foo”启动后启动容器”bar”:
#!/bin/bash
# 启动容器foo
docker-compose up -d foo
# 等待容器foo完全启动
while ! docker-compose exec foo echo "Container foo is ready"; do
sleep 1
done
# 启动容器bar
docker-compose up -d bar
在这个示例中,我们首先使用docker-compose up
命令启动容器”foo”。然后,使用一个循环来等待容器”foo”完全启动(这里是通过在容器内运行echo
命令来测试)。一旦容器”foo”就绪,我们再使用docker-compose up
命令启动容器”bar”。
通过使用这样的脚本,你可以手动控制容器的启动顺序,并确保依赖关系得到满足。
请注意,这只是一种解决方案,你可以根据自己的需求进行调整和修改。
总结
在Docker Compose中,当服务的profiles被激活时,只有该服务的profiles会自动启用,而不会自动启用任何依赖项的profiles。为了确保所有依赖项也会启动,你可以将依赖关系与profiles分离,或者使用脚本或工具来管理容器的启动顺序。以上是两种可能的解决方案,你可以根据自己的需求选择适合的方法。