概述
我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式:
- Shell格式:<instruction> <command>。例如:apt-get install python3
- Exec格式:<instruction> ["executable", "param1", "param2", ...]。例如: ["apt-get", "install", "python3"]
shell 模式
使用 shell 模式时,docker 会以 /bin/sh -c "task command"
的方式执行任务命令。也就是说容器中的 1 号进程不是任务进程而是 bash 进程,看下面的例子:
FROM ubuntu
CMD top
FROM ubuntu CMD top
把上面的代码保存到 test2 目录的 Dockerfile 中,然后进入 test2 目录构建镜像并启动一个容器:
$ docker build -t test2 . $ docker run -itd --name testcon2 test2
然后查看容器中的进程 ID:
$ docker exec testcon2 ps aux
CMD 指令允许用户指定容器的默认执行的命令。此命令会在容器启动且 docker run 没有指定其他命令时运行。
CMD echo "Hello world"
运行容器 docker run -it [image] 将输出:
Hello world
但当后面加上一个命令,比如 docker run -it [image] /bin/bash,CMD 会被忽略掉,命令 bash 将被执行:
root@10a32dc7d3d3:/#
同时使用 CMD 和 ENTRYPOINT 的情况
对于 CMD 和 ENTRYPOINT 的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMD 为 ENTRYPOINT 提供默认的可选参数。
我们大概可以总结出下面几条规律:
• 如果 ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略。
• 如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数。
• 如果 ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式。
真实的情况要远比这三条规律复杂,好在 docker 给出了官方的解释,如下图所示:
当我们无法理解容器中运行命令的行为时,说不定通过这个表格可以解开疑惑!
参考资料
参考资料