添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
气势凌人的柚子  ·  Dockerfile 的 ...·  3 小时前    · 
悲伤的山羊  ·  Docker中的ENTRYPOINT与CMD ...·  3 小时前    · 
阳光的青蛙  ·  日期区间控件- ...·  1 周前    · 
愤怒的菠菜  ·  Cannot find symbol - ...·  3 周前    · 
爱喝酒的草稿纸  ·  Excel ...·  2 月前    · 

每个Dockerfile写到最后,都需要指定一个需要执行的命令,及其参数。 一个Docker容器,需要有且仅有一个前台进程在运行。 一旦这个进程结束了,那么容器本身的运行也就终结了。 而Dockerfile最后指定的这个命令,就是Docker容器的前台进程。

指定的方法,一般有两种, ENTRYPOINT CMD 。 二者表面上看不出区别,实际上却有巨大差异,也有内在联系。

每个Docker容器,都必须要有一个可执行(executable)文件或命令、及相关参数,作为执行入口(entrypoint)。 所以, ENTRYPOINT CMD ,二者在Dockerfile与 docker run 里,至少指定一个。

在执行 docker run args... <image> cmd... 时,镜像名称 <image> 后的所有内容,都被看做 CMD 。 它会覆盖镜像中写好的 CMD (如果有的话)。

如果使用 docker run --entrypoint /bin/bash <image> cmd ,可以复写ENTRYPOINT为 /bin/bash

使用区别

使用ENTRYPOINT和CMD的方式,大概分两种。 一是Dockerfile,二是 docker run 。 还有docker-compose.yml,其实和 docker run 差不多。

Dockerfile

  • ENTRYPOINT和CMD至少要有一个。
  • 使用 ENTRYPOINT entry arg0 形式,与CMD将没有任何配合。因此,除非特定需求,否则不推荐这种使用方式。
  • 右下角 entry arg0 /bin/sh -c cmd arg1 这种形式,几乎没有什么使用场景,反而是常见错误,应该尽量避免。
  • 本质上,其实可以理解为ENTRYPOINT是真正的Docker可执行入口,而CMD则是可选参数。 之所以在很多情况下直接写CMD也能生效,是因为ENTRYPOINT就相当于是指定Shell,而CMD则是指定Shell中执行的命令。 注意,只是『相当于』。

    docker run与docker-compose.yml

    docker run <image> cmd arg1 时,总是相当于CMD的 ["cmd", "arg1"] 形式。 此外,docker-compose.yml的情况与 docker run 类似。

    docker run 中使用 --entrypoint 参数时,限制非常大。 仅仅只能指定一个命令、或可执行文件,不能指定一个参数列表。

    $ docker run --entrypoint ls alpine /etc/passwd
    /etc/passwd
    $ docker run --entrypoint ls alpine -l /etc/passwd
    -rw-r--r--    1 root     root          1224 Apr 24  2017 /etc/passwd
    

    这时,如果希望把-l参数放到--entrypoint中,则无法做到。 (一些早期版本似乎是可以的。)

    $ docker run --entrypoint 'ls -l' alpine /etc/passwd
    container_linux.go:262: starting container process caused "exec: \"ls -l\": executable file not found in $PATH"
    docker: Error response from daemon: oci runtime error: container_linux.go:262: starting container process caused "exec: \"ls -l\": executable file not found in $PATH".
    ERRO[0001] error waiting for container: context canceled
    

    --entrypoint中,无法指定一个列表。 不过,docker-compose.yml文件中,倒是可以。

        image: alpine
        entrypoint:
        command: /etc/passwd
    

    注意PID

    原则上,一个Docker容器里应该只有一个进程,其PID为1。 Docker外部的操作,比如docker stop,就是向这个进程发送信号。 如果那个唯一的前台进程PID不为1,那么就会收不到信号,只能在超时(默认约10秒)后被kill。

    在Dockerfile中使用ENTRYPOINT entry arg0这种形式时,entry的位置总是应该使用exec,后面再接其它内容。 比如,ENTRYPOINT exec top,这可以确保top命令是PID为1的进程。 否则,ENTRYPOINT top的形式,PID为1的进程就是/bin/sh -c top,而top则被挤到了另外一个进程。

    例如,对一个如下的Dockerfile:

    FROM alpine
    ENTRYPOINT top
    

    执行以下的build与run操作:

    docker build -t top .
    docker run --rm -it --name test top
    

    在另一个Shell中,可以查看到以下结果:

    $ docker exec test ps
    PID   USER     TIME   COMMAND
        1 root       0:00 /bin/sh -c top
        7 root       0:00 top
        8 root       0:00 ps
    $ time docker stop test
    real	0m10.774s
    user	0m0.008s
    sys	0m0.004s
    

    如果换成ENTRYPOINT exec top,或者ENTRYPOINT ["top"],就可以避免这个问题。

    Docker版本

    本文中描述的部分内容,在早期的Docker版本中并不正确。 撰写本文时,测试用的Docker版本信息如下。

    $ docker version
    Client:
     Version:      17.10.0-ce
     API version:  1.33
     Go version:   go1.8.3
     Git commit:   f4ffd25
     Built:        Tue Oct 17 19:02:43 2017
     OS/Arch:      linux/amd64
    Server:
     Version:      17.10.0-ce
     API version:  1.33 (minimum version 1.12)
     Go version:   go1.8.3
     Git commit:   f4ffd25
     Built:        Tue Oct 17 19:01:22 2017
     OS/Arch:      linux/amd64
     Experimental: false