关于CMD指令和ENTRYPOINT的区别

关于CMD指令和ENTRYPOINT还有docker run的区别

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 的主要目的是为正在执行的容器提供默认值。 这些默认值可以包含可执行文件,也可以省略可执行文件,在 这种情况下,您还必须指定 ENTRYPOINT 指令。

# 三种用法:
The CMD instruction has three forms:
 
CMD ["executable","param1","param2"] (exec form, this is the preferred form) # 首选
CMD ["param1","param2"] (as default parameters to ENTRYPOINT) # 不包含可执行文件时,需要定义 ENTRUPOINT
CMD command param1 param2 (shell form)  # shell模式

# 解释:
executable 可执行程序
param 参数

例:
# 第一种用法:运行一个可执行的文件并提供参数。
$ cat Dockerfile 
FROM centos

CMD ["/usr/bin/ping","-c","2","baidu.com"]

$ docker run test_ls
# 相当于执行了ping -c 2 baidu.com

-----------------------------------------------------------------------------------------------------

# 第二种用法:为ENTRYPOINT指定参数。
$ cat Dockerfile 
FROM centos

CMD ["123"]

ENTRYPOINT ["/usr/bin/echo"] 
# 相当于 执行了 echo 123。此时,就是CMD的参数传递给了ENTRYPOINT
$ docker  run test_echo
123
# CMD 可以是可执行文件,也可不是,当不是可执行文件时,必须得指定ENTRYPOINT

-----------------------------------------------------------------------------------------------------

# 第三种用法(shell form):是以”/bin/sh -c”的方法执行的命令。
$ cat Dockerfile 
FROM centos
 
CMD echo "hello"

$ docker run test1_echo
hello
# 官方推荐第一种写法

如果docker run没有指定任何命令或者dockerfile里面也没有entrypoint,那么,就会使用cmd指定的默认的执行命令执行。CMD则是启动时需要运行的,可以理解为开机启动。docker run是运行时执行的命令。

一句话总结:如果不额外指定,那就就是执行cmd的命令,只要你指定了,那么就不会执行cmd。

示例:

$ cat Dockerfile 
FROM centos

CMD echo "hello"

$ docker build . -t hello:centos -f Dockerfile

$ docker run hello:centos
hello

$ docker run hello:centos echo 123
123

# 正如上述所说,没有指定则默认执行Dockerfile中的CMD,若是docker run 后面指定了参数,dockerfile中CMD会被docker run 后面指定的参数覆盖。
这里就是网上所说CMD会被docker run 后面指定的参数覆盖。

ENTRYPOINT

# ENTRYPOINT :字面意思是进入点,而它的功能也恰如其意。

An ENTRYPOINT allows you to configure a container that will run as an executable.它可以让你的容器功能表现得像一个可执行程序一样。

例:
# 使用下面的ENTRYPOINT构造镜像:
$ cat Dockerfile 
FROM centos

ENTRYPOINT ["/bin/echo"] 

# 那么docker build出来的镜像以后的容器功能就像一个/bin/echo程序:
$ docker build . -t test -f Dockerfile 

# 比如我build出来的镜像名称叫test,那么我可以这样用它:
$ docker run -it test “666” 
“666”

# 这里就会输出”666”这串字符,而这个test镜像对应的容器表现出来的功能就像一个echo程序一样。 你添加的参数“666”会添加到ENTRYPOINT后面,就成了这样 /bin/echo “666” 。后面添加什么参数,就会打印出什么参数,其他命令也同理。

两种写法

# 两种写法:

# 写法一:
ENTRYPOINT ["executable", "param1", "param2"] (the preferred exec form)  #首选,官方推荐

$ cat Dockerfile 
FROM centos

ENTRYPOINT ["ping","-c","2","baidu.com"]


## 查看dockerfile
$ cat Dockerfile 

FROM centos

ENTRYPOINT ["ping","-c","2","baidu.com"]

$ docker build . -t test -f Dockerfile 
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
 ---> 300e315adb2f
Step 2/2 : ENTRYPOINT ["ping","-c","2","baidu.com"]
 ---> Using cache
 ---> 32a5f9e34bdd
Successfully built 32a5f9e34bdd
Successfully tagged test:latest

$  docker run test 
PING baidu.com (39.156.69.79) 56(84) bytes of data.
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=127 time=42.2 ms
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=127 time=40.2 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 40.201/41.177/42.154/0.997 ms

$  docker run test echo 123
ping: echo: Name or service not known

# 总结,因为docker run 指定的参数会全部传给entrypoint,所以会报错。
-----------------------------------------------------------------------------------------------------

# 写法二:
ENTRYPOINT command param1 param2 (shell form) 
# 查看dockerfile
$ cat Dockerfile 
FROM centos
 
ENTRYPOINT echo "abcdefg" 

# 相当于执行了 echo “abcdefg”
$ docker run test1
abcdefg

# 第二种(shell form)会屏蔽掉docker run时后面加的命令和CMD里的参数。
$ docker run test
PING baidu.com (39.156.69.79) 56(84) bytes of data.
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=127 time=39.9 ms
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=127 time=40.3 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 39.876/40.072/40.269/0.280 ms
$ docker run test echo 123
PING baidu.com (39.156.69.79) 56(84) bytes of data.
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=127 time=39.6 ms
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=2 ttl=127 time=40.6 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 39.591/40.077/40.563/0.486 ms
注:
这里就是网上所说的,ENTRYPOINT不会被docker run 后面的CMD覆盖

演示:

# CMD 第一种写法
$ cat Dockerfile 
FROM centos

CMD echo "hello"

$ docker build . -t test -f Dockerfile 
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
 ---> 300e315adb2f
Step 2/2 : CMD ["/usr/bin/ping","-c","2","baidu.com"]
 ---> Running in b5678c3f159d
Removing intermediate container b5678c3f159d
 ---> a1d714a89940
Successfully built a1d714a89940
Successfully tagged test:latest

$ docker run test 
PING baidu.com (220.181.38.148) 56(84) bytes of data.
64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=127 time=38.5 ms
64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=2 ttl=127 time=38.2 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 38.192/38.352/38.512/0.160 ms

$ docker run test echo 123
123
# 总结:CMD 的第一种写法,可以被docker run 后面指定的参数覆盖
# CMD 第三种写法
$ cat  Dockerfile 

FROM centos
 
CMD echo "hello"
$ docker build . -t test -f Dockerfile 
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
 ---> 300e315adb2f
Step 2/2 : CMD echo "hello"
 ---> Running in e04c7c5c6056
Removing intermediate container e04c7c5c6056
 ---> 557bbe7ffad5
Successfully built 557bbe7ffad5
Successfully tagged test:latest
$  docker run test 
hello
$  docker run test echo 123
123

# 总结:CMD的第三种写法,也会被docker run指定的参数覆盖
# CMD 第二种写法
$ cat Dockerfile 

FROM centos

CMD ["123"]

ENTRYPOINT ["/usr/bin/echo"] 


$ docker build . -t test -f Dockerfile 
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM centos
 ---> 300e315adb2f
Step 2/3 : CMD ["123"]
 ---> Running in f388f3f1fc1e
Removing intermediate container f388f3f1fc1e
 ---> 95d2c32ef4b0
Step 3/3 : ENTRYPOINT ["/usr/bin/echo"]
 ---> Running in c8019a15b5f6
Removing intermediate container c8019a15b5f6
 ---> cf0dbf4b792e
Successfully built cf0dbf4b792e
Successfully tagged test:latest

$ docker run test 
123
# 总结: CMD的第二种写法,CMD指定的参数传递给了ENTRYPOINT,官方推荐写法

$ docker run test echo abc
echo abc
# 总结:docker run 后面指定的参数 ,不会覆盖ENTRYPOINT,而是传递给ENTRYPOINT做为参数了
上一篇:使用 Dockerfile 自定义 Nginx 镜像


下一篇:Docker(三):Dockerfile 命令详解