在使用 Docker 构建容器镜像时,我们经常会使用 Dockerfile 来定义容器的配置。其中,ENTRYPOINT 和 CMD 是两个重要的指令,用于设置容器运行时的命令。本文将详细介绍 ENTRYPOINT 和 CMD 的主要区别,并探讨它们在 Dockerfile 中的结合使用。
CMD 与 ENTRYPOINT的主要区别
CMD
CMD
指令用于设置容器运行时的默认参数。- 如果 Dockerfile 中有多个
CMD
指令,只有最后一个会生效。 CMD
可以被docker run
命令行中的参数覆盖。- 在 Dockerfile 中,可以用 JSON 数组或字符串数组的形式指定
CMD
,如CMD ["command", "arg1", "arg2"]
或CMD command arg1 arg2
。 CMD
的参数会作为默认参数传递给 ENTRYPOINT。
ENTRYPOINT
ENTRYPOINT
指令用于设置容器启动时的默认可执行命令。ENTRYPOINT
可以是一个具体的命令或者一个可执行脚本。ENTRYPOINT
的值不会被docker run
命令行中的参数覆盖。- 在 Dockerfile 中,可以用 JSON 数组或字符串数组的形式指定
ENTRYPOINT
,如ENTRYPOINT ["command", "arg1", "arg2"]
或ENTRYPOINT command arg1 arg2
。
CMD 与 ENTRYPOINT的结合使用
CMD
和 ENTRYPOINT
可以结合使用,以满足不同的需求。当它们同时存在时,CMD
中的参数会作为 ENTRYPOINT
的默认参数。
以下是一个示例的 Dockerfile:
FROM ubuntu:latest
ENTRYPOINT ["echo", "Hello"]
CMD ["World"]
上述 Dockerfile 中,ENTRYPOINT
指定了默认的可执行命令为 echo
,并设定了默认参数为 Hello
。CMD
指定了默认参数为 World
。当容器启动时,会执行的命令为 echo Hello World
。
可以通过以下步骤验证 ENTRYPOINT
和 CMD
的结合使用效果:
Dockerfile
的文件,并将上述示例内容复制到文件中。docker build -t myimage .
docker run myimage
运行以上命令后,会看到容器输出 Hello World
,验证了 ENTRYPOINT
和 CMD
的结合运行。
需要注意的是,如果在运行容器时显式传递了命令行参数,则会覆盖 CMD
中指定的默认参数。例如,使用 docker run myimage "Greeting"
命令运行容器时,会执行的命令为 echo Greeting
,而不再是 echo Hello World
。
java
我们有一个 java 程序,它添加了两个数字,我们希望用户在执行 docker run 时传递参数。那么当我们容器化下面给出的程序时,我们如何实现这一点呢?
public static void main(String[] args) {
if (args.length == 2) {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
int sum = a + b;
System.out.println("Sum of "+args[0] +" & "+ args[1]+" is : " + sum);
}
}
ENTRYPOINT
FROM openjdk:8-jre-alpine
COPY out/production/DockerExampleArgsJava/ /tmp
WORKDIR /tmp
ENTRYPOINT ["java", "AddTwoNumber"]
-
上述文件中的ENTRYPOINT用于指定容器启动时要运行的命令,在本例中,它通过发出命令来启动 AddTwoNumber 程序的 main
java AddTwoNumber
方法 -
当你使用命令运行容器时
docker run raje/add2number
,它会给出一条消息 – 请输入 2 个整数 -
您可以通过发出相同的命令并传递参数来传递参数,这些将被传递到入口点示例
docker run raje/add2number 10 100
-
如果您想在启动时将默认值传递给容器,可以通过在 Dockerfile 中提及它来实现,如下所示
FROM openjdk:8-jre-alpine
COPY out/production/DockerExampleArgsJava/ /tmp
WORKDIR /tmp
ENTRYPOINT ["java", "AddTwoNumber","5","15"]
CMD
-
如果您现在使用命令运行该程序
docker run raje/add2number
,它将显示总和 -
然而,如果你尝试传递新的参数,那是行不通的。尝试 d
ocker run raje/add2number 10 100
并且参数将不会被考虑 -
发生这种情况是因为我们在 dockerfile 中提供的 ENTRYPOINT 指令不会被忽略,而是会附加到原始指令中,因此在这种情况下,程序将被调用,如下所示
java AddTwoNumber 5 15 10 100
-
CMD 是另一个选项,它提供有关在执行 docker run 时应执行的操作的说明。
-
如果我们在 Dockerfile 中使用以下指令
FROM openjdk:8-jre-alpine
COPY out/production/DockerExampleArgsJava/ /tmp
WORKDIR /tmp
CMD ["java", "AddTwoNumber","5","15"]
-
执行后
docker run raje/add2number
-
我们将看到输出:
Sum of 10 & 100 is : 110
-
使用 ENTRYPOINT,当我们传递新参数时,它会附加到命令中,但是使用 CMD 你可以覆盖命令,例如
-
如果你想传递新的参数,你可以运行:
docker run raje/add2number java AddTwoNumber 300 40
-
您可以将命令完全替换为类似的命令
docker run raje/add2number echo This is Test
-
-
如果您有一个场景,您希望默认命令是您提到的程序并希望用于覆盖参数,那么您可以使用 ENTRYPOINT 和 CMD 的组合
使用 ENTRYPOINT 和 CMD 的组合
FROM openjdk:8-alpine
COPY out/production/DockerExampleArgsJava/ /tmp
WORKDIR /tmp ENTRYPOINT ["java", "AddTwoNumber"]
CMD ["10","200"]
-
使用上面的 docker 文件,当您发出命令时,
docker run raje/add2number
它将输出Sum of 10 & 200 is : 210
-
您可以通过发出类似命令来覆盖默认参数
docker run raje/add2number 40 50
,它将输出Sum of 40 & 50 is : 90
总结
在 Dockerfile 中,ENTRYPOINT
和 CMD
是两个重要的指令,用于设置容器运行时的命令。ENTRYPOINT
指定了默认的可执行命令,而 CMD
则提供了 ENTRYPOINT
的默认参数。它们的结合使用可以帮助我们定义灵活且可定制的容器镜像。通过实际的例子与操作指引,我们深入理解了它们的功能和使用方法。