008-Dockerfile-ENTRYPOINT

语法

语法 1

ENTRYPOINT ["executable", "param1", "param2"] (exec 形式,推荐)

语法 2

ENTRYPOINT command param1 param2 (shell 形式)

作用 & 描述

    ENTRYPOINT 允许你配置容器的可执行文件运行容器。

例如: 以下将使用其默认 content 启动 nginx,侦听 80 端口:

docker run -i -t --rm -p 80:80 nginx

docker run 的命令行参数将附加在 exec 形式的 ENTRYPOINT 后,并将覆盖使用 CMD 指定的所有元素。这允许将参数传递给入口点。你可以使用 docker run --entrypoint flag 覆盖 ENTRPOINT 指令。

shell 形式可以防止使用任何 CMD 或运行命令行参数,但缺点是 ENTRYPOINT 将作为 /bin/sh -c 的子命令启动,它不传递信号。这意味着可执行文件不是容器的 PID 1 - 并且不会收到 Unix 信号 - 因此你的可执行文件不会从 docker stop 接收 SIGTERM。

只有 Dockerfile 中的最后一个 ENTRYPOINT 指令才会生效。

Exec 形式 ENTRYPOINT 示例

你可以使用 ENTRYPOINT 形式设置相当稳定的默认命令和参数,然后使用任一形式的 CMD 来设置可能更改的其它默认值。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

运行容器时,你可以看到 top 是唯一的进程。
要进一步检查结果,可以使用 docker exec:

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux

你可以优雅地请求使用 docker stop test 来关闭 top
以下 Dockerfile 显示使用 ENTRYPOINT 在前台运行 Apache(即,作为 PID 1):

FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

如果需要为单个可执行文件编写启动脚本,可以使用 exec 和 gosu 命令确保最终的可执行文件接收 Unix 信号:

#!/usr/bin/env 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 "$@"

最后,如果你需要在关机时进行一些额外的清理(或与其它容器通信),或者协调多个可执行文件,你可能需要确保 ENTRYPOINT 脚本接收 UNinx 信号,传递它们,然后做了一些工作:

#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too

# USE the trap if you need to also do manual cleanup after the service is stopped,
#     or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM

# start service in background here
/usr/sbin/apachectl start

echo "[hit enter key to exit] or run 'docker stop '"
read

# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop

echo "exited $0"

如果你使用 docker run -it --rm -p 80:80 --name test apache 运行这个镜像,你可以用 docker exec 或 docker top 检查容器的进程,然后让脚本停止 Apache:

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
$ docker top test
PID                 USER                COMMAND
10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054               root                /usr/sbin/apache2 -k start
10055               33                  /usr/sbin/apache2 -k start
10056               33                  /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real	0m 0.27s
user	0m 0.03s
sys	0m 0.03s

注意:

你可以使用 --entrypoint 覆盖 ENTRYPOINT 设置,但这只能将二进制设置为 exec(不使用 sh -c)

注意:

exec 形式被解析为 JSON 数组,这意味着你使用双引号(")来围绕单词而不是单引号(’)

注意:

与 shell 表单不同,exec 形式不会调用 shell 命令。这意味着不会发生正常的 shell 处理。例如,ENTRYPOINT [“echo”, “$HOME”] 不会对 $HOME 执行变量替换。如果你想要 shell 处理,那么要么使用 shell 形式,要么直接执行 shell,例如: ENTRYPOINT [“sh”, “-c”, “echo $HOME”]。当使用 exec 形式并直接执行 shell 时(如果shell形式的情况),它是执行环境变量扩展的 shell,而不是 docker。

shell 形式 ENTRYPOINT 示例

你可以为 ENTRYPOINT 指定一个纯字符串,它将在 /bin/sh -c 中执行。此形式将使用 shell 处理来替换 shell 环境变量,并将忽略任何 CMD 或docker运行命令行参数。要确保docker stop能正确发出任何长时间运行的ENTRYPOINT可执行文件,你需要记住用 exec 启动它:

FROM ubuntu
ENTRYPOINT exec top -b

运行此镜像时,你讲看到单个 PID 1 进程.
使用 docker stop 可以干净的退出:

$ /usr/bin/time docker stop test
test
real	0m 0.20s
user	0m 0.02s
sys	0m 0.04s

如果您忘记将exec添加到ENTRYPOINT的开头:

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1

然后,您可以运行它(为下一步命名):

$ docker run -it --name test top --ignored-param2
Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
Load average: 0.01 0.02 0.05 2/101 7
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
    7     1 root     R     3164   0%   0% top -b

您可以从top的输出中看到指定的ENTRYPOINT不是PID 1。
如果然后运行docker stop test,容器将不会干净地退出 - stop命令将被强制在超时后发送SIGKILL:

$ docker exec -it test ps aux
PID   USER     COMMAND
    1 root     /bin/sh -c top -b cmd cmd2
    7 root     top -b
    8 root     ps aux
$ /usr/bin/time docker stop test
test
real	0m 10.19s
user	0m 0.04s
sys	0m 0.03s

了解CMD和ENTRYPOINT如何相互作用

CMD 和 ENTRYPOINT 指令都定义了在运行容器时执行的命令。 很少有规则描述他们的合作。

1. Dockerfile 应至少指定一个 CMD 或 ENTRYPOINT 命令。
2. 使用容器作为可执行文件时,应定义 ENTRYPOINT。
3. CMD 应该用作为 ENTRYPOINT 命令定义默认参数或在容器中执行 ad-hoc 命令的方法。
4. 使用备用参数运行容器时,将覆盖 CMD。

下表显示了针对不同 ENTRYPOINT/CMD 组合执行的命令:

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

你可能感兴趣的:(Dockerfile,Docker)