在此处显示的两种情况下,您都使用 JSON 数组 exec form 来表示 ENTRYPOINT 和 CMD。这意味着不运行任何 shell,除非在第二种情况下显式运行它。这两部分只是combined together into a single command。
第一个构造运行脚本./mybashscript,它必须是可执行的并且有一个有效的“shebang”行(可能是#!/bin/bash)。该脚本传递了三个参数,您可以在 shell 变量 $1、$2 和 $3 中看到它们:分号 ;、flask 和 run。
第二个构造运行/bin/sh -c './mybashscript && flask' run。 sh -c 接受一个参数,即mybashscript && flask;剩余的参数run 被解释为位置参数,sh -c 命令会将其视为$0。
您显示的ENTRYPOINT 和CMD 的任意拆分实际上没有任何意义。两者之间唯一真正重要的区别是,在运行容器时更容易更改CMD,例如将其放在docker run 命令中的图像名称之后。将所有命令放在命令部分或不放在命令部分是有意义的,但实际上将一半命令放在一个部分,一半放在另一个部分。
我在这里的第一关是写:
# no ENTRYPOINT
CMD ./mybashscript && flask run
Docker 将在裸字符串shell form 中为您插入一个sh -c 包装器,因此&& 具有其通常的Bourne-shell 含义。
此设置看起来您正在尝试在主容器命令之前运行初始化脚本。有一个合理的标准模式是为此使用ENTRYPOINT。由于它通过CMD 作为参数传递,脚本可以以exec "$@" 结尾来运行CMD(可能在docker run 命令中被覆盖)。入口点脚本可能看起来像
#!/bin/sh
# entrypoint.sh
./mybashscript
exec "$@"
(如果你写了mybashscript,你也可以用exec "$@" 行结束它,并使用该脚本作为入口点。)
在 Dockerfile 中,将此包装脚本设置为ENTRYPOINT,然后将主命令设置为CMD。
ENTRYPOINT ["./entrypoint.sh"] # must be a JSON array
CMD ["flask", "run"] # can be either form
如果您提供备用命令,它将替换 CMD,因此 exec "$@" 行将运行该命令而不是 Dockerfile 中的命令,但 ENTRYPOINT 包装器仍会运行。
# See the environment the wrapper sets up
docker run --rm your-image env
# Double-check the data directory setup
docker run --rm -v $PWD/data:/data your-image ls -l /data
如果您真的想要使用sh -c 形式和拆分ENTRYPOINT,那么sh -c 中的命令必须读取$@ 才能找到它的位置参数(@987654367 @),另外你需要知道第一个参数是$0 而不是$1。如果您编写,您显示的表单将是有效的
# not really recommended but it would work
ENTRYPOINT ["/bin/sh", "-c", "./mybashscript && flask \"$@\"", "flask"]
CMD ["run"]