RUN vs CMD vs ENTRYPOINT - 每天5分钟玩转 Docker 容器技

作者:编程技术

简单的说

<instruction> ["executable", "param1", "param2", ...]

7.2 MAINTAINER

用法:

MAINTAINER <name>

指定创建镜像的用户

RUN 有两种使用方式

  • RUN
  • RUN 每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像,后续的RUN都在之前RUN提交后的镜像为基础,镜像是分层的,可以通过一个镜像的任何一个历史提交点来创建,类似源码的版本控制。

     

    exec 方式会被解析为一个 JSON 数组,所以必须使用双引号而不是单引号。exec 方式不会调用一个命令 shell,所以也就不会继承相应的变量,如:

    这种方式是不会达到输出 HOME 变量的,正确的方式应该是这样的
    

     

    RUN产生的缓存在下一次构建的时候是不会失效的,会被重用,可以使用--no-cache选项,即docker build --no-cache,如此便不会缓存。
    

     

    ### 7.3 CMD

    CMD有三种使用方式:

    • CMD CMD指定在 Dockerfile 中只能使用一次,如果有多个,则只有最后一个会生效。

       

      CMD的目的是为了在启动容器时提供一个默认的命令执行选项。如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

      CMD会在启动容器的时候执行,build 时不执行,而RUN只是在构建镜像的时候执行,后续镜像构建完成之后,启动容器就与RUN无关了,这个初学者容易弄混这个概念,这里简单注解一下。

       

      ### 7.4 EXPOSE

      EXPOSE <port> [<port>...]
      

      告诉 Docker 服务端容器对外映射的本地端口,需要在 docker run 的时候使用-p或者-P选项生效。

      ### 7.5 ENV

      ENV <key> <value>       # 只能设置一个变量
      ENV <key>=<value> ...   # 允许一次设置多个变量
      

      指定一个环节变量,会被后续RUN指令使用,并在容器运行时保留。

      例子:

      等同于
      

       

      7.6 ADD
      
      ADD <src>... <dest>
      

      ADD复制本地主机文件、目录或者远程文件 URLS 从 并且添加到容器指定路径中 。

      支持通过 Go 的正则模糊匹配,具体规则可参见 

    • 路径必须是绝对路径,如果 不存在,会自动创建对应目录

    • 路径必须是 Dockerfile 所在路径的相对路径
    • 如果是一个目录,只会复制目录下的内容,而目录本身则不会被复制

    ### 7.7 COPY

    COPY <src>... <dest>
    

    COPY复制新文件或者目录从 并且添加到容器指定路径中 。用法同ADD,唯一的不同是不能指定远程文件 URLS。

    ### 7.8 ENTRYPOINT

    • ENTRYPOINT 配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,而CMD是可以被覆盖的。如果需要覆盖,则可以使用docker run --entrypoint选项。

       

      每个 Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效。

      #### Exec form ENTRYPOINT 例子

      通过ENTRYPOINT使用 exec form 方式设置稳定的默认命令和选项,而使用CMD添加默认之外经常被改动的选项。

      通过 Dockerfile 使用ENTRYPOINT展示前台运行 Apache 服务
      

       

      FROM debian:stable
      RUN apt-get update && apt-get install -y --force-yes apache2
      EXPOSE 80 443
      VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
      ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
      

      #### Shell form ENTRYPOINT 例子

      这种方式会在/bin/sh -c中执行,会忽略任何CMD或者docker run命令行选项,为了确保docker stop能够停止长时间运行ENTRYPOINT的容器,确保执行的时候使用exec选项。

      如果在ENTRYPOINT忘记使用exec选项,则可以使用CMD补上:
      

       

      7.9 VOLUME
      
      创建一个可以从本地主机或其他容器挂载的挂载点,后续具体介绍。
      

       

      ### 7.10 USER

      指定运行容器时的用户名或 UID,后续的RUN、CMD、ENTRYPOINT也会使用指定用户。
      

       

      ### 7.11 WORKDIR

      为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
      

       

      最终路径是/a/b/c。
      

       

      WORKDIR指令可以在ENV设置变量之后调用环境变量:

      最终路径则为 /path/$DIRNAME。
      

       

      ### 7.12 ONBUILD

      配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
      

       

      例如,Dockerfile 使用如下的内容创建了镜像 image-A:

      如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用 FROM image-A 指定基础镜像时,会自动执行 ONBUILD 指令内容,等价于在后面添加了两条指令。
      

       

      使用ONBUILD指令的镜像,推荐在标签中注明,例如 ruby:1.9-onbuild。
      

       

      ### 7.13 Dockerfile Examples

      # Nginx
      #
      # VERSION               0.0.1
      
      FROM      ubuntu
      MAINTAINER Victor Vieux <victor@docker.com>
      
      RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
      
      # Firefox over VNC
      #
      # VERSION               0.3
      
      FROM ubuntu
      
      # Install vnc, xvfb in order to create a 'fake' display and firefox
      RUN apt-get update && apt-get install -y x11vnc xvfb firefox
      RUN mkdir ~/.vnc
      # Setup a password
      RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
      # Autostart firefox (might not be the best way, but it does the trick)
      RUN bash -c 'echo "firefox" >> /.bashrc'
      
      EXPOSE 5900
      CMD    ["x11vnc", "-forever", "-usepw", "-create"]
      
      # Multiple images example
      #
      # VERSION               0.1
      
      FROM ubuntu
      RUN echo foo > bar
      # Will output something like ===> 907ad6c2736f
      
      FROM ubuntu
      RUN echo moo > oink
      # Will output something like ===> 695d7793cbe4
      
      # You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
      # /oink.
      

      ### 7.14 docker build

      参考文档:
      7.15 dockerfile 最佳实践
      
      • 使用.dockerignore文件

      为了在docker build过程中更快上传和更加高效,应该使用一个.dockerignore文件用来排除构建镜像时不需要的文件或目录。例如,除非.Git在构建过程中需要用到,否则你应该将它添加到.dockerignore文件中,这样可以节省很多时间。

      • 避免安装不必要的软件包

      为了降低复杂性、依赖性、文件大小以及构建时间,应该避免安装额外的或不必要的包。例如,不需要在一个数据库镜像中安装一个文本编辑器。

      • 每个容器都跑一个进程

      在大多数情况下,一个容器应该只单独跑一个程序。解耦应用到多个容器使其更容易横向扩展和重用。如果一个服务依赖另外一个服务,可以参考 

    • 最小化层

    我们知道每执行一个指令,都会有一次镜像的提交,镜像是分层的结构,对于Dockerfile,应该找到可读性和最小化层之间的平衡。

    • 多行参数排序

    如果可能,通过字母顺序来排序,这样可以避免安装包的重复并且更容易更新列表,另外可读性也会更强,添加一个空行使用换行:

    RUN apt-get update && apt-get install -y 
      bzr 
      cvs 
      git 
      mercurial 
      subversion
    
    • 创建缓存

    镜像构建过程中会按照Dockerfile的顺序依次执行,每执行一次指令 Docker 会寻找是否有存在的镜像缓存可复用,如果没有则创建新的镜像。如果不想使用缓存,则可以在docker build时添加--no-cache=true选项。

    从基础镜像开始就已经在缓存中了,下一个指令会对比所有的子镜像寻找是否执行相同的指令,如果没有则缓存失效。在大多数情况下只对比Dockerfile指令和子镜像就足够了。ADD和COPY指令除外,执行ADD和COPY时存放到镜像的文件也是需要检查的,完成一个文件的校验之后再利用这个校验在缓存中查找,如果检测的文件改变则缓存失效。RUN apt-get -y update命令只检查命令是否匹配,如果匹配就不会再执行更新了。

    为了有效地利用缓存,你需要保持你的 Dockerfile 一致,并且尽量在末尾修改。

     

    #### Dockerfile 指令

    • FROM: 只要可能就使用官方镜像库作为基础镜像
    • RUN: 为保持可读性、方便理解、可维护性,把长或者复杂的RUN语句使用分隔符分成多行
      • 不建议RUN apt-get update独立成行,否则如果后续包有更新,那么也不会再执行更新
      • 避免使用RUN apt-get upgrade或者dist-upgrade,很多必要的包在一个非privileged权限的容器里是无法升级的。如果知道某个包更新,使用apt-get install -y xxx
      • 标准写法
        • RUN apt-get update && apt-get install -y package-bar package-foo

    例子:

    RUN apt-get update && apt-get install -y 
        aufs-tools 
        automake 
        btrfs-tools 
        build-essential 
        curl 
        dpkg-sig 
        git 
        iptables 
        libapparmor-dev 
        libcap-dev 
        libsqlite3-dev 
        lxc=1.0* 
        mercurial 
        parallel 
        reprepro 
        ruby1.9.1 
        ruby1.9.1-dev 
        s3cmd=1.1.0*
    
    • CMD: 推荐使用CMD [“executable”, “param1”, “param2”…]这种格式,CMD [“param”, “param”]则配合ENTRYPOINT使用
    • EXPOSE: Dockerfile 指定要公开的端口,使用docker run时指定映射到宿主机的端口即可
    • ENV: 为了使新的软件更容易运行,可以使用ENV更新PATH变量。如ENV PATH /usr/local/nginx/bin:$PATH确保CMD ["nginx"]即可运行

    ENV也可以这样定义变量:

    ENV PG_MAJOR 9.3
    ENV PG_VERSION 9.3.4
    RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
    ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
    
    • ADDorCOPY:ADD比COPY多一些特性「tar 文件自动解包和支持远程 URL」,不推荐添加远程 URL

    如不推荐这种方式:

    推荐使用 curl 或者 wget 替换,使用如下方式:
    

     

    RUN mkdir -p /usr/src/things 
        && curl -SL http://example.com/big.tar.gz 
        | tar -xJC /usr/src/things 
        && make -C /usr/src/things all
    

    如果不需要添加 tar 文件,推荐使用COPY。

分分快三计划 1

执行 docker run <image> 将输出:

Dockerfile 有以下指令选项:

Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。

在为 ENTRYPOINT 选择格式时必须小心,因为这两种格式的效果差别很大。

Docker 可以通过 Dockerfile 的内容来自动构建镜像。Dockerfile 是一个包含创建镜像所有命令的文本文件,通过docker build命令可以根据 Dockerfile 的内容构建镜像,在介绍如何构建之前先介绍下 Dockerfile 的基本语法结构。

先回顾一下通过 Dockerfile 构建镜像的过程:

 

7.1 FROM

用法:

FROM <image>

或者

FROM <image>
  • FROM指定构建镜像的基础源镜像,如果本地没有指定的镜像,则会自动从 Docker 的公共库 pull 镜像下来。
  • FROM必须是 Dockerfile 中非注释行的第一个指令,即一个 Dockerfile 从FROM语句开始。
  • FROM可以在一个 Dockerfile 中出现多次,如果有需求在一个 Dockerfile 中创建多个镜像。
  • 如果FROM语句没有指定镜像标签,则默认使用latest标签。

分分快三计划 2

Exec 格式

  • FROM
  • MAINTAINER
  • RUN
  • CMD
  • EXPOSE
  • ENV
  • ADD
  • COPY
  • ENTRYPOINT
  • VOLUME
  • USER
  • WORKDIR
  • ONBUILD

例如

<instruction> <command>

这是 CMD 的推荐格式。

 

如果希望使用环境变量照如下修改

运行容器将输出:

RUN 在当前镜像的顶部执行命令并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。

ENTRYPOINT 看上去与 CMD 很像,它们都可以指定要执行的命令及其参数。不同的地方在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。

Exec 格式CMD ["executable","param1","param2"]

运行容器将输出:

目录 bunch:由 ADD 指令从 build context 复制的归档文件 bunch.tar.gz,已经自动解压。

RUN 指令通常用于安装应用和软件包。

Shell 格式ENTRYPOINT command param1 param2

Hello, Cloud Man

当指令执行时会直接调用 不会被 shell 解析。

 

当指令执行时shell 格式底层会调用 /bin/sh -c 。

ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。

注意apt-get update 和 apt-get install 被放在一个 RUN 指令中执行这样能够保证每次安装的是最新的包。如果 apt-get install 在单独的 RUN 中执行则会使用 apt-get update 创建的镜像层而这一层可能是很久以前缓存的。

 

设置容器启动时运行的命令。

CMD

第二种格式 CMD ["param1","param2"] 要与 Exec 格式 的 ENTRYPOINT 指令配合使用其用途是为 ENTRYPOINT 设置默认的参数。我们将在后面讨论 ENTRYPOINT 时举例说明。

我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式,二者在使用上有细微的区别。

下面来看 Exec 格式。

 

在 ubuntu-with-vi-dockerfile 镜像上直接添加一层就得到了新的镜像 ubuntu-with-vi-dockerfile-2。

ENTRYPOINT echo "Hello world" 

但当后面加上一个命令比如 docker run -it [image] /bin/bashCMD 会被忽略掉命令 bash 将被执行

比如下面的 Dockerfile 片段:

执行 docker build:

 cvs

我们来看一个调试的例子。Dockerfile 内容如下:

 

运行容器 docker run -it [image] 将输出

注意环境变量 name 已经被值 Cloud Man 替换。

构建镜像:

 bzr

从这个过程可以看出,如果 Dockerfile 由于某种原因执行到某个指令失败了,我们也将能够得到前一个指令成功执行构建出的镜像,这对调试 Dockerfile 非常有帮助。我们可以运行最新的这个镜像定位指令失败的原因

此命令会在容器启动且 docker run 没有指定其他命令时运行。

分分快三计划 3

下面看看 CMD 是如何工作的。Dockerfile 片段如下:

如果 WORKDIR 不存在,Docker 会自动为我们创建。

 

举例说明,比如交换前面 RUN 和 COPY 的顺序:

下面来看 Exec 格式。

指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。

ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]

运行容器将输出

当指令执行时,shell 格式底层会调用 /bin/sh -c <command> 。

原文

ENTRYPOINT

由 Dockerfile 可知 httpd 的 base 镜像为 debian,正好之前已经下载过 debian 镜像,所以有缓存可用。通过 docker history 可以进一步验证。

ENTRYPOINT ["/bin/echo", "Hello world"]

RUN apt-get install -y mypackage=$MY_VERSION

 

虽然在逻辑上这种改动对镜像的内容没有影响,但由于分层的结构特性,Docker 必须重建受影响的镜像层。

CMD ["/bin/echo", "Hello world"]  

分分快三计划 4

Shell 格式

CMD 有三种格式

CMD echo "Hello world"  

我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令Shell 格式和 Exec 格式二者在使用上有细微的区别。

RUN 有两种格式:

② WORKDIR 中保存了我们希望的文件和目录:

Exec 格式

分分快三计划 5

下面我们详细分析。

当容器通过 docker run -it [image] 启动时输出为

 

如果 Docker 镜像的用途是运行应用程序或服务比如运行一个 MySQL应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数同时可利用 docker run 命令行替换默认参数。

例如:

CMD 设置容器启动后默认执行的命令及其参数但 CMD 能够被 docker run 后面跟的命令行参数替换。

  1. Shell 格式:RUN

  2. Exec 格式:RUN ["executable", "param1", "param2"]

分分快三计划 6

到这里,我们已经具备编写 Dockerfile 的能力了。如果大家还觉得没把握,推荐一个快速掌握 Dockerfile 的方法:去 Docker Hub 上参考那些官方镜像的 Dockerfile

ENTRYPOINT 看上去与 CMD 很像它们都可以指定要执行的命令及其参数。不同的地方在于 ENTRYPOINT 不会被忽略一定会被执行即使运行 docker run 时指定了其他命令。

 mercurial

重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕。

运行容器 docker run -it [image] 将输出:

在前面的 Dockerfile 中添加一点新内容,往镜像中复制一个文件:

  1. 使用 RUN 指令安装应用和软件包,构建镜像。

  2. 如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。

  3. 如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。

ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数同时可通过 CMD 提供额外的参数。

下面是使用 RUN 安装多个包的例子:

在容器中运行指定的命令。

而如果通过 docker run -it [image] CloudMan 启动,则输出为:

COPY ["src", "dest"]

CMD 有三种格式:

COPY src dest

  1. Exec 格式:CMD ["executable","param1","param2"]
    这是 CMD 的推荐格式。

  2. CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。

  3. Shell 格式:CMD command param1 param2

docker pull 命令输出显示第一层已经存在,不需要下载。

ENV name Cloud Man  

例如

ENTRYPOINT 有两种格式:

注:Dockerfile 支持以“#”开头的注释。

RUN apt-get update && apt-get install -y  

除了构建时使用缓存,Docker 在下载镜像时也会使用。例如我们下载 httpd 镜像。

root@10a32dc7d3d3:/#

③ 执行 COPY 指令。

  1. RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。

  2. CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run 后面跟的命令行参数替换。

  3. ENTRYPOINT 配置容器启动时运行的命令。

ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。

  1. 如果 docker run 指定了其他命令,CMD 指定的默认命令将被忽略。

  2. 如果 Dockerfile 中有多个 CMD 指令,只有最后一个 CMD 有效。

将文件从 build context 复制到镜像。

ENV name Cloud Man  

CMD

CMD ["world"]

下面是使用 RUN 安装多个包的例子

 

RUN 有两种格式

 

举例说明。

当指令执行时,会直接调用 <command>,不会被 shell 解析。
例如下面的 Dockerfile 片段:

CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数此时 ENTRYPOINT 必须使用 Exec 格式。

Hello world

分分快三计划 7分分快三计划 8

ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。

分分快三计划 9

Hello, $name

比如下面的 Dockerfile 片段

当容器通过 docker run -it [image] 启动时,输出为:

运行容器,验证镜像内容:

RUN ["apt-get", "install", "python3"]  

① 确保 testfile 已存在。

ENTRYPOINT echo "Hello, $name" 

注意环境变量“name”没有被替换。

Exec 和 Shell 格式前面已经介绍过了。
第二种格式 CMD ["param1","param2"] 要与 Exec 格式 的 ENTRYPOINT 指令配合使用,其用途是为 ENTRYPOINT 设置默认的参数。我们将在后面讨论 ENTRYPOINT 时举例说明。

ENTRYPOINT 中的参数始终会被使用而 CMD 的额外参数可以在容器启动时动态替换掉。

CMD 指令允许用户指定容器的默认执行的命令。

下面列出了 Dockerfile 中最常用的指令,完整列表和说明可参看官方文档。

Hello world

例如下面的 Dockerfile 片段

Hello CloudMan

ENTRYPOINT

RUN

手工执行 RUN 指令很容易定位失败的原因是 busybox 镜像中没有 bash。虽然这是个极其简单的例子,但它很好地展示了调试 Dockerfile 的方法。

Shell 和 Exec 格式

与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。

Shell 格式

执行类似 docker commit 的操作,生成一个新的镜像层。

 

重点在这里:之前已经运行过相同的 RUN 指令,这次直接使用缓存中的镜像层 35ca89798937。

ENTRYPOINT ["/bin/echo", "Hello"]  

Exec 格式RUN ["executable", "param1", "param2"]

ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。

到这里相信大家对 Dockerfile 的功能和使用流程有了比较完整的印象,但还没有系统学习 Dockerfile 的各种指令和实际用法,下节会开始这个主题。

注意环境变量“name”没有被替换。
如果希望使用环境变量,照如下修改

在上面这些指令中,RUN、CMD、ENTRYPOINT 很重要且容易混淆,下节专门讨论。

例如下面的 Dockerfile 片段:

Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。

Hello, Cloud Man

好了我们已经学习完如何创建自己的 image下一节讨论如何分发 image。

ENTRYPOINT ["/bin/echo", "Hello, $name"]

Shell 格式RUN

RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。

而如果通过 docker run -it [image] CloudMan 启动则输出为

RUN apt-get install python3  

CMD 指令允许用户指定容器的默认执行的命令。

  1. Exec 格式:ENTRYPOINT ["executable", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式。

  2. Shell 格式:ENTRYPOINT command param1 param2

root@10a32dc7d3d3:/#

CMD 和 ENTRYPOINT 推荐使用 Exec 格式,因为指令可读性更强,更容易理解。RUN 则两种格式都可以。

如果 docker run 指定了其他命令CMD 指定的默认命令将被忽略。

例如:

Hello, $name

简单的说:

文件 tmpfile1:由 RUN 指令创建。

注意:apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包。如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的。

分分快三计划 10

 

下面看看 CMD 是如何工作的。Dockerfile 片段如下

最佳实践

Hello, Cloud Man

 

从 base 镜像运行一个容器。

好了,我们已经学习完如何创建自己的 image,下一节讨论如何分发 image。

分分快三计划 11

ENV name Cloud Man  

分分快三计划 12

 git

从上面的输出可以看到生成了新的镜像层 bc87c9710f40,缓存已经失效。

 subversion

使用 RUN 指令安装应用和软件包构建镜像。

ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。

COPY 支持两种形式:

RUN、CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似,很容易混淆。本节将通过实践详细讨论它们的区别。

如果我们希望在构建镜像时不使用缓存,可以在 docker build 命令中加上 --no-cache参数。

CMD echo "Hello world"

RUN

分分快三计划 13

包括 Dockerfile 在内的任何脚本和程序都会出错。有错并不可怕,但必须有办法排查,所以本节讨论如何 debug Dockerfile。

但当后面加上一个命令,比如 docker run -it [image] /bin/bash,CMD 会被忽略掉,命令 bash 将被执行:

① 进入容器,当前目录即为 WORKDIR。

Hello CloudMan

RUN 执行命令并创建新的镜像层RUN 经常用于安装软件包。

Hello world

CMD 和 ENTRYPOINT 推荐使用 Exec 格式因为指令可读性更强更容易理解。RUN 则两种格式都可以。

设置镜像的作者,可以是任意字符串。

Hello world

如果想为容器设置默认的启动命令可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。

下面我们来看一个较为全面的 Dockerfile:

也就是说,如果我们改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。

下面我们详细分析。

ENTRYPOINT 有两种格式

Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。

注意环境变量 name 已经被值 Cloud Man 替换。

Exec 和 Shell 格式前面已经介绍过了。

...

Docker 再基于刚刚提交的镜像运行一个新容器。

运行容器将输出

ENTRYPOINT 配置容器启动时运行的命令。

分分快三计划 14

Exec 格式ENTRYPOINT ["executable", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式。

分分快三计划 15

Exec 格式

分分快三计划 16

例如下面的 Dockerfile 片段

分分快三计划 17

在为 ENTRYPOINT 选择格式时必须小心因为这两种格式的效果差别很大。

到这里我们已经具备编写 Dockerfile 的能力了。如果大家还觉得没把握推荐一个快速掌握 Dockerfile 的方法去 Docker Hub 上参考那些官方镜像的 Dockerfile

其过程是启动临时容器,复制 testfile,提交新的镜像层 8d02784a78f4,删除临时容器。

如果 Dockerfile 中有多个 CMD 指令只有最后一个 CMD 有效。

容器启动时运行指定的命令。

是时候系统学习 Dockerfile 了。

为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。

分分快三计划 18

CMD echo "Hello world"

分分快三计划 19

Shell 格式CMD command param1 param2

Hello, Cloud Man

调试 Dockerfile

将文件或目录声明为 volume。我们会在容器存储部分详细讨论。

Dockerfile 在执行第三步 RUN 指令时失败。我们可以利用第二步创建的镜像 22d31cc52b3e 进行调试,方式是通过 docker run -it 启动镜像的一个容器。

分分快三计划 20

Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。

分分快三计划 21分分快三计划 22

执行一条指令,对容器做修改。

② 依次执行 Dockerfile 指令,完成构建。

...

设置环境变量,环境变量可被后面的指令使用。例如:

ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。

分分快三计划 23

① 构建前确保 build context 中存在需要的文件。

文件 tmpfile2:由 COPY 指令从 build context 复制。

指定 base 镜像。

RUN 指令通常用于安装应用和软件包。

RUN、CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似很容易混淆。本节将通过实践详细讨论它们的区别。

分分快三计划 24

此命令会在容器启动且 docker run 没有指定其他命令时运行。

本文由分分快三计划发布,转载请注明来源

关键词: 技术 教程 docker 玩转