本文共两篇,很好的说明了“CMD”“ ENTRYPOINT”的用法

转载:https://blog.csdn.net/u010900754/article/details/78526443

第一篇
cmd:

这个命令是用来做什么的?下面是官网的答案:
The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.

意思是,cmd给出的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行的命令。重点就是这个“默认”。意味着,如果docker run没有指定任何的执行命令或者dockerfile里面也没有entrypoint,那么,就会使用cmd指定的默认的执行命令执行。同时也从侧面说明了entrypoint的含义,它才是真正的容器启动以后要执行命令。

所以这句话就给出了cmd命令的一个角色定位,它主要作用是默认的容器启动执行命令。(注意不是“全部”作用)

这也是为什么大多数网上博客论坛说的“cmd会被覆盖”,其实为什么会覆盖?因为cmd的角色定位就是默认,如果你不额外指定,那么就执行cmd的命令,否则呢?只要你指定了,那么就不会执行cmd,也就是cmd会被覆盖。
  
  明白了cmd命令的主要用途。下面就看看具体用法。
  总共有三种用法:
  
  1 CMD [“executable”,“param1”,“param2”] (exec form, this is the preferred form)
  2 CMD [“param1”,“param2”] (as default parameters to ENTRYPOINT)
  3 CMD command param1 param2 (shell form)
  
因为还没有讲entrypoint,所以先不看用法2

用法3:shell form,即没有中括号的形式。那么命令command默认是在 /bin/sh -c下执行的。

比如下面的dockerfile:
# vi Dockerfile
FROM ubuntu:18.04
CMD echo “hello cmd!”
#
# docker build -t hello .
# docker run hello
hello cmd!

用法1:带有中括号的形式。这时,命令没有再任何shell终端环境下,如果我们要执行shell,必须把shell加入到中括号的参数中。这种用法就像一个c语言的exec函数,意思是我们要执行一个进程。如果采用非shell的方法,那么上面的例子要修改为:
# vi Dockerfile
FROM ubuntu:18.04
CMD ["/bin/bash", “-c”, “echo ‘hello2 cmd!’”]
#
# docker build -t hello2 .
# docker run hello2
hello2 cmd!

需要注意,采用中括号形式,那么第一个参数必须是命令的全路径才行。而且,一个dockerfile至多只能有一个cmd,如果有多个,只有最后一个生效。官网推荐采用这种方法。

当然,以上都是体现了cmd的“默认”行为。如果我们在run时指定了命令或者有entrypoint,那么cmd就会被覆盖。仍然是上面的image。run命令变了:

# docker run hello2 echo abcdefg
abcdefg

可以看到,最终容器里面执行的是run命令后面的命令,而不是cmd里面定义的。

entrypoint:

An ENTRYPOINT allows you to configure a container that will run as an executable.

也就是说entrypoint才是正统地用于定义容器启动以后的执行体的,其实我们从名字也可以理解,这个是容器的“入口”。

有两种用法:
  1 ENTRYPOINT [“executable”, “param1”, “param2”] (exec form, preferred)
  2 ENTRYPOINT command param1 param2 (shell form)

命令行shell

先看命令行模式,也就是带中括号的。和cmd的中括号形式是一致的,但是是在shell的环境下执行的,与cmd(不在shell的环境下运行)有区别。如果run命令后面有东西,那么后面的全部都会作为entrypoint的参数。如果run后面没有额外的东西,但是cmd有,那么cmd的全部内容会作为entrypoint的参数,这同时是cmd的第二种用法。这也是网上说的entrypoint不会被覆盖。当然如果要在run里面覆盖,也是有办法的,使用–entrypoint即可。

下面看几个例子。
# vi Dockerfile
FROM ubuntu:18.04
CMD [“p in cmd”]
ENTRYPOINT [“echo”]

#
# docker build -t hello3 .

如果run不带参数:
# docker run hello3
p in cmd

如果run带参数:
# docker run hello3 abcdefg
abcdefg

而且,确实entrypoint的中括号形式下,command是在shell环境下运行的,否则这里的echo是无法被执行的。

第二种是shell模式的。在这种模式下,任何run和cmd的参数都无法被传入到entrypoint里。官网推荐第一种用法。

修改文件:
# vi Dockerfile
FROM ubuntu:18.04
CMD [“p in cmd”]
ENTRYPOINT echo

#
# docker build -t hello4 .

如果run不带参数:
# docker run hello4

如果run带参数:
# docker run hello4 abcdefg

cmd的参数没有被打印。

总结下一般该怎么使用:一般还是会用entrypoint的中括号形式作为docker 容器启动以后的默认执行命令,里面放的是不变的部分,可变部分比如命令参数可以使用cmd的形式提供默认版本,也就是run里面没有任何参数时使用的默认参数。如果我们想用默认参数,就直接run,否则想用其他参数,就run 里面加参数。

第二篇

转载:https://www.jb51.net/article/136264.htm

前言

CMD 和 ENTRYPOINT 指令都是用来指定容器启动时运行的命令。

单从功能上来看,这两个命令几乎是重复的。单独使用其中的一个就可以实现绝大多数的用例。但是既然 doker 同时提供了它们,为了在使用中不至于混淆,本文试图把它们的用法理清楚。下面话不多说了,来一起看看详细的介绍吧。

exec 模式和 shell 模式

CMD 和 ENTRYPOINT 指令都支持 exec 模式和 shell 模式的写法,所以要理解 CMD 和 ENTRYPOINT 指令的用法,就得先区分 exec 模式和 shell 模式。这两种模式主要用来指定容器中的不同进程为 1 号进程。了解 linux 的朋友应该清楚 1 号进程在系统中的重要地位。笔者也在《在 docker 容器中捕获信号》一文中介绍过 1 号进程对容器中信号处理的重要性,感兴趣的朋友可以移步这里进行了解。下面我们通过 CMD 指令来学习 exec 模式和 shell 模式的特点。

exec 模式

使用 exec 模式时,容器中的任务进程就是容器内的 1 号进程,看下面的例子:

FROM ubuntu:18.04
CMD [ “top” ]

把上面的代码保存到 test1 目录的 Dockerfile 中,然后进入 test1 目录构建镜像并启动一个容器:

$ docker build -t test1 .
$ docker run -idt --name testcon test1

然后查看容器中的进程 ID:

$ docker exec testcon ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.0 36592 3040 ? Ss+ 02:06 0:00 top
root 7 0.0 0.0 34396 2808 ? Rs 02:06 0:00 ps aux

从图中我们看到运行 top 命令的进程 ID 为 1。

exec 模式是建议的使用模式,因为当运行任务的进程作为容器中的 1 号进程时,我们可以通过 docker 的 stop 命令优雅的结束容器(详情请参考《在 docker 容器中捕获信号》)。

exec 模式的特点是不会通过 shell 执行相关的命令,所以像 $HOME 这样的环境变量是取不到的:

FROM ubuntu:18.04
CMD [ “echo”, “$HOME” ]

把上面的代码保存到 test1 目录的 Dockerfile 中,然后进入 test1 目录构建镜像并启动一个容器:

$ docker build --no-cache -t test1 .
$ docker run --rm test1
$HOME

通过 exec 模式执行 shell 可以获得环境变量:

FROM ubuntu:18.04
CMD [ “sh”, “-c”, “echo $HOME” ]

把上面的代码保存到 test1 目录的 Dockerfile 中,然后进入 test1 目录构建镜像并启动一个容器:

$ docker build --no-cache -t test1 .
$ docker run --rm test1
/root

这次正确取到了 $HOME 环境变量的值。

shell 模式

使用 shell 模式时,docker 会以 /bin/sh -c “task command” 的方式执行任务命令。也就是说容器中的 1 号进程不是任务进程而是 bash 进程,看下面的例子:

FROM ubuntu:18.04
CMD top

把上面的代码保存到 test2 目录的 Dockerfile 中,然后进入 test2 目录构建镜像并启动一个容器:

$ docker build -t test2 .
$ docker run -itd --name testcon2 test2

然后查看容器中的进程 ID:

$ docker exec testcon2 ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.0 4624 868 ? Ss+ 02:39 0:00 /bin/sh -c top
root 7 0.0 0.0 36592 3012 ? S+ 02:39 0:00 top
root 8 0.0 0.0 34396 2836 ? Rs 02:39 0:00 ps aux

1 号进程执行的命令居然是/bin/sh -c top。而我们指定的 top 命令的进程 ID 为 7。这是由 docker 内部决定的,目的是让我们执行的命令或者脚本可以取到环境变量。

CMD 指令

CMD 指令的目的是:为容器提供默认的执行命令。

CMD 指令有三种使用方式,其中的一种是为 ENTRYPOINT 提供默认的参数:

CMD [“param1”,“param2”]

另外两种使用方式分别是 exec 模式和 shell 模式:

CMD [“executable”,“param1”,“param2”] // 这是 exec 模式的写法,注意需要使用双引号。
CMD command param1 param2 // 这是 shell 模式的写法。

注意命令行参数可以覆盖 CMD 指令的设置,但是只能是重写,却不能给 CMD 中的命令通过命令行传递参数。
一般的镜像都会提供容器启动时的默认命令,但是有些场景中用户并不想执行默认的命令。用户可以通过命令行参数的方式覆盖 CMD 指令提供的默认命令。比如通过下面命令创建的镜像:

FROM ubuntu:18.04
CMD [ “top” ]

在启动容器时我们通过命令行指定参数 ps aux 覆盖默认的 top 命令:

$ docker build --no-cache -t test1 .
$ docker run -idt --name testcon test1
$ docker exec testcon ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 36592 3196 ? Ss+ 03:13 0:00 top
root 7 0.0 0.0 34396 2812 ? Rs 03:15 0:00 ps aux

$ docker run --rm test1 ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 25940 1544 ? Rs 03:21 0:00 ps aux

从上图可以看到,命令行上指定的 ps aux 命令覆盖了 Dockerfile 中的 CMD [ “top” ]。实际上,命令行上的命令同样会覆盖 shell 模式的 CMD 指令。

ENTRYPOINT 指令

ENTRYPOINT 指令的目的也是为容器指定默认执行的任务。

ENTRYPOINT 指令有两种使用方式,就是我们前面介绍的 exec 模式和 shell 模式:

ENTRYPOINT [“executable”, “param1”, “param2”] // 这是 exec 模式的写法,注意需要使用双引号。
ENTRYPOINT command param1 param2 // 这是 shell 模式的写法。

exec 模式和 shell 模式的基本用法和 CMD 指令是一样的,下面我们介绍一些比较特殊的用法。

指定 ENTRYPOINT 指令为 exec 模式时,命令行上指定的参数会作为参数添加到 ENTRYPOINT 指定命令的参数列表中。用下面的代码构建镜像 test1:

FROM ubuntu:18.04
ENTRYPOINT [ “top”, “-b” ]

运行下面的命令:

$ docker build --no-cache -t test1 .
$ docker run --rm test1 -c
top - 03:31:59 up 2:18, 0 users, load average: 0.19, 0.15, 0.10
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 0.2 sy, 0.0 ni, 99.4 id, 0.1 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16383348 total, 13349388 free, 1883336 used, 1150624 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 14059300 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 36480 3024 2676 R 0.0 0.0 0:00.06 top -b -c

我们在命令行上添加的参数被追加到了 top 命令的参数列表中(top -b -c)。

由 CMD 指令指定默认的可选参数:

FROM ubuntu
ENTRYPOINT [ “top”, “-b” ]
CMD [ “-c” ]

使用这段代码构建镜像 test2 并不带命令行参数启动容器:

$ docker build --no-cache -t test2 .
$ docker run --rm test2
top - 03:37:48 up 2:24, 0 users, load average: 0.37, 0.13, 0.10
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 5.4 us, 1.8 sy, 0.0 ni, 92.0 id, 0.6 wa, 0.0 hi, 0.3 si, 0.0 st
KiB Mem : 16383348 total, 13342380 free, 1889964 used, 1151004 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 14052664 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 36480 3068 2712 R 0.0 0.0 0:00.04 top -b -c

这时容器中运行的命令为:top -b -c。

如果我们指定命令行参数:

$ docker run --rm test2 -n 1
top - 03:38:46 up 2:25, 0 users, load average: 0.28, 0.14, 0.10
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.0 us, 0.5 sy, 0.0 ni, 97.8 id, 0.7 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16383348 total, 13341072 free, 1891212 used, 1151064 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 14051396 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 36480 3048 2700 R 0.0 0.0 0:00.04 top

-n 1 会覆盖 通过 CMD [ “-c” ] 指定的参数,容器执行的命令为:top -b -n 1
注意上图的输出显示 -c 参数被覆盖了。

指定 ENTRYPOINT 指令为 shell 模式时,会完全忽略命令行参数

FROM ubuntu:18.04
ENTRYPOINT echo $HOME

把上面的代码编译成镜像 test2,分别不带命令行参数和使用命令行参数 ls 执行命令:

$ docker build --no-cache -t test2 .
$ docker run --rm test2
/root
$ docker run --rm test2 ls
/root

我们看到 ls 命令没有被执行,这说明命令行参数被 ENTRYPOINT 指令的 shell 模式忽略了。

覆盖默认的 ENTRYPOINT 指令:

ENTRYPOINT 指令也是可以被命令行覆盖的,只不过不是默认的命令行参数,而是需要显式的指定 --entrypoint 参数。比如我们通过下面的方式覆盖上面镜像中的 echo $HOME 命令:

$ docker run --rm --entrypoint hostname test2
706d6acdc3e4

这里我们使用 hostname 命令覆盖了默认的 echo $HOME 命令。

Dockerfile 中至少要有一个

如果镜像中既没有指定 CMD 也没有指定 ENTRYPOINT 那么在启动容器时会报错。这不算是什么问题,因为现在能见到的绝大多数镜像都默认添加了 CMD 或 ENTRYPOINT 指令。

指定任意一个,效果差不多

从结果上看,CMD 和 ENTRYPOINT 是一样的,我们可以通过它们实现相同的目的。下面我们分别用 CMD 和 ENTRYPOINT 设置 top -b 命令,然后观察容器运行时的 metadata 信息:




虽然实现方式不同,但最终容器运行的命令是一样的。

同时使用 CMD 和 ENTRYPOINT 的情况

对于 CMD 和 ENTRYPOINT 的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMD 为 ENTRYPOINT 提供默认的可选参数。

我们大概可以总结出下面几条规律:

• 如果 ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略。
• 如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数。
• 如果 ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式。

真实的情况要远比这三条规律复杂,好在 docker 给出了官方的解释,如下图所示:
当我们无法理解容器中运行命令的行为时,说不定通过这个表格可以解开疑惑!

总结

对于 Dockerfile 来说,CMD 和 ENTRYPOINT 是非常重要的指令。它们不是在构建镜像的过程中执行,而是在启动容器时执行,所以主要用来指定容器默认执行的命令。但是提供两个功能类似的指令,必然会给用户带来理解上的困惑和使用中的混淆。希望本文能够帮助大家理解二者的区别与联系,并更好的使用二者。

“CMD”“ ENTRYPOINT”详解相关推荐

  1. android route命令详解,route cmd命令详解

    在本地 IP 路由表中显示和修改条目.使用不带参数的 route 可以显示帮助.接下来是小编为大家收集的route cmd命令详解,希望能帮到大家. route cmd命令详解 语法 route [- ...

  2. CMD文件详解与DSP存储空间

    CMD文件详解与DSP存储空间 CMD的全称为链接命令配置文件.以ROM/FLASH和RAM两类存储器为对象,用户通过编写CMD文件,来管理和分配系统中的所有物理存储器和地址空间.DSP芯片的片内存储 ...

  3. java执行cmd命令详解

    前言 Java应用程序主要是通过Runtime和Process两个类来执行cmd命令. Runtime.exec方法创建本机进程并返回Process子类的实例,该实例可用于控制进程并获取有关它的信息. ...

  4. Docker配置Dockerfile中关键ENTRYPOINT和CMD命令详解

    一.dockerfile中的 CMD 1.每个dockerfile中只能有一个CMD如果有多个那么只执行最后一个. 2.CMD 相当于启动docker时候后面添加的参数看,举个简单例子: docker ...

  5. Dockerfile CMD 命令详解

    官网解释:https://docs.docker.com/engine/reference/builder/#cmd 自己翻译: cmd命令的三种格式 CMD ["executable&qu ...

  6. [CMD] DSP CMD文件详解

    目录 1. CMD文件是什么? 2. CMD文件的功能 3. CMD文件的使用方法 MEMORY伪指令--指示存储空间 SECTIONS伪指令--分配段到存储空间 4. 注意事项 1. CMD文件是什 ...

  7. F28335之cmd文件详解

    1.CMD文件的作用 CMD文件的作用就像仓库的货物摆放记录一样,为程序代码和数据分配指定的空间. 2.C语言生成的段 C语言生成的段大致分为两大类:初始化和未初始化,已初始化的段含有真正的指令和数据 ...

  8. TMS320F28335项目开发记录6_28335之cmd文件详解

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接: https://blog.csdn.net/scottly1/article/de ...

  9. Windows学习总结(10)——Windows系统中常用的CMD命令详解

    1.ping命令 ping是电脑网络故障诊断中的常用的命令,它的作用是用来检查网络是否通畅或者网络连接速度.我们来看一下PING命令的具体表述. 日常的诊断过程中我们最常用到的就是诊断连接是否通畅.

最新文章

  1. 【c语言】蓝桥杯算法训练 大等于n的最小完全平方数
  2. 解决:error: Cannot find libmysqlclient_r under /usr/local/mysql.
  3. 使用 soapUI 测试 REST 服务
  4. 如何找到status group里定义的所有status value
  5. 12.8 早晨我一直在假笑,为了骗自己
  6. 【算法】LeetCode算法题-Maximum Subarray
  7. Asp.NetCore轻松学-部署到 IIS 进行托管
  8. 隐藏的东西? 您需要HiddenSidesPane
  9. js函数、作用域和闭包
  10. P2550 [AHOI2001]彩票摇奖
  11. Mysql怎么把8位数变成日期_SQL中如何将数字型转换为日期型
  12. opencv-api getRotationMatrix2D
  13. 微软获 OpenAI 独家 GPT-3 模型授权,为何马斯克炮轰?
  14. 怎么多快好省地学习中文自然语言处理
  15. 结合使用 Oracle Coherence 和 Spring Batch 进行高性能数据处理
  16. 并发编程学习之线程池
  17. 源泉设计cad插件下载 | 含源泉cad插件使用教程
  18. Node.js meitulu图片批量下载爬虫1.04版
  19. mysql全量备份命令_mysql全量备份与增量备份
  20. buildroot 执行 make savedefconfig 错误解决

热门文章

  1. JavaWeb项目 JSP+SQL个人博客系统多人
  2. 战地2(Battlefield 2)全面资料
  3. 如何考虑问题更周全?
  4. python四五事_python函数(四)
  5. 编译警告struct declared inside parameter list
  6. Quard SPI和QPI的区别
  7. php歌声美化_人声美化:人声后期处理方法
  8. qq飞车怎么找回自己的服务器,qq飞车怎样找回装备简单又方便
  9. OpenCascade笔记:gp包
  10. 张晓彤老师--沪师经纪刘建