1

我无法理解或看到使用 bash 脚本作为 Docker 容器的入口点的某些工作版本。我已经尝试了很多东西了大约 5 个小时。

即使来自这个官方 Docker 博客,使用 bash 脚本作为入口点仍然不起作用。

Dockerfile

FROM debian:stretch
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"]

码头入口点.sh

#!/bin/bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

构建.sh

docker build -t test .

运行.sh

docker service create \
--name test \
test

尽管付出了很多努力,但我似乎无法使用入口点作为 bash 脚本来获取 Dockerfile,该脚本不会不断重启并反复失败。

我的理解是exec "$@"假设保持容器表单立即退出,但我不确定这是否依赖于脚本中的其他进程失败。

我试过使用一个docker-entrypoint.sh看起来像这样的脚本:

#!/bin/bash

exec "$@"

而且由于这也失败了,我认为这排除了脚本内部出现的其他问题是导致失败的原因。

同样令人沮丧的是,没有来自docker service logs test或的日志docker logs [container_id],而且我似乎在docker inspect [container_id].

我很难理解每个人对exec "$@". 我不想诉诸于使用类似的东西tail -f /dev/null或使用命令 at docker run。我希望有一些一致、可靠的方式,docker-entrypoint.sh脚本可以可靠地用于启动服务,我也可以使用这些服务来运行docker run其他服务,但即使在 Docker 的官方博客和这里的无数问题以及来自其他站点的博客上,我似乎无法找到一个可以工作的例子。

我真的很感激能深入了解我在这里所缺少的东西。

4

2 回答 2

1

$@ 只是命令行参数的字符串。您没有提供任何内容,因此它正在执行一个空字符串。退出并将杀死码头工人。但是, exec 命令将始终退出正在运行的脚本——它会破坏当前的 shell 并启动一个新的 shell,它不会让它继续运行。

我认为您想要做的是以递归方式继续调用此脚本。要真正让脚本调用本身,该行将是:

exec $0

$0 是 bash 文件的名称(或函数名称,如果在函数中)。在这种情况下,它将是您的脚本的名称。

另外,我很好奇您不想使用 tail -f /dev/null 吗?以尽可能快的速度一遍又一遍地创建一个新的 shell 并不能提高性能。我猜你希望这个脚本一遍又一遍地运行来检查你的 if 条件。

在这种情况下,while(1) 循环可能会起作用。

于 2019-08-09T01:56:23.713 回答
1

原则上,您展示的内容应该可以工作,并且是标准的 Docker 模式之一。

ENTRYPOINT和之间的交互CMD非常简单。如果两者都提供,则主容器进程是ENTRYPOINT(或docker run --entrypoint)指定的任何内容,并且它作为参数传递CMD(或末尾的命令docker run)。在这种情况下,结束入口点脚本exec "$@"只是意味着“将我替换CMD为主容器进程”。

所以,这里的模式是

  1. 做一些初始设置,比如chown创建一个可能是外部的数据目录;然后
  2. exec "$@"运行作为命令传递的任何内容。

在您的示例中,有几件事值得检查;它不会如图所示运行。

无论您提供什么,都ENTRYPOINT需要遵守可执行命令的通常规则:如果它是一个裸命令,它必须在$PATH; 它必须在其文件权限中设置可执行位;如果它是一个脚本,它的解释器也必须存在;如果它是二进制文件,则它必须是静态链接的,或者它的所有共享库依赖项必须已经在映像中。对于您的脚本,如果还没有,您可能需要使其可执行

RUN chmod +x /usr/local/bin/docker-entrypoint.sh

此设置的另一件事是(绝对)如果ENTRYPOINT退出,则整个容器退出,并且 Bourne shellset -e指令告诉脚本在任何错误时退出。在问题中的工件中,gosu不是debian基本映像的标准部分,因此您的入口点将失败(并且您的容器将退出)尝试运行该命令。(但这不会影响非常简单的情况。)

最后,如果您在 Docker Swarm 或 Kubernetes 等编排系统下运行容器时遇到问题,您的第一步应该是在本地、前台运行相同的容器:docker run不使用该-d选项并查看它打印出来的内容。例如:

% docker build .
% docker run --rm c5fb7da1c7c1
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"docker-entrypoint.sh\": executable file not found in $PATH": unknown.
ERRO[0000] error waiting for container: context canceled 
% chmod +x docker-entrypoint.sh
% docker build .
% docker run --rm f5a239f2758d
/usr/local/bin/docker-entrypoint.sh: line 3: exec: postgres: not found

(使用问题中的Dockerfile和短docker-entrypoint.sh,并使用docker build .这些docker run命令中的最终图像 ID。)

于 2019-08-09T14:18:53.307 回答