1. 前言
Dockerfile中的CMD和ENTRYPOINT有什么区别?
docker run时默认执行什么命令,怎样覆盖默认命令?
pod定义中的args和command字段有什么作用?
本文,我们来回答一下这些问题。主要参考Docker RUN vs CMD vs ENTRYPOINT和Mumshad Mannambeth的课程。
2. 指令执行方式
RUN、CMD和ENTRYPOINT指令都可以有两种执行方式:shell方式和exec方式。
2.1. shell方式
shell方式格式:<instruction> <command>
例子:
1 | RUN apt-get install python3 |
当指令以shell方式执行时,它会在后台调用 /bin/sh -c <command>
,并且会进行常规的shell处理。例如,Dockerfile中的以下定义:
1 | ENV name voidking |
docker run 会输出 Hello, voidking
,变量会被替换。
2.2. exec方式
exec方式格式:<instruction> ["executable", "param1", "param2", ...]
数组中每个元素都是一个整体。
如果写成 ["executable param1 param2"]
,executable param1 param2
会被当成一个可执行程序,是找不到路径的。
如果写成 ["executable", "param1 param2"]
,param1 param2
会被当成一个参数,是不符合预期的。
例子:
1 | RUN ["apt-get", "install", "python3"] |
当指令以exec方式执行时,它将直接调用可执行文件,并且不会进行shell处理。例如,Dockerfile中的以下定义:
1 | ENV name voidking |
docker run 会输出 Hello, $name
,变量不会被替换。
如果需要运行bash而不是sh,需要使用exec方式。在这种情况下,将进行常规的shell处理。例如,Dockerfile中的以下定义:
1 | ENV name voidking |
docker run 会输出 Hello, voidking
,变量会被替换。
3. CMD和ENTRYPOINT
3.1. CMD定义
访问dockerhub ubuntu,Supported tags and respective Dockerfile links,随便选择一个系统版本,这里选择 16.04 。点击链接,可以看到Dockerfile的定义。
1 | FROM scratch |
可以看到,Dockerfile中定义了CMD为 /bin/bash
,也就是定义了默认命令为 /bin/bash
。
docker run ubuntu:16.04
会执行默认命令 /bin/bash
。
3.2. 执行特定命令
我们想要执行命令,那么需要在docker run时指定命令,覆盖默认命令。
执行sleep 3600
1 | docker run ubuntu:16.04 sleep 3600 |
如果想要使这个特定命令永久生效,那么需要使用Dockerfile定义一个新的镜像。
1 | FROM ubuntu:16.04 |
生成新的镜像,执行默认命令 sleep 3600
1 | docker build -t ubuntu-sleeper . |
3.3. 特定参数
如果我们想要修改sleep的时间,该怎么做?
1 | docker run ubuntu:16.04 sleep 3600 |
sleep命令没有变,变化的只有参数,sleep是否可以省略?可以的,定义一个新的镜像。
1 | FROM ubuntu:16.04 |
1 | # 生成新镜像 |
ENTRYPOINT里的命令是否可以被替换的呢?也是可以的,以执行 sleep2.0 1200 为例
1 | docker run --entrypoint sleep2.0 ubuntu-sleeper 1200 |
综上,docker run会默认执行 ENTRYPOINT + CMD
。
通常情况下,我们会在Dockerfile中定义ENTRYPOINT作为固定命令,定义CMD作为默认参数。
4. k8s中的args和command
在k8s中定义pod时,有args和command两个字段。这两个字段,分别覆盖CMD和ENTRYPOINT。
k8s中的args和command,只支持exec的执行方式,因此参数格式为:["executable", "param1", "param2", ...]
例如:
1 | apiVersion: v1 |
该pod启动后的执行命令为 sleep 1200