CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

CMD 在docker run 时运行。
RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参 
1、不传参运行

$ docker run  nginx:test
容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf
2、传参运行

$ docker run  nginx:test /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf
ENTRYPOINT ["python hello.py","<param1>","<param2>",...] 这样写正确吗

不太正确。

ENTRYPOINT 命令的作用是在容器启动时执行,指定容器启动时执行的默认命令,并且可以带上参数。但是 ENTRYPOINT 命令跟 CMD 命令有很大的区别,CMD 可以被运行 docker run 命令时传进来的命令行参数覆盖,而ENTRYPOINT 命令则不会被覆盖,只会被参数追加。

而针对你的问题,正确的写法是在 ENTRYPOINT 后面使用数组形式来指定运行的命令,例如:

ENTRYPOINT ["python", "hello.py", "<param1>", "<param2>", ...]
数组中的每个元素都是一个独立的参数,这样定义容器启动后会运行 python 命令,并且执行 hello.py 脚本。如果需要带上参数,可以在数组中追加相应的参数即可。

另外需要注意的是,在使用数组形式指定命令时,不需要使用 shell 解析参数,因此参数不需要使用双引号或单引号引起来。

在这个 Dockerfile 中,实际执行的命令是 python start_multi_progress_server.py --workers。这个命令是通过 ENTRYPOINT 指定的,其实在 CMD 中指定的 1 参数会被忽略掉,因为 CMD 命令只会将参数追加到 ENTRYPOINT 命令的后面。

因此,当你使用 docker run 命令启动这个容器时,实际运行的命令应该类似于:

CMD ["1"] # 变参,run指令可以覆盖
ENTRYPOINT ["python","start_multi_progress_server.py", "--workers"] # 定参

python start_multi_progress_server.py --workers 1
其中的 1 参数是你在 Dockerfile 中使用 CMD 命令传递的。
docker run -p 8090:8090 --name ltkj-cpu-py38-pp242 -d harbor.dubhe.com/train/ltkj-cpu-py38-pp242:v0.0.1.20230524 --workers 2

补充

CMD

功能为容器启动时要运行的命令

语法有三种写法

  1. CMD [“executable”,“param1”,“param2”]
  2. CMD [“param1”,“param2”]
  3. CMD command param1 param2
    第三种比较好理解了,就时shell这种执行方式和写法

第一种和第二种其实都是可执行文件加上参数的形式

举例说明两种写法:

CMD [ “sh”, “-c”, “echo docker run 命令和dockerfile run的区别 dockerfile run和cmd区别_运维HOME” ]
补充细节:这里边包括参数的一定要用双引号,就是",不能是单引号。千万不能写成单引号。

原因是参数传递后,docker解析的是一个JSON array

补充1

非常抱歉,再次确认后我的答案还是有误,我混淆了在Dockerfile中使用argparse的两个语法风格。如果在Dockerfile中使用ENTRYPOINTCMD来运行Python脚本,并使用argparse来处理命令行参数,您可以通过两种不同的方式来指定参数。下面分别是这两种方式:

1.使用长参数名和对应的值:

ENTRYPOINT ["python", "app.py"]
CMD ["--arg1=value1", "--arg2=value2"]

在这个示例中,我们使用 ENTRYPOINT 指令指定了要在容器内运行的命令 python app.py,然后使用 CMD 指令定义了要传递给命令的默认参数值。在 CMD 中,我们使用了长参数名称和对应的值来指定argparse参数。在这种语法风格下,参数值使用 = 号与参数名称分隔开。

假设在 app.py 中定义了以下 argparse 参数:

import argparse

parser = argparse.ArgumentParser(description='My Python script')
parser.add_argument('--arg1', help='Argument 1', required=True)
parser.add_argument('--arg2', help='Argument 2', required=False)

args = parser.parse_args()

在运行容器时,可以使用以下命令来指定新的参数值:

docker run -it --rm 镜像名称 --arg1 new_value1 --arg2 new_value2

使用上述命令运行容器时,Docker将使用新的参数值来执行 app.py 脚本。在这种语法风格下,新的参数值直接添加在容器运行命令的最后。可以看到,新的参数值使用长参数名并指定其值。

2.使用短参数名和对应的值:

ENTRYPOINT ["python", "app.py"]
CMD ["-a value1", "-b value2"]

在这个示例中,我们同样使用 ENTRYPOINT 指令指定了运行的命令 python app.py,然后使用 CMD 指令定义了要传递给命令的默认参数。与第一种语法风格不同的是,这一次我们使用了单个横线作为参数前缀并且使用空格将参数名称及其值分隔开来定义argparse参数。

假设在 app.py 中使用了以下 argparse 参数:

import argparse

parser = argparse.ArgumentParser(description='My Python script')
parser.add_argument('-a', '--arg1', help='Argument 1', required=True)
parser.add_argument('-b', '--arg2', help='Argument 2', required=False)

args = parser.parse_args()

在运行容器时,可以使用以下命令来指定新的参数值:

docker run -it --rm 镜像名称 -a new_value1 -b new_value2

在这个例子中,使用 -a 等单个横线作为前缀的短参数名称来指定argparse参数,而不是使用两个横线以及 = 号。另外,新的参数值直接添加在容器运行命令的最后。