0


Dockerfile中的CMD和ENTRYPOINT

Shell格式和Exec格式

Dockerfile中,RUNCMDENTRYPOINT指令都可以使用两种格式:Shell格式Exec格式

  • exec 格式INSTRUCTION ["executable","param1","param2"]
  • shell 格式INSTRUCTION command param1 param2

exec格式使得避免使用shell字符串处理成为可能,并且可以使用特定的命令shell或任何其他可执行文件来调用命令。它使用JSON数组语法,数组中的每个元素都是一个命令、标志或参数。

shell格式更加灵活,强调易用性、灵活性和可读性。

在使用shell格式时系统会自动选择一个命令shell来执行指令,而在使用exec格式时,需要明确指定使用哪个命令shell或其他可执行文件来执行命令。换句话说,shell格式会自动选择执行环境,而exec格式需要手动指定执行环境。

Exec 格式

Exec格式被解析为一个JSON数组,这意味着你必须使用双引号(")而不是单引号(')来包围单词。

ENTRYPOINT ["/bin/bash", "-c", "echo hello"]

Exec格式最适合用于指定

ENTRYPOINT

指令,并结合

CMD

来设置可以在运行时覆盖的默认参数。

变量替换

使用Exec格式不会自动调用命令shell。这意味着不会发生常规的shell处理,例如变量替换。例如,

RUN [ "echo", "$HOME" ]

不会处理

$HOME

的变量替换。

如果你想进行shell处理,可以使用Shell格式,或者直接在Exec格式中执行shell,例如:

RUN [ "sh", "-c", "echo $HOME" ]

。当使用Exec格式并直接执行shell时,就像Shell格式一样,是由shell进行环境变量替换,而不是构建器。

反斜杠

在Exec格式中,你必须对反斜杠进行转义。这在Windows上特别重要,因为在Windows中反斜杠是路径分隔符。以下行将因未被视为有效的JSON而被视为Shell格式,并以意外的方式失败:

RUN ["c:\windows\system32\tasklist.exe"]

正确的语法示例是:

RUN ["c:\\windows\\system32\\tasklist.exe"]

Shell 格式

与Exec格式不同,使用Shell格式的指令总是使用命令shell。Shell格式不使用JSON数组格式,而是一个常规的字符串。Shell格式字符串允许你使用转义字符(默认是反斜杠)来换行,将单个指令延续到下一行。这使得它更容易用于更长的命令,因为它允许你将它们分割成多行。例如,考虑以下两行:

RUN source$HOME/.bashrc &&\echo$HOME

它们等同于以下单行:

RUN source$HOME/.bashrc &&echo$HOME

你可以使用heredocs与Shell格式来拆分命令:

RUN <<EOF
source $HOME/.bashrc && \
echo $HOME
EOF

使用不同的shell

你可以使用

SHELL

命令更改默认shell。例如:

SHELL["/bin/bash", "-c"]
RUN echo hello

CMD

CMD

指令设置了在从镜像运行容器时要执行的命令。

你可以使用shell格式或exec格式来指定CMD指令:

  • CMD ["executable","param1","param2"](exec格式)
  • CMD ["param1","param2"](exec格式,作为ENTRYPOINT的默认参数)
  • CMD command param1 param2(shell格式) Dockerfile中只能有一个CMD指令。如果列出多个CMD,只有最后一个会生效。
CMD

的目的是为正在执行的容器提供默认值。这些默认值可以包括一个可执行文件,也可以省略可执行文件,此时你必须同时指定

ENTRYPOINT

指令。

如果你希望容器每次运行时都执行相同的可执行文件,那么你应该考虑结合使用

ENTRYPOINT

CMD

。如果用户在

docker run

中指定了参数,它们将覆盖在

CMD

中指定的默认值,但仍会使用默认的

ENTRYPOINT

如果

CMD

用于为

ENTRYPOINT

指令提供默认参数,则应该以

exec格式

指定

CMD

ENTRYPOINT

指令。

注意

*不要将RUN与CMD混淆。RUN实际上运行一个命令并提交结果;

CMD

不会在构建时执行任何操作,而是为镜像指定预期的命令。*

ENTRYPOINT

ENTRYPOINT

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

ENTRYPOINT

有两种可能的格式:

  • 首选的 exec 格式:
ENTRYPOINT ["executable", "param1", "param2"]
  • shell 格式:
ENTRYPOINT command param1 param2

以下命令从带有默认内容、监听端口 80 的 nginx 启动容器:

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

对于

docker run <image>

的命令行参数将附加在 exec 格式的

ENTRYPOINT

中的所有元素之后,并将覆盖使用

CMD

指定的所有元素。这允许将参数传递给入口点,即

docker run <image> -d

将向入口点传递

-d

参数。您可以使用

docker run --entrypoint

标志覆盖

ENTRYPOINT

指令。

ENTRYPOINT

的 shell 格式阻止使用任何

CMD

命令行参数。它还将您的

ENTRYPOINT

作为

/bin/sh -c

的子命令启动,不会传递信号。这意味着可执行文件不会成为容器的

PID 1

,并且不会接收 Unix 信号。在这种情况下,您的可执行文件不会从

docker stop <container>

接收

SIGTERM

信号。

Dockerfile 中的最后一个 ENTRYPOINT 指令将生效。

Exec 格式的 ENTRYPOINT 示例

您可以使用 exec 格式的

ENTRYPOINT

来设置相对稳定的默认命令和参数,然后使用

CMD

的任一格式来设置更有可能被更改的其他默认值。

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

当您运行容器时,您可以看到top是唯一的进程:

docker run -it--rm--nametesttop-Htop - 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      2001974423362080 R  0.00.10:00.04 top

要进一步检查结果,您可以使用docker exec:

dockerexec-ittestps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         12.60.1197522352 ?        Ss+  08:24   0:00 top-b-H
root         70.00.1155722164 ?        R+   08:25   0:00 ps aux

您可以使用

docker stop test

优雅地请求

top

关闭。

以下Dockerfile显示使用

ENTRYPOINT

在前台运行Apache(即作为

PID 1

):

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

如果您需要为单个可执行文件编写启动脚本,您可以使用

exec

gosu

命令确保最终可执行文件接收Unix信号:

#!/usr/bin/env bashset-eif["$1"='postgres'];thenchown-R postgres "$PGDATA"if[-z"$(ls-A"$PGDATA")"];then
        gosu postgres initdb
    fiexec gosu postgres "$@"fiexec"$@"

最后,如果您需要在关闭时进行一些额外的清理(或与其他容器通信),或者协调多个可执行文件,您可能需要确保

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 containertrap"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 hereecho"stopping apache"
/usr/sbin/apachectl stop

echo"exited $0"

如果您使用

docker run -it --rm -p 80:80 --name test apache

运行此映像,则可以使用

docker exec

docker top

检查容器的进程,然后要求脚本停止Apache:

dockerexec-ittestps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         10.10.04448692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
root        190.00.2713044440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
www-data    200.20.23604686004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
www-data    210.20.23604686000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
root        810.00.1155722140 ?        R+   00:44   0:00 ps aux

dockertoptest

PID                 USER                COMMAND
10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054               root                /usr/sbin/apache2 -k start
1005533                  /usr/sbin/apache2 -k start
1005633                  /usr/sbin/apache2 -k start

/usr/bin/time docker stop testtest
real    0m 0.27s
user    0m 0.03s
sys    0m 0.03s

Shell 格式 ENTRYPOINT 示例

您可以为

ENTRYPOINT

指定一个纯字符串,它将在

/bin/sh-c

中执行。此表单将使用shell处理来替换shell环境变量,并将忽略任何

CMD

docker run

命令行参数。为了确保

docker stop

将正确地发出任何长时间运行的

ENTRYPOINT

可执行文件的信号,您需要记住以exec开头:

FROM ubuntu
ENTRYPOINT exectop-b

当您运行此映像时,您将看到单个

PID 1

进程:

docker run -it--rm--nametesttop

Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
Load average: 0.080.030.052/98 6
  PID  PPIDUSER     STAT   VSZ %VSZ %CPU COMMAND
    10 root     R     31640%   0% top-b

在docker stop上干净地退出:

/usr/bin/time docker stop testtest
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--nametesttop --ignored-param2

top - 13:58:24 up 17 min,  0 users,  load average: 0.00, 0.00, 0.00
Tasks:   2 total,   1 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s): 16.7 us, 33.3 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :1990.8 total,   1354.6 free,    231.4 used,    404.7 buff/cache
MiB Swap:   1024.0 total,   1024.0 free,      0.0 used.   1639.8 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    1 root      2002612604536 S   0.00.00:00.02 sh6 root      200595631882768 R   0.00.20:00.00 top

您可以从

top

的输出中看到指定的

ENTRYPOINT

不是

PID 1

如果您随后运行

docker stop test

,容器将不会干净地退出-

stop

命令将在超时后强制发送

SIGKILL

dockerexec-ittestps waux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         10.40.02612604 pts/0    Ss+  13:58   0:00 /bin/sh -ctop-b --ignored-param2
root         60.00.159563188 pts/0    S+   13:58   0:00 top-b
root         70.00.158842816 pts/1    Rs+  13:58   0:00 ps waux

/usr/bin/time docker stop testtest
real    0m 10.19s
user    0m 0.04s
sys    0m 0.03s

了解CMD和ENTRYPOINT如何交互

CMD

ENTRYPOINT

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

  1. Dockerfile应至少指定一个CMDENTRYPOINT命令。
  2. 将容器用作可执行文件时应定义ENTRYPOINT
  3. CMD应该用作定义ENTRYPOINT命令或在容器中执行 ad-hoc 命令的默认参数的一种方式。
  4. 使用替代参数运行容器时,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_entryCMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmdCMD 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

Note

: *如果从基本图像定义了

CMD

,则设置

ENTRYPOINT

会将

CMD

重置为空值。在这种情况下,必须在当前图像中定义

CMD

才能具有值。*


本文转载自: https://blog.csdn.net/i_love_t/article/details/138470863
版权归原作者 爱尚你1993 所有, 如有侵权,请联系我们删除。

“Dockerfile中的CMD和ENTRYPOINT”的评论:

还没有评论