• CMD 命令和 ENTRYPOINT 命令的区别


    CMD 命令

    CMD-shell 形式

    1. 创建 Dockerfile1
    vim Dockerfile1
    # 写入以下两行内容
    FROM centos:7
    CMD cal
    
    • 1
    • 2
    • 3
    • 4
    2. 构建和运行新镜像
    # 说明:-f 用于指定本次构建所要使用的Dockerfile的文件名。
    docker build -f Dockerfile1 -t my-cal:1.0 .
    
    • 1
    • 2

    构建成功运行新镜像。运行后可以查看到当前月份的日历。

    image-20230911102224504

    3. 覆盖 CMD

    image-20230911100132103

    docker run 命令中指定要执行的命令,Dockerfile 中通过 CMD 指定的默认的命令就不会在执行,也就是说Dockerfile 中的 CMD 命令是可以被覆盖的。

    4. 添加命令选项

    image-20230911102303525

    cal命令添加 -y 选项可以显示当前年的所有月份。但这种方式无法为 CMD 中指定的默认的命令指定选项。

    小总结

    cmd-shell的形式可以被覆盖,但不能添加命令选项。

    CMD-exec形式

    1. 创建Dockerfile2、构建和运行新镜像

    此步骤与前面类似,只是把Dockerfile1里面的CMD cal 替换为CMD [“cal”] 或者CMD [“/bin/bash”, “-c”, “cal”]。

    CMD-exec形式的语法:

    CMD [“executable”,“param1”,“param2”]

    • “executable” 是你想要运行的命令或程序。
    • “param1”,“param2” 是传递给这个命令或程序的参数。

    image-20230911102606406

    image-20230911102631745

    最后运行新镜像的结果和CMD-shell 形式的结果一样。

    2.覆盖 CMD和添加命令选项

    image-20230911102701172

    小总结

    cmd-exec的形式可以被覆盖,但不能添加命令选项。

    ENTRYPOINT 命令

    ENTRYPOINT-shell

    1. 创建Dockerfile3、构建和运行新镜像

    ENTRYPOINT-shell形式的语法:ENTRYPOINT command param1 param2

    vim Dockerfile3
    # 写入以下两行内容
    FROM centos:7
    ENTRYPOINT cal
    # 构建镜像
    docker build -f Dockerfile3 -t my-cal:3.0 .
    # 运行镜像
    docker run -it my-cal:3.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果如下:

    image-20230911152434533

    2. 覆盖 ENTRYPOINT 和 添加命令选项
    image-20230911152648861

    可以看到ENTRYPOINT-shell形式的指令是不会被 docker run 中指定的命令给覆盖掉的。在 docker run 中添加的命令选项,对于 ENTRYPOINT 中指定的命令是无效的。在这点上不像 CMD 指令一样报错。

    ENTRYPOINT-exec

    为了更好的理解ENTRYPOINT命令,ENTRYPOINT-exec又分了两种情况进行讨论。分别是ENTRYPOINT [“cal”] 和 ENTRYPOINT [“/bin/bash”,“-c”,“cal”] 。看看它们之间的区别有哪些以及为什么。

    1. 创建Dockerfile4、构建和运行新镜像
    vim Dockerfile4
    # 写入以下两行内容
    FROM centos:7
    ENTRYPOINT ["cal"]
    # 构建镜像
    docker build -f Dockerfile4 -t my-cal:4.0 .
    # 运行镜像
    docker run -it my-cal:4.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果如下:

    image-20230911153728227

    2. 覆盖 ENTRYPOINT 和 添加命令选项
    image-20230911153851075

    可以看到这种的ENTRYPOINT-exec形式的指令也是不会被 docker run 中指定的命令给覆盖掉的,并且会报出错误信息。而在 docker run 中添加的命令选项,对于 ENTRYPOINT 中指定的命令却是是有效的,能够显示出整年的日历。

    ENTRYPOINT-exec 的另一种写法

    为了节省篇幅,我简要写出关键步骤后直接看运行结果。

    # 建立Dockerfile5
    vim Dockerfile5
    # 写入以下两行内容
    FROM centos:7
    ENTRYPOINT ["/bin/bash","-c","cal"]
    # 构建镜像
    docker build -f Dockerfile5 -t my-cal:5.0 .
    # 运行镜像
    docker run -it my-cal:5.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果如下:

    image-20230911154657701

    覆盖 ENTRYPOINT 和 添加命令选项的结果如下:

    image-20230911154753592

    发现最后的结果与ENTRYPOINT-shell的形式一样。也就是不会被覆盖并且添加选项无效。

    基于前面五个实验的总结

    Dockerfile的命令命令是否可以被覆盖是否可以添加选项
    CMD cal可以被覆盖不能添加选项,添加选项后会报错
    CMD [“cal”]可以被覆盖不能添加选项,添加选项后会报错
    ENTRYPOINT cal不可以被覆盖,添加的命令会被忽略不能添加选项,添加的选项被忽略
    ENTRYPOINT [“cal”]不可以被覆盖,添加命令后会报错可以添加选项
    ENTRYPOINT [“/bin/bash”,“-c”,“cal”]不可以被覆盖,添加的命令会被忽略不能添加选项,添加的选项被忽略

    在总结之前先来看看docker run命令的语法:

    image-20230911161656508

    可以看到:IMAGE的后面是可以接命令和参数的,但命令和参数并不是必须的,所以用 [ ] 括起来了。所以结论如下:

    1. shell命令格式和exec命令格式的区别:

      对于 shell 形式的 ENTRYPOINT 或者 CMD,docker daemon 会创建一个新的 /bin/bash shell 进程,并在这个新进程中运行你的命令。这意味着你的命令会在一个新的 shell 环境中运行,这个环境有它自己的环境变量,且和启动容器的环境是隔离的。

      这与 exec 形式不同,exec 形式直接在 Docker 容器的主进程中运行命令,没有额外创建 shell 进程。这就是为什么 exec 形式可以接收 docker run 附加的参数。

    2. CMD指令:

      Dockerfile 中的 CMD 指令是可以被docker run 命令中的[COMMAND]替代的。也就是说,如果docker run命令中的 IMAGE 后仍有内容,此时docker daemon 首先会将IMAGE后面的[COMMAND]替换掉CMD指令中的[COMMAND],如果有两个或两个以上的内容,docker daemon会认为是从第二个内容开始后面的都是[ARG]。所以,添加的-y 会报错,这是因为没有-y 这样的[COMMAND]。

    3. ENTRYPOINT指令:

      如果Dockerfile中的[EXECUTABLE]是通过 ENTRYPOINT 指定的,则该镜像的启动命令 docker run 中是可以添加参数[ARG]的。也就是说,ENTRYPOINT指定的命令是不可被替代的,并且如果IMAGE后面还有内容,这些内容会被作为参数传递给ENTRYPOINT指定的命令。但加上参数后如果有语法错误,那么docker daemon就会忽略该参数。

    最后的总结:基于以上三个结论,下面我就写一下每种命令执行的底层原理。

    1. 对于CMD-shell来说,首先docker daemon会fork一个新进程,该进程就是一个shell环境。如果docker run 命令后面的IMAGE没有命令和参数,那么docker daemon会将Dockerfile里面的CMD-shell命令放在这个新shell里面执行;如果docker run 命令后面的IMAGE有命令和参数,那么会将IMAGE后面的命令和参数放在新shell里面执行。在这个新的 shell 环境有它自己的环境变量,且和启动容器的环境是隔离的。
    2. 对于CMD-exec来说,命令的执行环境就是运行容器的主进程的环境。如果docker run 命令后面的IMAGE没有命令和参数,那么docker daemon会将Dockerfile里面的CMD-shell命令放在运行容器的主进程的环境执行;如果docker run 命令后面的IMAGE有命令和参数,那么IMAGE后面的命令和参数将会替换掉Dockerfile里面的CMD-exec命令,也就是只执行IMAGE后面的命令和参数
    3. 对于ENTRYPOINT-shell来说,首先docker daemon会fork一个新进程,该进程就是一个shell环境。如果docker run 命令后面的IMAGE没有命令和参数,那么docker daemon会将Dockerfile里面的 ENTRYPOINT-shell 命令放在这个新shell里面执行;如果docker run 命令后面的IMAGE有命令和参数,那对不起,IMAGE后面所有的命令和参数都会被丢弃
    4. 对于ENTRYPOINT-exec来说,命令的执行环境就是运行容器的主进程的环境。如果docker run 命令后面的IMAGE没有命令和参数,那么docker daemon会将Dockerfile里面的ENTRYPOINT-exec命令放在运行容器的主进程的环境执行;如果docker run 命令后面的IMAGE有命令和参数,那么docker daemon会将IMAGE后面所有的命令和参数追加到Dockerfile里面的ENTRYPOINT-exec命令的后面,但是如果追加后有语法错误,那么就不会追加了。最后在运行容器的主进程的环境执行命令
    5. 最后就是ENTRYPOINT [“/bin/bash”,“-c”,“cal”]的执行原理了,其实这有点类似于shell和exec两种形式的结合版,对于最后这个命令的底层执行原理请读者自行理解。不过需要注意的是cal -y的执行结果和/bin/bash -c cal -y的执行结果是不一样的;而 cal -y 和 /bin/bash -c “cal -y” 这两条命令的执行结果是一样的。

    CMD 与 ENTRYPOINT 组合使用

    这两个指令都用于指定容器启动时要执行的命令,无论哪个指令,每个 Dockerfile 中都只能有一个 CMD/ENTERYPOINT 指令,多个 CMD/ENTERYPOINT 指令只会执行最后一个。如果同时存在多个CMD 和 ENTRYPOINT,Docker 只会执行最后一个。此外,CMD 和 ENTRYPOINT 可以配合使用。当 ENTRYPOINT 和 CMD 同时存在时,CMD 中的内容会被作为 ENTRYPOINT 的参数。在这种模式下,docker run 命令后面的参数会覆盖 CMD 的内容。

    验证如下:

    # 新建Dockerfile6
    vim Dockerfile6
    # 写入以下三行内容
    FROM centos:7
    CMD ["hello world"]
    ENTRYPOINT ["echo"]
    # 构建镜像
    docker build -f Dockerfile6 -t my-cal:6.0 .
    # 运行镜像
    docker run -it my-cal:6.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果如下:

    image-20230911185712380

  • 相关阅读:
    在.Core中用EF添加数据库实体类
    python使用pandas中的read_csv函数读取csv数据为dataframe、查看dataframe数据中是否包含重复数据
    qt中加载qss样式不生效的问题
    Linux--vim
    多线程之一(进程理解、线程理解与创建、Thread类、线程状态)
    java计算机毕业设计网上图书分享系统源码+系统+mysql数据库+lw文档+部署
    93. 复原 IP 地址
    10 个用于网络管理员进行高级扫描的端口扫描工具
    Django聚合分组查询(F与Q查询|ORM查询优化|常见字段参数)
    Python [sortedcontainers]有序容器库使用不完全指南
  • 原文地址:https://blog.csdn.net/qq_54015483/article/details/132823037