RUN和ENTRYPOINT指令都可以有两种执行方式:shell方式和exec方式。
shell方式
shell方式格式:
<instruction> <command>
例子:
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
当指令以shell方式执行时,它会在后台调用 /bin/sh -c <command>
,并且会进行常规的shell处理。例如,Dockerfile中的以下定义:
ENV name voidking
ENTRYPOINT echo "Hello, $name"
docker run 会输出 Hello, voidking
,变量会被替换。
exec方式
exec方式格式:
<instruction> ["executable", "param1", "param2", ...]
例子:
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
当指令以exec方式执行时,它将直接调用可执行文件,并且不会进行shell处理。例如,Dockerfile中的以下定义:
ENV name voidking
ENTRYPOINT ["/bin/echo", "Hello, $name"]
docker run 会输出 Hello, $name
,变量不会被替换。
如果需要运行bash而不是sh,需要使用exec方式。在这种情况下,将进行常规的shell处理。例如,Dockerfile中的以下定义:
ENV name voidking
ENTRYPOINT ["/bin/bash", "-c", "echo Hello, $name"]
docker run 会输出 Hello, voidking
,变量会被替换。
CMD定义
访问dockerhub ubuntu,Supported tags and respective Dockerfile links,随便选择一个系统版本,这里选择 16.04 。点击链接,可以看到Dockerfile的定义。
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
CMD ["/bin/bash"]
可以看到,Dockerfile中定义了CMD为 /bin/bash
,也就是定义了默认命令为 /bin/bash
。
docker run ubuntu:16.04
会执行默认命令 /bin/bash
。
执行特定命令
我们想要执行命令,那么需要在docker run时指定命令,覆盖默认命令。
docker run ubuntu:16.04 sleep 3600
,会执行 sleep 3600
。
如果想要使这个特定命令永久生效,那么需要使用Dockerfile定义一个新的镜像。
FROM ubuntu:16.04
CMD ["sleep","3600"]
docker build -t ubuntu-sleeper .
,生成新的镜像。
docker run ubuntu-sleeper
,执行默认命令 sleep 3600
。
特定参数
如果我们想要修改sleep的时间,该怎么做?
docker run ubuntu:16.04 sleep 3600
docker run ubuntu:16.04 sleep 1200
sleep命令没有变,变化的只有参数,sleep是否可以省略?可以的,定义一个新的镜像。
FROM ubuntu:16.04
ENTRYPOINT ["sleep"]
CMD ["3600"]
docker build -t ubuntu-sleeper .
,生成新的镜像。
docker run ubuntu-sleeper
,执行默认命令 sleep 3600
。
docker run ubuntu-sleeper 1200
,执行命令 sleep 1200
。
那么,ENTRYPOINT里的命令是否可以被替换的呢?也是可以的。
docker run --entrypoint sleep2.0 ubuntu-sleeper 1200
,执行命令 sleep2.0 1200
。
综上,docker run会默认执行 ENTRYPOINT + CMD
。
通常情况下,我们会在Dockerfile中定义ENTRYPOINT作为固定命令,定义CMD作为默认参数。
在k8s中定义pod时,有args和command两个字段。这两个字段,分别覆盖CMD和ENTRYPOINT。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ubuntu
name: ubuntu
spec:
containers:
- image: ubuntu:16.04
name: ubuntu
resources: {}
command: ["sleep"]
args: ["1200"]
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
该pod启动后的执行命令为 sleep 1200
。