天天看点

Dockerfile指令详解

博文大纲: dockerfile基本结构 dockerfile常用指令 FROM——指定基础镜像 MAINTAINER——指定维护者信息 RUN——运行指令 COPY——复制文件\目录 ADD——更高级的复制文件\目录 ENV——设置环境变量 ARG——构建参数 EXPOSE——暴露端口 CMD——容器启动命令 ENTRYPOINT——入口点 ENTRYPOINT和CMD组合使用 VOLUME——定义匿名卷 USER——指定当前用户 WORKDIR——指定工作目录 ONBUILD——为他人做嫁衣

Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。

一般Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。如下:

其中,一开始必须指明所基于的镜像,接下来推荐说明维护者信息,再接下来就是镜像操作的指令,如RUN、COPY等。每运行一条指令,就会为镜像添加新的一层并提交,注:一个镜像最多不允许超过127层。最后时CMD指令,是指定运行容器时的操作指令。

格式为:FROM <image>或者 FROM <image>:<tag>。

第一条指令必须为FROM指令,如果在同一个dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次,但是一般不会这么做)。

格式为:MAINTAINER <name> <email>。用来指定维护者信息。

格式为:RUN <command> 或者RUN ["executable", "param1", "param2"]。

前者将在 shell 终端中运行命令,即 /bin/sh -c;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]。

每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。(注:如果觉得镜像的层数可能过多,可以一个RUN指令后面接多条指令,中间使用&&进行拼接即可)。

格式为:格式为 COPY <src> <dest>。

作用:复制本地的<src> (源文件/目录必须要与Dockerfile在相同的目录中)到容器中的<dest>。

当使用本地目录为源目录时,推荐使用COPY。

使用COPY时,所指定的源文件/目录,也可以是其他镜像中的文件,格式如下:

格式为:ADD <src> <dest>。它和COPY很相似,同样需要源文件和Dockerfile位于相同目录中,或者是一个URL。它比COPY更为人性化些。

该命令将复制指定的 <src> 到容器中的 <dest>。 其中 <src> 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL(自动下载URL所对应的文件);还可以是一个 tar 文件(自动解压为目录)。

在使用该指令的时候还可以加上 --chown=<user>:<group> 选项来改变文件的所属用户及所属组。

ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 ADD 命令了。

因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。

格式为 ENV <key> <value>。 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。

举个栗子:

格式:ARG <参数名>[=<默认值>]

构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。

在 1.13 之前的版本,要求 --build-arg 中的参数名,必须在 Dockerfile 中用 ARG 定义过了,换句话说,就是 --build-arg 指定的参数,必须在 Dockerfile 中使用了。如果对应参数没有被使用,则会报错退出构建。从 1.13 开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建。这对于使用 CI 系统,用同样的构建流程构建不同的 Dockerfile 的时候比较有帮助,避免构建命令必须根据每个 Dockerfile 的内容修改。

格式为:EXPOSE <port> [<port>...]。

该指令的作用是告诉docker服务端容器暴露的端口号,供互联系统使用,在启动容器时需要通过-P,docker主机会自动分配一个端口转发到指定的端口。

它支持以下三种格式: CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式; CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用; CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

作用是指定启动容器时执行的命令,每个dockerfile只有一条CMD命令,如果指定了多条,那么前面的会被覆盖,只有最后一条指令生效。

如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

如下:

一般我将CMD和ENTRYPOINT结合使用。也就是上面的第三种格式。

它支持下面两种格式: ENTRYPOINT ["executable", "param1", "param2"]; ENTRYPOINT command param1 param2(shell中执行)。

配置容器启动后执行的命令,并且不可被docker run提供的参数覆盖。

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

使用举例:

在某种情况下,ENTRYPOINT和CMD组合使用能发挥更大的作用。

组合使用ENTRYPOINT和CMD, ENTRYPOINT指定默认的运行命令, CMD指定默认的运行参数。

查看容器最后一条执行的命令如下:

Dockerfile指令详解

上面执行的命令是ENTRYPOINT和CMD指令拼接而成. ENTRYPOINT和CMD同时存在时, docker把CMD的命令拼接到ENTRYPOINT命令之后, 拼接后的命令才是最终执行的命令. 但是由于上文说docker run命令行执行时, 可以覆盖CMD指令的值. 如果你希望这个docker镜像启动后不是ping localhost, 而是ping其他服务器,, 可以这样执行docker run:

Dockerfile指令详解

下表列出了如果把Shell表示法和Exec表示法混合, 最终得到的命令行, 可以看到如果有Shell表示法存在, 很难得到正确的效果:

从上面看出, 只有ENTRYPOINT和CMD都用Exec表示法, 才能得到预期的效果。

容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

指令格式为:VOLUME ["/data"]。

作用:/data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:

在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。

这种方式是docker manager volumes数据持久化方式,不支持Bind mount挂载方式(也就是不支持指定本地的目录)。

在基于镜像运行容器后,可以通过命令“docker inspect container_name”查看容器的详细信息,在返回的结果中,查看MOUNT字段可以看到容器内对应的本地目录位置,如下:

返回的结果如下:

Dockerfile指令详解

命令格式为:USER <用户名>[:<用户组>]。

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

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

当然,和 WORKDIR 一样,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

如果以 root 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 su 或者 sudo,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 gosu。

格式为:WORKDIR /path/to/workdir。

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。

可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如

则最终路径为 /a/b/c。

格式为:ONBUILD [INSTRUCTION]。

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

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

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

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

———————— 本文至此结束,感谢阅读 ————————