Dockerfile 操作建议

Docker可以读取一个Dockerfile文件来构建所需的镜像,这个文件里包含所有所需要的指令。Dockerfile文件用特有的格式来设置镜像信息,更多基础知识在Dockerfile页面会详细展示。如果你是初学Dockerile,你应该从那里学起。
本文包含Docker官方提供的一些践以及方法,我们强烈建议你去参照这些建议(事实上,如果你要创建一个包转的官方镜像,你必须遵从这些Tips。)

官方建议:

  1. 一个Dockerfile文件尽量越简洁越好,这意味着 它可以被停止销毁,然后被最小化配置安装到另一个地方。
  2. 在通常情况下,最好把Dockerfile文件放到一个空目录,然后,将构建镜像所需要动文件添加到该目录。为了提高构建性能,你也可以通过添加.dockerignore文件到该目录以排除文件和目录,该文件支持排斥的模式类似于.gitignore文件。有关创建信息,请参照.dockerignore file.
  3. 为了减少镜像复杂度、依赖、文件大小和构建时间,应该尽量避免安装多余的不需要包,例如:你不需要在一个数据库镜像中添加一个文本编辑器。
  4. 在绝大多数情况下,每一个镜像只跑一个process,应用于多个容器中可以方边应用横向扩展和重复利用容器。如果该服务依赖于其他服务,请使用容器互联。
  5. 你需要在Dockerfile的可读性和镜像层次最小化之间取得平衡,要有目的且非常谨慎的控制使用分层的数量
  6. 尽可能缓解由字母数字排序的多行参数后的变化。这将帮助你避免包的重复,使列表更容易更新。这也使得PRs更容易审查。在一个空格前面加一个反斜杠能起到帮助。

    下面是来自buildpack-DEPS形象的例子:

    1. RUN apt-get update && apt-get install -y \
    2. bzr \
    3. cvs \
    4. git \
    5. mercurial \
    6. subversion
  7. 构建缓存

    During the process of building an image Docker will step through the instructions in your Dockerfile executing each in the order specified. As each instruction is examined Docker will look for an existing image in its cache that it can reuse, rather than creating a new (duplicate) image. If you do not want to use the cache at all you can use the —no-cache=true option on the docker build command.

    However, if you do let Docker use its cache then it is very important to understand when it will, and will not, find a matching image. The basic rules that Docker will follow are outlined below:

    Starting with a base image that is already in the cache, the next instruction is compared against all child images derived from that base image to see if one of them was built using the exact same instruction. If not, the cache is invalidated.

    In most cases simply comparing the instruction in the Dockerfile with one of the child images is sufficient. However, certain instructions require a little more examination and explanation.

    For the ADD and COPY instructions, the contents of the file(s) in the image are examined and a checksum is calculated for each file. The last-modified and last-accessed times of the file(s) are not considered in these checksums. During the cache lookup, the checksum is compared against the checksum in the existing images. If anything has changed in the file(s), such as the contents and metadata, then the cache is invalidated.

    Aside from the ADD and COPY commands cache checking will not look at the files in the container to determine a cache match. For example, when processing a RUN apt-get -y update command the files updated in the container will not be examined to determine if a cache hit exists. In that case just the command string itself will be used to find a match.

    Once the cache is invalidated, all subsequent Dockerfile commands will generate new images and the cache will not be used.

Dockerfile 基本指令

指令的一般格式为 INSTRUCTION arguments,指令包括 FROM、MAINTAINER、RUN 等。

FROM

  1. 格式为 FROM <image>FROM <image>:<tag>。

第一条指令必须为 FROM 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令(每个镜像一次)。

MAINTAINER

  1. 格式为 MAINTAINER <name>,指定维护者信息。

RUN

  1. 格式为 RUN <command> RUN ["executable", "param1", "param2"]。

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

每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。

CMD

支持三种格式

  1. CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;
  2. CMD command param1 param2 /bin/sh 中执行,提供给需要交互的应用;
  3. CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。

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

EXPOSE

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

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

ENV

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

例如

  1. ENV PG_MAJOR 9.3
  2. ENV PG_VERSION 9.3.4
  3. RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
  4. ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADD

  1. 格式为 ADD <src> <dest>

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

COPY

  1. 格式为 COPY <src> <dest>

复制本地主机的 (为 Dockerfile 所在目录的相对路径)到容器中的

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

ENTRYPOINT

两种格式:

  1. ENTRYPOINT ["executable", "param1", "param2"]
  2. ENTRYPOINT command param1 param2shell中执行)。

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

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

VOLUME

  1. 格式为 VOLUME ["/data"]。

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

USER

  1. 格式为 USER daemon

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

当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要临时获取管理员权限可以使用 gosu,而不推荐 sudo。

WORKDIR

  1. 格式为 WORKDIR /path/to/workdir

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

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

  1. WORKDIR /a
  2. WORKDIR b
  3. WORKDIR c
  4. RUN pwd

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

ONBUILD

  1. 格式为 ONBUILD [INSTRUCTION]。

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

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

  1. [...]
  2. ONBUILD ADD . /app/src
  3. ONBUILD RUN /usr/local/bin/python-build --dir /app/src
  4. [...]

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

  1. FROM image-A
  2. #Automatically run the following
  3. ADD . /app/src
  4. RUN /usr/local/bin/python-build --dir /app/src

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