在 Dockerfile 中,CMD
和 ENTRYPOINT
是两个用于定义容器启动时默认执行命令的指令,但它们在功能和使用场景上有明显的区别。以下是它们的详细对比:
1. 基本定义
1.1 CMD
:- 用于为容器指定默认的启动命令。
- 如果用户在运行容器时没有指定其他命令,
CMD
指定的命令会被执行。 - 它是可被覆盖的,即用户可以通过在
docker run
命令中指定新的命令来覆盖CMD
中定义的命令。
1.2 ENTRYPOINT
:- 用于定义容器启动时执行的程序或脚本。
- 它是不可被覆盖的,即用户不能通过在
docker run
命令中指定新的命令来覆盖ENTRYPOINT
中定义的命令。 - 如果同时使用了
ENTRYPOINT
和CMD
,CMD
的内容会被作为参数传递给ENTRYPOINT
。
2. 使用场景
-
2.1 CMD
的使用场景:-
当你希望容器启动时运行一个默认的命令,但用户可以根据需要覆盖该命令时,使用
CMD
。 -
例如,你希望容器默认运行一个 Web 服务器,但用户也可以选择运行一个脚本或命令行工具。
-
示例:
CMD ["python", "app.py"]
用户可以通过以下命令覆盖默认行为:
docker run my-image bash
-
-
2.2 ENTRYPOINT
的使用场景:-
当你希望容器始终运行一个固定的程序或脚本,并且用户可以通过传递参数来扩展功能时,使用
ENTRYPOINT
。 -
例如,你希望容器始终运行一个脚本,用户可以通过传递参数来控制脚本的行为。
-
示例:
ENTRYPOINT ["./my-script.sh"] CMD ["--default-param"]
用户可以通过以下命令传递参数:
docker run my-image --custom-param
这时,
--custom-param
会被传递给./my-script.sh
。
-
3. 参数传递
3.1 CMD
:- 如果用户在
docker run
中指定了新的命令,则CMD
的内容会被完全替换。 - 如果没有指定新的命令,则
CMD
的内容会被执行。
- 如果用户在
3.2 ENTRYPOINT
:ENTRYPOINT
定义的命令始终会被执行。- 如果同时定义了
CMD
,CMD
的内容会被作为参数传递给ENTRYPOINT
。 - 用户可以通过在
docker run
中指定参数来覆盖CMD
的内容。
4. 命令格式
4.1 CMD
:- 可以有三种格式:
- Shell 形式:
CMD command param1 param2
例如:CMD python app.py
- Exec 形式:
CMD ["command", "param1", "param2"]
例如:CMD ["python", "app.py"]
- 默认参数形式:
CMD ["param1", "param2"]
仅当与ENTRYPOINT
一起使用时有效。
- Shell 形式:
- 可以有三种格式:
4.2 ENTRYPOINT
:- 只有两种格式:
- Shell 形式:
ENTRYPOINT command param1 param2
例如:ENTRYPOINT ./my-script.sh
- Exec 形式:
ENTRYPOINT ["command", "param1", "param2"]
例如:ENTRYPOINT ["./my-script.sh"]
- Shell 形式:
- 只有两种格式:
5. 示例对比
5.1 使用 CMD
CMD ["python", "app.py"]
- 默认行为:容器启动时运行
python app.py
。 - 用户覆盖:
docker run my-image bash
,容器会运行bash
而非python app.py
。
5.2 使用 ENTRYPOINT
ENTRYPOINT ["./my-script.sh"]
CMD ["--default-param"]
- 默认行为:容器启动时运行
./my-script.sh --default-param
。 - 用户覆盖:
docker run my-image --custom-param
,容器会运行./my-script.sh --custom-param
。
6. 总结
6.1 CMD
:- 更灵活,用户可以覆盖默认命令。
- 适合定义默认行为,但允许用户自定义。
6.2 ENTRYPOINT
:- 更固定,用户不能覆盖,但可以通过参数扩展功能。
- 适合定义容器的固定入口程序或脚本。
在实际使用中,可以根据你的需求选择合适的指令。如果需要用户能够灵活控制容器的行为,优先使用 CMD
;如果需要容器始终运行某个程序或脚本,优先使用 ENTRYPOINT
。