Docker中的ENTRYPOINT与CMD
source link: https://note.qidong.name/2017/11/docker-entrypoint-cmd/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Docker中的ENTRYPOINT与CMD
2017-11-10 10:18:10 +08 字数:1891 标签: Docker
记住两点,就可以完全理解这两个关键字相关的所有用法与现象。
- ENTRYPOINT的默认值相当于是
/bin/sh
。(只是『相当于』。) - 容器的执行入口为
ENTRYPOINT CMD
。
相关概念 ¶
每个Dockerfile写到最后,都需要指定一个需要执行的命令,及其参数。 一个Docker容器,需要有且仅有一个前台进程在运行。 一旦这个进程结束了,那么容器本身的运行也就终结了。 而Dockerfile最后指定的这个命令,就是Docker容器的前台进程。
指定的方法,一般有两种,ENTRYPOINT与CMD。 二者表面上看不出区别,实际上却有巨大差异,也有内在联系。
每个Docker容器,都必须要有一个可执行(executable)文件或命令、及相关参数,作为执行入口(entrypoint)。
所以,ENTRYPOINT和CMD,二者在Dockerfile与docker run
里,至少指定一个。
在执行docker run args... <image> cmd...
时,镜像名称<image>
后的所有内容,都被看做CMD。
它会覆盖镜像中写好的CMD(如果有的话)。
如果使用docker run --entrypoint /bin/bash <image> cmd
,可以复写ENTRYPOINT为/bin/bash
。
使用区别 ¶
使用ENTRYPOINT和CMD的方式,大概分两种。
一是Dockerfile,二是docker run
。
还有docker-compose.yml,其实和docker run
差不多。
Dockerfile ¶
No ENTRYPOINT ENTRYPOINT entry arg0 ENTRYPOINT [“entry”, “arg0”] No CMD error, not allowed /bin/sh -c entry arg0 entry arg0 CMD [“cmd”, “arg1”] cmd arg1 /bin/sh -c entry arg0 entry arg0 cmd arg1 CMD cmd arg1 /bin/sh -c cmd arg1 /bin/sh -c entry arg0 entry arg0 /bin/sh -c cmd arg1上表源于官方文档中的Understand how CMD and ENTRYPOINT interact,有所简化。 (原文应该是个中国人写的,竟然还用中文的引号!)
- ENTRYPOINT和CMD至少要有一个。
- 使用
ENTRYPOINT entry arg0
形式,与CMD将没有任何配合。因此,除非特定需求,否则不推荐这种使用方式。 - 右下角
entry arg0 /bin/sh -c cmd arg1
这种形式,几乎没有什么使用场景,反而是常见错误,应该尽量避免。
本质上,其实可以理解为ENTRYPOINT是真正的Docker可执行入口,而CMD则是可选参数。 之所以在很多情况下直接写CMD也能生效,是因为ENTRYPOINT就相当于是指定Shell,而CMD则是指定Shell中执行的命令。 注意,只是『相当于』。
docker run与docker-compose.yml ¶
在docker run <image> cmd arg1
时,总是相当于CMD的["cmd", "arg1"]
形式。
此外,docker-compose.yml的情况与docker run
类似。
在docker run
中使用--entrypoint
参数时,限制非常大。
仅仅只能指定一个命令、或可执行文件,不能指定一个参数列表。
例如:
$ docker run --entrypoint ls alpine /etc/passwd
/etc/passwd
$ docker run --entrypoint ls alpine -l /etc/passwd
-rw-r--r-- 1 root root 1224 Apr 24 2017 /etc/passwd
这时,如果希望把-l
参数放到--entrypoint
中,则无法做到。
(一些早期版本似乎是可以的。)
$ docker run --entrypoint 'ls -l' alpine /etc/passwd
container_linux.go:262: starting container process caused "exec: \"ls -l\": executable file not found in $PATH"
docker: Error response from daemon: oci runtime error: container_linux.go:262: starting container process caused "exec: \"ls -l\": executable file not found in $PATH".
ERRO[0001] error waiting for container: context canceled
在--entrypoint
中,无法指定一个列表。
不过,docker-compose.yml文件中,倒是可以。
image: alpine
entrypoint:
- ls
- -l
command: /etc/passwd
注意PID ¶
原则上,一个Docker容器里应该只有一个进程,其PID为1。
Docker外部的操作,比如docker stop
,就是向这个进程发送信号。
如果那个唯一的前台进程PID不为1,那么就会收不到信号,只能在超时(默认约10秒)后被kill。
在Dockerfile中使用ENTRYPOINT entry arg0
这种形式时,entry
的位置总是应该使用exec
,后面再接其它内容。
比如,ENTRYPOINT exec top
,这可以确保top
命令是PID为1的进程。
否则,ENTRYPOINT top
的形式,PID为1的进程就是/bin/sh -c top
,而top
则被挤到了另外一个进程。
例如,对一个如下的Dockerfile:
FROM alpine
ENTRYPOINT top
执行以下的build与run操作:
docker build -t top .
docker run --rm -it --name test top
在另一个Shell中,可以查看到以下结果:
$ docker exec test ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh -c top
7 root 0:00 top
8 root 0:00 ps
$ time docker stop test
real 0m10.774s
user 0m0.008s
sys 0m0.004s
如果换成ENTRYPOINT exec top
,或者ENTRYPOINT ["top"]
,就可以避免这个问题。
Docker版本 ¶
本文中描述的部分内容,在早期的Docker版本中并不正确。 撰写本文时,测试用的Docker版本信息如下。
$ docker version
Client:
Version: 17.10.0-ce
API version: 1.33
Go version: go1.8.3
Git commit: f4ffd25
Built: Tue Oct 17 19:02:43 2017
OS/Arch: linux/amd64
Server:
Version: 17.10.0-ce
API version: 1.33 (minimum version 1.12)
Go version: go1.8.3
Git commit: f4ffd25
Built: Tue Oct 17 19:01:22 2017
OS/Arch: linux/amd64
Experimental: false
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK