文章目录
- 一、概述
- 二、RUN 命令(构建时运行)
- 三、CMD 命令(启动时运行)
- 四、ENTRYPOINT 命令(启动时运行)
- 五、SHELL 命令(构建时运行)
- 六、CMD 和 ENTRYPOINT 命令区别
- 七、总结
- 参考资料
一、概述
Dockerfile 是用于构建 Docker 镜像的文本文件,提供了一系列构建指令和配置,用于自动化和标准化 Docker 镜像的构建流程。一个 Dockerfile 可以通过依次执行每行命令来创建一个新的 Docker 镜像。因此,执行命令与 Dockerfile 的编写和构建密不可分。
在 Dockerfile 中,可以使用多种方式执行命令:
- RUN 命令: RUN 命令是最常用的一种方式,它允许在构建 Docker 镜像期间执行任意命令。例如:
RUN apt-get update && apt-get install -y python
- CMD 命令: CMD 命令用于指定容器启动时要执行的默认命令。它可以在 Dockerfile 中只出现一次且必须是最后一个命令。例如:
CMD ["python", "app.py"]
- ENTRYPOINT 命令: ENTRYPOINT 命令用于指定容器启动时要执行的默认命令,并且不支持被覆盖。例如:
ENTRYPOINT ["python", "app.py"]
- SHELL 命令: SHELL 命令用于指定运行在 RUN 命令中的 SHELL。默认的 SHELL 是 /bin/sh -c,但也可以在 Dockerfile 中指定其它的 SHELL。例如:
SHELL ["/bin/bash", "-c"]
需要注意的是,这些命令的主要区别在于何时执行命令。RUN 命令在构建期间执行,CMD 和 ENTRYPOINT 在容器启动时执行。SHELL 可以用于在 RUN 命令中指定更多的 SHELL 选项。在 Dockerfile 中可以结合使用这些命令以完成更复杂的操作。
二、RUN 命令(构建时运行)
2.1 RUN 命令简介
RUN 命令是 Dockerfile 中常用的一种命令,它表示需要在构建 Docker 镜像时执行的命令。
RUN 命令实际上是在一个新的临时容器中执行所指定的命令,并在这个过程中创建新的镜像层,在最终的 Docker 镜像中保存这些更改。
RUN命令语法:
RUN ["command", "param1", "param2"]:用于指定要运行的可执行文件及其所需参数。 RUN command1 && command2:用于在同一行中运行多个命令,以便节省Docker镜像的层数。
2.2 注意点和使用技巧
- 一条 RUN 命令只能提交一个镜像层,因此为了最小化镜像大小,应该在同一个 RUN 命令中执行多个命令,并使用一些好的构建最佳实践(例如删除不需要的软件包和临时文件等)。
- 通常将多个命令合并到一条 RUN 命令中执行,使用 && 连接多个命令,使用\ 分行,使用 && 连接多条命令可将多个命令合并为一条 RUN 命令,一旦其中某个命令失败了,后续命令都不会再执行。例如:
RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y software-properties-common && \ add-apt-repository ppa:deadsnakes/ppa && \ apt-get install -y python3.6 && \ apt-get clean
三、CMD 命令(启动时运行)
3.1 CMD 命令简介
CMD 命令用于 Docker 镜像的默认启动命令,表示容器启动时要执行的默认操作。
CMD 指令只能在 Dockerfile 中出现一次,如果有多个 CMD 指令,则只有最后一个 CMD 指令生效。
CMD 命令有两种形式,分别是 exec 形式和 shell 形式:
- EXEC 形式
EXEC 形式中 CMD 指令的语法如下:
CMD ["executable","param1","param2"] # CMD ["python", "app.py"]
其中,executable 指的是将要运行的可执行文件或脚本,param1、param2 等参数代表这个程序的命令行参数,可以省略参数。指令参数是一个 JSON 数组。
- SHELL 形式
SHELL 形式中的 CMD 指令语法如下:
CMD command param1 param2 # CMD python app.py
其中,command 表示将要运行的命令,param1 和 param2 为可选的命令行参数。
3.2 注意点和使用技巧
- CMD 指令只能在 Dockerfile 中出现一次,如果有多个 CMD 指令,则只有最后一个 CMD 指令生效。
- 使用 SHELL 形式的 CMD 指令时,Docker 会自动在 /bin/sh 中启动 SHELL 并运行 CMD 指定的命令,由于 SHELL 不支持信号处理,可以使用 exec 形式的 CMD 指令,这样可以直接使用信号传递机制,并且能够获得更好的性能和资源管理。
四、ENTRYPOINT 命令(启动时运行)
4.1 ENTRYPOINT 简介
ENTRYPOINT 命令用于设置默认的容器执行命令,与 CMD 命令类似,不同的是 ENTRYPOINT 命令设置的命令不会被覆盖,而是作为容器运行时的默认命令始终存在。
ENTRYPOINT 命令有两种形式:exec 形式和 shell 形式,具体的语法如下:
- 使用 exec 形式
ENTRYPOINT ["executable", "param1", "param2"] # ENTRYPOINT ["python", "app.py"]
其中,executable 是在容器启动时要运行的可执行文件或脚本,param1 和 param2 分别为该可执行文件或脚本的参数。可以省略参数。
- 使用 shell 形式
ENTRYPOINT command param1 param2 # ENTRYPOINT python app.py
其中,command 表示在容器启动时要运行的命令,在 shell 中执行。param1 和 param2 是 command 命令的参数,可以省略。
4.2 注意点和使用技巧
- ENTRYPOINT 命令的默认值和 CMD 命令的默认值可以同时存在,也可以互相随意组合。
- 如果 ENTRYPOINT 命令有多个,只有最后一个命令有效。
- 同时,也可以使用 shell 的 exec 命令来实现 ENTRYPOINT 命令的 exec 形式,例如:
ENTRYPOINT ["/bin/sh", "-c", "exec <exec_command>"]
其中,<exec_command> 表示使用的可执行命令。
五、SHELL 命令(构建时运行)
5.1 SHELL命令简介
SHELL 命令用于在 Dockerfile 中指定运行在 RUN 命令的 SHELL。SHELL 命令有两种形式:使用 SHELL 指令更改默认 shell 或者在 RUN 命令中临时更改 shell。
- 使用 SHELL 指令更改默认 shell
SHELL 指令语法为:
SHELL ["executable", "parameters"] # SHELL ["/bin/bash", "-c"]
其中,executable 为默认的 SHELL 可执行程序,parameters 用于设置 SHELL 程序的参数,可以省略。在 Dockerfile 中使用 SHELL 指令更改默认 shell 可以改变整个 Dockerfile 中所有的 RUN。
- 在 RUN 命令中临时更改 shell
在 RUN 命令中可以通过 SHELL 命令来临时更改 shell。使用 SHELL 命令可以将构建环境的 shell 上下文更改为指定的 shell,并在 RUN 指令中执行 SHELL 命令。在 RUN 命令中使用 SHELL 命令的语法为:
RUN ["/bin/sh", "-c", "SHELL command"] # RUN ["/bin/sh", "-c", "SHELL=/bin/bash apt-get update"]
其中,command 部分表示希望在临时 shell 中执行的命令。例如:
RUN ["/bin/sh", "-c", "SHELL=/bin/bash apt-get update"]
则会在临时的 bash shell 中执行 apt-get update 命令。
5.2 注意点和使用技巧
需要注意的是,RUN 命令中的 SHELL 命令在 RUN 命令结束后会被自动清除,RUN 下一行将会使用默认 shell 上下文,并且没有从之前的 SHELL 指定中继承环境变量。
总之,SHELL 命令用于更改 Dockerfile 中的 shell 上下文,可以通过 SHELL 指令更改默认 shell 或者在 RUN 命令中临时更改 shell,根据实际需求可以使用不同的方式来更改 Dockerfile 中的 shell 上下文。
六、CMD 和 ENTRYPOINT 命令区别
CMD 和 ENTRYPOINT 指令都是用来指定容器启动时运行的命令。
单从功能上来看,这两个命令几乎是重复的。单独使用其中的一个就可以实现绝大多数的用例。但是既然 doker 同时提供了它们,必然有区别。
CMD 和 ENTRYPOINT 指令都支持 exec 模式和 shell 模式的写法,上文中已经进行了详细描述。
其中,CMD 指令有三种使用方式,其中的一种是为 ENTRYPOINT 提供默认的参数,当指定 ENTRYPOINT 指令为 exec 模式时,命令行上指定的参数会作为参数添加到 ENTRYPOINT 指定命令的参数列表中。 示例如下:
ENTRYPOINT [ "python3" ] CMD [ "app.py" ]
关于CMD 和 ENTRYPOINT 命令区别,需要注意以下几点:
(1)Dockerfile 中至少要有一个
如果镜像中既没有指定 CMD 也没有指定 ENTRYPOINT 那么在启动容器时会报错。现在绝大多数镜像都默认添加了 CMD 或 ENTRYPOINT 指令。
(2)指定任意一个,效果差不多
从结果上看,CMD 和 ENTRYPOINT 是一样的,我们可以通过它们实现相同的目的。
CMD ["python", "app.py"]
ENTRYPOINT ["python", "app.py"]
以上两个命令虽然实现方式不同,但最终容器运行的命令是一样的。
(3)同时使用 CMD 和 ENTRYPOINT 的情况
对于 CMD 和 ENTRYPOINT 的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMD 为 ENTRYPOINT 提供默认的可选参数。我们大概可以总结出下面几条规律:
- 如果 ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略。
- 如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数。
- 如果 ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式。
真实的情况要远比这三条规律复杂,好在 docker 给出了官方的解释,如下图所示:
参考资料:Dockerfile中CMD和ENTRYPOINT命令详解
七、总结
本文从 RUN 命令、CMD 命令、 ENTRYPOINT 命令、SHELL命令四个方面对 Dockerfile 中的常用命令进行了介绍。其中:
- RUN 命令用于在 Docker 镜像中执行指定的命令并创建新的镜像层
- CMD 命令则用于设置在容器启动时需要执行的默认命令
- ENTRYPOINT 命令则用于设置容器启动时的默认命令,并且设置的命令不会被覆盖。
此外,本文还介绍了如何在 RUN 命令中执行多条命令、如何使用 SHELL 命令更改默认 SHELL 和如何在 RUN 命令中临时更改 SHELL 的方法和语法。了解这些常用的 Dockerfile 命令可以使 Docker 镜像的构建更加高效和方便。
参考资料
本文转载自:Dockerfile中执行命令的几种方式