美文网首页Docker
Dockerfile的ENTRYPOINT和CMD

Dockerfile的ENTRYPOINT和CMD

作者: CodingCode | 来源:发表于2018-12-29 13:26 被阅读0次

    Dockerfile的ENTRYPOINT和CMD都是用来定义命令的执行入口。

    1. 定义ENTRYPOINT
    $ cat Dockerfile 
    FROM oraclelinux
    ADD ./docker-entry.sh   /docker-entry.sh
    ENTRYPOINT /docker-entry.sh
    
    $ cat docker-entry.sh
    #!/usr/bin/env bash
    echo "Entry of ENTRYPOINT, ARGS[#]=$#"
    for ((i = 0; i <= $#; i++ )); do
      echo "ENTRYPOINT ARGS[${i}]=[${!i}]"
    done
    
    $ docker build -t testimage
    
    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=0
    

    在docker run的时候ENTRYPOINT指定的命令被调用了。

    1. 定义CMD
    $ cat Dockerfile 
    FROM oraclelinux
    ADD ./docker-cmd.sh   /docker-cmd.sh
    CMD /docker-cmd.sh
    
    $ cat docker-cmd.sh
    #!/usr/bin/env bash
    echo "Entry of CMD, ARGS[#]=$#"
    for ((i = 0; i <= $#; i++ )); do
      echo "CMD ARGS[${i}]=[${!i}]"
    done
    
    $ docker build -t testimage
    
    $ docker run --rm testimage
    Entry of CMD, ARGS[#]=0
    

    这里看起来,ENTRYPOINT和CMD的行为是一样的,没有啥区分。

    1. 同时定义ENTRYPOINT和CMD
    $ cat Dockerfile 
    FROM oraclelinux
    ADD ./docker-cmd.sh   /docker-cmd.sh
    ADD ./docker-entry.sh   /docker-entry.sh
    CMD        /docker-cmd.sh
    ENTRYPOINT /docker-entry.sh
    
    $ docker build -t testimage
    
    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=0
    
    • 同时定义了ENTRYPOINT和CMD时,CMD被忽略。
    1. ENTRYPOINT和CMD的两种写法

    4.1 SHELL
    格式:<ENTRYPOINT|CMD> executable param1 param2 ...
    4.2 EXEC
    格式:<ENTRYPOINT|CMD> ["executable", "param1", "param2", ...]

    1. 使用EXEC的方式重新执行上面三个case

    5.1 定义ENTRYPOINT

    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=0
    

    5.2 定义CMD

    $ docker run --rm testimage
    Entry of CMD, ARGS[#]=0
    

    5.3 同时定义ENTRYPOINT和CMD

    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[/docker-cmd.sh]
    

    看到没有5.3这里和前面使用SHELL格式的有重大不一样,CMD的内容被作为参数传递给了ENTRYPOINT,虽然目前ENTRYPOINT没有用到,但是我们知道就可以用了。

    1. 使用run自带命令

    6.1 ENTRYPOINT + SHELL格式

    $ docker run --rm testimage date
    Entry of ENTRYPOINT, ARGS[#]=0
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    

    6.2 CMD + SHELL格式

    $ docker run --rm testimage date
    Sun Dec 30 04:44:33 UTC 2018
    

    6.3 ENTRYPOINT + CMD + SHELL格式

    $ docker run --rm testimage date
    Entry of ENTRYPOINT, ARGS[#]=0
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    

    6.4 ENTRYPOINT + EXEC格式

    $ docker run --rm testimage date
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[date]
    

    6.5 CMD + EXEC格式

    $ docker run --rm testimage date
    Sun Dec 30 04:47:12 UTC 2018
    

    6.6 ENTRYPOINT + CMD + EXEC格式

    $ docker run --rm testimage date
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[date]
    
    1. 总结

    7.1. ENTRYPOINT和CMD都可以用来指定容器的入口命令。
    7.2 ENTRYPOINT具有优先权

    • 如果定义了ENTRYPOINT,那么执行ENTRYPOINT,忽略CMD
    • 如果没有定义ENTRYPOINT,那么执行CMD;如果CMD也没有则失败。

    7.3 在EXEC模式下,CMD会被作为ARG[1]传递给ENTRYPOINT

    • 这样ENTRYPOINT可以决定是否调用CMD的内容。
    • 在SHELL模式下则不会。
    • 如果没有ENTRYPOINT,如前所述,则CMD直接被执行了。

    7.3 docker run的时候如果后面指定命令,那么这个命令是CMD的替换。

    • 规则遵从CMD的处理流程。

    7.4 因此建议ENTRYPOINT和CMD均采用EXEC的调用方式

    • 这样CMD的内容可以被ENTRYPOINT调用,而且
    • 原始CMD的内容可以在命令行被替换。

    完整例子:

    $ cat Dockerfile
    FROM oraclelinux
    
    ADD ./docker-cmd.sh     /docker-cmd.sh
    ADD ./docker-entry.sh   /docker-entry.sh
    
    ENTRYPOINT  [ "/docker-entry.sh" ]
    CMD         [ "/docker-cmd.sh" ]
    
    $ docker build . -t testimage
    
    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[/docker-cmd.sh]
    $@=[/docker-cmd.sh]
    Entry of CMD, ARGS[#]=0
    CMD ARGS[0]=[/docker-cmd.sh]
    
    $ docker run --rm testimage date
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[date]
    $@=[date]
    Sun Dec 30 05:03:34 UTC 2018
    
    $ docker run --rm testimage date "+%s"
    Entry of ENTRYPOINT, ARGS[#]=2
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[date]
    ENTRYPOINT ARGS[2]=[+%s]
    $@=[date +%s]
    1546146222
    
    1. EXEC模式的缺陷

    8.1 EXEC不能使用环境变量

    例如在SHELL模式下:

    $ cat Dockerfile
    FROM oraclelinux
    
    ADD ./docker-entry.sh   /docker-entry.sh
    
    ENV VAR Hello
    
    ENTRYPOINT  "/docker-entry.sh" "${VAR}"
    
    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[Hello]
    $@=[Hello]
    

    而同样的功能如果在EXEC模式下:

    $ cat Dockerfile
    FROM oraclelinux
    
    ADD ./docker-entry.sh   /docker-entry.sh
    
    ENV VAR Hello
    
    ENTRYPOINT  [ "/docker-entry.sh", "${VAR}" ]
    
    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[${VAR}]
    $@=[${VAR}]
    

    这个环境变量$VAR没有被替换掉,而是源文本的方式穿下去了。

    解决这个问题的办法使用"bash -c"来调用ENTRYPOINT指令:

    $ cat Dockerfile
    FROM oraclelinux
    
    ADD ./docker-entry.sh   /docker-entry.sh
    
    ENV VAR Hello
    
    ENTRYPOINT  [ "/bin/bash", "-c", "/docker-entry.sh ${VAR}" ]
    
    $ docker run --rm testimage
    Entry of ENTRYPOINT, ARGS[#]=1
    ENTRYPOINT ARGS[0]=[/docker-entry.sh]
    ENTRYPOINT ARGS[1]=[Hello]
    $@=[Hello]
    

    相关文章

      网友评论

        本文标题:Dockerfile的ENTRYPOINT和CMD

        本文链接:https://www.haomeiwen.com/subject/rzhvlqtx.html