我该如何使我的Docker Compose中的“wait-for-it”脚本调用原始容器的ENTRYPOINT或CMD?

28
根据Compose中控制启动顺序,可以使用“wait-for-it”脚本来控制Docker Compose启动容器的顺序。脚本wait-for-it.sh需要一个host:port参数以及当端口可用时脚本应执行的命令。文档建议Docker Compose使用entrypoint:选项调用此脚本。但是,如果使用此选项,则容器将不再运行其默认的ENTRYPOINTCMD,因为entrypoint:会覆盖默认设置。
如何向wait-for-it.sh提供此默认命令,以便在满足等待条件时脚本可以调用默认的ENTRYPOINTCMD
在我的情况下,我实现了一个脚本wait-for-file.sh,它轮询等待文件存在:
#!/bin/bash

set -e

waitFile="$1"
shift
cmd="$@"

until test -e $waitFile
do
  >&2 echo "Waiting for file [$waitFile]."
  sleep 1
done

>&2 echo "Found file [$waitFile]."
exec $cmd

Docker Compose将wait-for-file.sh作为入口点调用,该脚本位于从tomcat:8-jre8派生的稍微自定义的容器中:
  platinum-oms:
    image: opes/platinum-oms
    ports:
      - "8080:8080"
    volumes_from:
      - liquibase
    links:
      - postgres:postgres
      - activemq:activemq
    depends_on:
      - liquibase
      - activemq
    entrypoint: /wait-for-file.sh /var/run/liquibase/done

在成功退出之前,另一个自定义容器liquibase创建了/var/run/liquibase/done,因此platinum-oms有效地等待容器liquibase完成。
一旦容器liquibase创建了文件/var/run/liquibase/donewait-for-file.sh会打印Found file [/var/run/liquibase/done].,但无法调用基础容器tomcat:8-jre8中的默认命令catalina.sh run。为什么?

测试场景

我创建了一个简化的测试场景docker-compose-wait-for-file来展示我的问题。容器ubuntu-wait-for-file等待容器ubuntu-create-file创建文件/wait/done,然后我期望容器ubuntu-wait-for-file调用默认的ubuntu容器命令/bin/bash,但是它却退出了。为什么它不像我期望的那样工作?
1个回答

12
然而,如果使用此选项,则容器将不再运行其默认的ENTRYPOINTCMD命令,因为entrypoint:会覆盖默认设置。
这是可以预料的,这就是为什么wait-for-it被呈现为一个包装脚本的原因。它确实允许执行“子命令”:
wait-for-it.sh host:port [-s] [-t timeout] [-- command args]
                                               ^^^^^^^^^^^^

“无论服务是否启动,子命令都将被执行。如果您希望仅在服务启动时执行子命令,请添加--strict参数。” 这意味着您镜像的CMD部分可以用作实际容器命令,因为它的参数将传递给ENTRYPOINT命令。
entrypoint: wait-for-it.sh host:port --
cmd: mycmd myargs

这应该可以运行……除了 docker-compose 问题3140(由 OP Derek Mahar评论中提到)。

docker-compose.yml中定义的entrypoint会清除Dockerfile中定义的CMD

那个问题建议(2021年1月):

如果您有自定义图像,可以将启动脚本添加到构建中,并在Dockerfile中调用它,在docker-compose中再次调用它。
这是一种避免更复杂的入口点重复的方法。


1
是的,但是Docker Compose或wait-for-it如何确定并运行容器中的原始ENTRYPOINTCMD? 实际上,我希望wait-for-it在测试成功后委派给默认容器命令。 如果容器隐藏此命令,wait-for-it如何做到这一点? 至少在我的情况下,如果脚本无法运行原始容器命令,wait-for-it等待条件再让容器继续进行没有太大用处。 - Derek Mahar
1
VonC,但是我的两个容器镜像都派生自ubuntu镜像,该镜像有一个默认命令https://github.com/tianon/docker-brew-ubuntu-core/blob/045b1c500151a8239fce3cedd1fd656e7c113041/xenial/Dockerfile#L34。`wait-for-file.sh`不应该调用这个命令吗? - Derek Mahar
1
好的,但这不是我试图表示的场景。在我的“真实”情况下,我的容器没有默认命令,它派生自tomcat:8-jre8,该镜像有一个默认命令catalina.sh run - Derek Mahar
1
@DerekMahar 是的,我确定。CMD 始终传递到 ENTRYPOINT 。 wait-for-it 将执行在镜像中找到的 CMD。 - VonC
根据https://github.com/docker/compose/issues/3140#issuecomment-234267729的说法,VonC认为3140实际上是Docker Compose文档中的一个错误。由于Docker Engine可能会覆盖命令,因此“wait-for-it”将不会在镜像中执行“CMD”。尽管如此,这绝对不是我所期望的行为。 - Derek Mahar
显示剩余21条评论

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