Dockerfile参考(12) – ENTRYPOINT配置创建容器后执行的容器命令

ENTRYPOINT有两种形式:

  • ENTRYPOINT [“executable”, “param1”, “param2”] [exec形式,首选]
  • ENTRYPOINT command param1 param2 [shell形式]
  • ENTRYPOINT指令用来配置创建容器时执行的容器命令。
    例如,下面的示例将以默认页启动nginx,在80端口监听:

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

    docker run [image]的命令行参数会附加到exec形式ENTRYPOINT所有元素的后面,且会覆盖使用CMD指定的所有元素。这允许命令行参数能够传递到entry point。如docker run [image] -d会传递-d参数到entry point。你可以你使用docker run –entrypoint标志来覆盖ENTRYPOINT指令。
    shell形式的ENTRYPOINT能够阻止使用任何CMD或run命令行参数,不过不好的地方是ENTRYPOINT将以/bin/sh -c的子命令执行,且ENTRYPOINT收不到信号。意味着执行的命令的PID不是容器的PID 1 – 收不到来自主机的Unix信号 – 所以无法使用docker stop [container]停止容器。
    仅是Dockerfile的最后一个ENTRYPOINT指令起作用。

    exec形式ENTRYPOINT示例

    你可以使用ENTRYPOINT的exec形式设置稳定的默认命令和参数,然后使用同样形式的CMD设置额外的可以修改的默认参数。

    1. FROM ubuntu
    2. ENTRYPOINT ["top", "-b"]
    3. CMD ["-c"]

    当你运行容器,你会看到top是唯一的进程:

    1. $ docker run -it --rm --name test  top -H
    2. top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
    3. Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
    4. %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
    5. KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
    6. KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem
    7.  
    8.   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    9.     1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

    我们再看到top的具体参数:

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

    并且可以使用docker stop test来停止这个容器。
    下面的Dockerfile显示了使用ENTRYPOINT来在前台运行Apache[作为PID 1运行]:

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

    如果你需要为单个可执行程序编辑一个启动脚本,你可以使用exec和gosu命令来确保最终的执行程序能收到Unix信号:

    1. #!/bin/bash
    2. set -e
    3.  
    4. if [ "$1" = 'postgres' ]; then
    5.     chown -R postgres "$PGDATA"
    6.  
    7.     if [ -z "$(ls -A "$PGDATA")" ]; then
    8.         gosu postgres initdb
    9.     fi
    10.  
    11.     exec gosu postgres "$@"
    12. fi
    13.  
    14. exec "$@"

    最后,如果你需要在关闭或协调多个可执行程序时做些额外的清理工作,你需要确保ENTRPOINT脚本能够收到Unix信号,捕获它们并做些额外的工作:

    1. #!/bin/sh
    2. # Note: I've written this using sh so it works in the busybox container too
    3.  
    4. # USE the trap if you need to also do manual cleanup after the service is stopped,
    5. #     or need to start multiple services in the one container
    6. trap "echo TRAPed signal" HUP INT QUIT TERM
    7.  
    8. # start service in background here
    9. /usr/sbin/apachectl start
    10.  
    11. echo "[hit enter key to exit] or run 'docker stop <container>'"
    12. read
    13.  
    14. # stop service and clean up here
    15. echo "stopping apache"
    16. /usr/sbin/apachectl stop
    17.  
    18. echo "exited $0"

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

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

    注意:你可以使用–entrypoint来覆盖ENTRPOINT的设置,不过仅可以二进制到exec,如/usr/sbin/apache2 -k start[不仅调用sh -c执行]

    shell形式ENTRYPOINT示例

    可以为ENTRYPOINT指定一个纯字符串,它将运行在/bin/sh -c。这种形式将使用shell处理shell环境变量替换,将忽略任何的CMD或docker run命令行参数。为了确保docker stop能够正确发送信号到ENTRPOINT的可执行程序,记得使用exec执行:

    1. FROM ubuntu
    2. ENTRYPOINT exec top -b

    运行这个镜像后,将会看到这个进程的PID为1:

    1. $ docker run -it --rm --name test top
    2. Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
    3. CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
    4. Load average: 0.08 0.03 0.05 2/98 6
    5.   PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    6.     1     0 root     R     3164   0%   0% top -b

    且可以使用docker stop停止进程:

    1. $ /usr/bin/time docker stop test
    2. test
    3. real    0m 0.20s
    4. user    0m 0.02s
    5. sys 0m 0.04s

    如果忘记使用exec执行命令:

    1. FROM ubuntu
    2. ENTRYPOINT top -b
    3. CMD --ignored-param1

    然后运行:

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

    可以看到top进程的PID为是1了。
    并且使用docker stop test不能停止进程:

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

    ENTRYPOINT和CMD使用建议

    1.Dockerfile应该至少指定一个CMD或ENTRYPOINT指令。
    2.当使用容器作为可执行程序时,应该定义ENTRYPOINT。
    3.CMD应该用来设置ENTRYPOINT的默认参数。
    4.当运行容器带有额外参数时,将会覆盖CMD的参数。

    标签:容器Docker 发布于:2019-11-19 21:45:04