Dockerfile命令CMD和ENTRYPOINT

2,043 阅读2分钟

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

www.jb51.net/article/136…