第 3 章 镜像 - 017 - RUN vs CMD vs ENTRYPOINT
RUN、CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似,很容易混淆。
简单的说:
RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run
后面跟的命令行参数替换。
ENTRYPOINT 配置容器启动时运行的命令。
Shell 和 Exec 格式
可以用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式,二者在使用上存在细微的区别。
Shell 格式
<instruction> <command>
例如:
RUN apt-get install python3 CMD echo "Hello world" ENTRYPOINT echo "Hello world"
当指令执行时,shell 格式底层会调用 /bin/sh -c <command>。
例如下面的 Dockerfile 片段:
1 ENV name xxx 2 ENTRYPOINT echo "Hello, $name"
执行 docker run <image> 将输出:
Hello, xxx
注意环境变量 name
已经被值 xxx
替换。
Exec 格式
<instruction> ["executable", "param1", "param2", ...]
例如:
1 RUN ["apt-get", "install", "python3"] 2 CMD ["/bin/echo", "Hello world"] 3 ENTRYPOINT ["/bin/echo", "Hello world"]
当指令执行时,会直接调用 <command>,不会被 shell 解析。
以Dockerfile 片段为例:
1 ENV name xxx 2 ENTRYPOINT ["/bin/echo", "Hello, $name"]
运行容器将输出:
Hello, $name
注意环境变量“name”没有被替换。
如果希望使用环境变量,照如下修改
1 ENV name xxx 2 ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
运行容器将输出:
Hello, xxx
CMD 和 ENTRYPOINT 推荐使用 Exec 格式,指令可读性更强,更容易理解。RUN 则两种格式都可以。
RUN
RUN 指令通常用于安装应用和软件包。
RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。
RUN 有两种格式:
- Shell 格式:RUN
- Exec 格式:RUN ["executable", "param1", "param2"]
可以使用 RUN 安装多个包:
RUN apt-get update && apt-get install -y \ bzr \ cvs \ git \ mercurial \ subversion
注意:apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包。如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的。
CMD
CMD 指令允许用户指定容器的默认执行的命令。此命令会在容器启动且 docker run 没有指定其他命令时运行。
- 如果 docker run 指定了其他命令,CMD 指定的默认命令将被忽略。
- 如果 Dockerfile 中有多个 CMD 指令,只有最后一个 CMD 有效。
CMD 有三种格式:
- Exec 格式(推荐):CMD ["executable","param1","param2"]
- CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。
- Shell 格式:CMD command param1 param2
举个栗子:
1 root@ubuntu:~/0108# cat Dockerfile 2 FROM ubuntu 3 CMD echo "hello world" 4 root@ubuntu:~/0108# 5 root@ubuntu:~/0108# docker build -t cmd-eg-v1 . 6 Sending build context to Docker daemon 2.048kB 7 Step 1/2 : FROM ubuntu 8 ---> 1d9c17228a9e 9 Step 2/2 : CMD echo "hello world" 10 ---> Running in 73a418109975 11 Removing intermediate container 73a418109975 12 ---> 44b793b3959c 13 Successfully built 44b793b3959c 14 Successfully tagged cmd-eg-v1:latest 15 root@ubuntu:~/0108# 16 root@ubuntu:~/0108# docker run -it cmd-eg-v1 17 hello world 18 root@ubuntu:~/0108# docker run -it cmd-eg-v1 /bin/bash 19 root@57afa1edf189:/#
在执行 docker run -it [image] /bin/bash,CMD 会被忽略掉,命令 bash 被执行。
ENTRYPOINT
ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。
ENTRYPOINT 看上去与 CMD 很像,它们都可以指定要执行的命令及其参数。区别在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。
ENTRYPOINT 有两种格式:
- Exec 格式(推荐):ENTRYPOINT ["executable", "param1", "param2"]
- Shell 格式:ENTRYPOINT command param1 param2
在为 ENTRYPOINT 选择格式时必须小心,因为这两种格式的效果差别很大。
Exec 格式
ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。
ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。
举个例子:
1 root@ubuntu:~/0108# cat Dockerfile 2 FROM ubuntu 3 ENTRYPOINT ["/bin/echo", "Hello"] 4 CMD ["world"] 5 root@ubuntu:~/0108# 6 root@ubuntu:~/0108# docker build -t cmd-eg-v2 . 7 Sending build context to Docker daemon 2.048kB 8 Step 1/3 : FROM ubuntu 9 ---> 1d9c17228a9e 10 Step 2/3 : ENTRYPOINT ["/bin/echo", "Hello"] 11 ---> Running in fae6feb9277a 12 Removing intermediate container fae6feb9277a 13 ---> 93c655c722d2 14 Step 3/3 : CMD ["world"] 15 ---> Running in 0de0893f9c13 16 Removing intermediate container 0de0893f9c13 17 ---> 3632ca1d41fa 18 Successfully built 3632ca1d41fa 19 Successfully tagged cmd-eg-v2:latest 20 root@ubuntu:~/0108# 21 root@ubuntu:~/0108# docker run -it cmd-eg-v2 22 Hello world 23 root@ubuntu:~/0108# docker run -it cmd-eg-v2 xxx 24 Hello xxx 25 root@ubuntu:~/0108#
Shell 格式
ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。
小结
- 使用 RUN 指令安装应用和软件包,构建镜像。
- 如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。
- 如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。
---------------------------引用来自-----------------------------------
https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587614&idx=1&sn=2070e193da6b71861052e393eccae055&chksm=8d308087ba4709915514e06e73bba8a93fca5510f910552a8290e9a1b4ae111d7a3fd230c0a5&scene=21#wechat_redirect