Dockerfile 之 ENTRYPOINT

Posted 秋风小凉鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dockerfile 之 ENTRYPOINT相关的知识,希望对你有一定的参考价值。

ENTRYPOINT入口点有两种形式:

  • ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
  • ENTRYPOINT command param1 param2 (shell form)

ENTRYPOINT 允许您配置将作为可执行文件运行的容器。

例如,下面将启动nginx的默认内容,监听端口80:

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

docker run <image> 的命令行参数将追加到 exec form  ENTRYPOINT中的所有元素之后,并将覆盖使用CMD指定的所有元素。这允许参数被传递到入口点,即 docker run <image> -d 将把-d参数传递给入口点。您可以使用  docker run --entrypoint  标志覆盖ENTRYPOINT指令。

shell form 可以防止使用任何CMD或run命令行参数,但是有一个缺点,即您的入口点将作为/bin/sh -c的子命令启动,该命令不传递信号。这意味着可执行文件不是容器的PID 1,也不会收到Unix信号,所以你的可执行文件不会收到来自docker stop <container>的SIGTERM。

只有Dockerfile中的最后一条ENTRYPOINT指令才会起作用。

一、exec form 的ENTRYPOINT 例子

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

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

当你运行容器,你可以看到顶部是唯一的进程:

$ docker run -it --rm --name test  top -H
top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 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测试优雅地请求top关闭。

下面的Dockerfile展示了如何使用ENTRYPOINT在前台运行Apache(即, as 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脚本接收到Unix信号,然后将它们传递下去,然后再做一些工作:

#!/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 <container>'"
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)。

 

二、 了解CMD和ENTRYPOINT是如何交互的

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

  • Dockerfile应该指定至少一个CMD或ENTRYPOINT命令。
  • 在将容器用作可执行文件时,应该定义ENTRYPOINT。
  • CMD应该用作定义ENTRYPOINT命令的默认参数或在容器中执行特别命令的方法。
  • 当运行带有可选参数的容器时,CMD将被覆盖。

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

 No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]
No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”]p1_cmd p2_cmd/bin/sh -c exec_entry p1_entryexec_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_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

 

 

以上是关于Dockerfile 之 ENTRYPOINT的主要内容,如果未能解决你的问题,请参考以下文章

Dockerfile 中的 CMD 和 ENTRYPOINT 有啥区别?

Dockerfile中CMD命令和ENTRYPOINT 命令的说明

Dockerfile中CMD和ENTRYPOINT的用法

Dockerfile 中 CMD 和ENTRYPOINT 的区别

dockerfile:如何使用基础镜像中的 CMD 或 ENTRYPOINT

Dockerfile 中的 CMD 与 ENTRYPOINT