Dockerfile最佳实践

Dockerfile最佳实践

Docker Version: 19.03.5

😄 Written by Zak Zhu

参考

一般准则

  • Create ephemeral containers

    Dockerfile构建的镜像应该生成尽可能短暂的容器。 “短暂”是指可以停止和销毁容器,然后对其进行重建和替换,并使用绝对的最小的设置和配置.

  • Exclude with .dockerignore

    使用.dockerignore文件排除不需要加载到build context内的文件或目录, 以提高构建效率.

    如何写.dockerignore文件, 详见官网文档: .dockerignore file

    EXAMPLE:

    下面.dockerignore示例来自于wushuiyong的walle-web项目

    1

  • Use multi-stage builds

    多阶段构建(即multi-stage builds)可以大幅度减小最终图像的大小, 而不必努力减少中间层和文件的数量.

    如何使用, 详见官网文档: Use multi-stage builds

  • Don't install unnecessary packages

    为了减少容器复杂度, 软件依赖度, 镜像大小和构建时间, 应该尽量避免安装不必要的软件包.

  • Decouple applications

    一个容器应该只运行一个进程.

    将应用解耦到多个容器中可以更轻松地水平扩展和重新使用容器.

    例如, Web应用堆栈可能由三个独立的容器组成, 每个容器具有自己独特的镜像, 以解耦的方式管理web application, database, in-memory cache.

  • Minimize the number of layers

    减少镜像层数量:

    1. 尽可能少使用RUN, COPY, ADD指令.
    2. 使用多阶段构建(即multi-stage builds).
  • Sort multi-line arguments

    尽可能通过字母数字排序和多行参数来简化以后的更改. 这有助于避免软件包重复, 并使列表更易于更新. 这也使PR易于阅读和查看. 在反斜杠\之前添加空格也有帮助.

    EXAMPLE:

    RUN apt-get update && apt-get install -y \
      bzr \
      cvs \
      git \
      mercurial \
      subversion
    
  • Leverage build cache

    When building an image, Docker steps through the instructions in your Dockerfile, executing each in the order specified. As each instruction is examined, Docker looks for an existing image in its cache that it can reuse.

    If you do not want to use the cache at all, you can use the --no-cache=true option on the docker build command.

    The basic rules that Docker follows are outlined below:

    • Starting with a parent 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 build 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.
    • For the ADD and COPY instructions, the contents of the files are examined and a checksum is calculated for each file. The last-modified and last-accessed times of the files 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 files, then the cache is invalidated.
    • Aside from the ADD and COPY commands, cache checking does 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 are not examined to determine if a cache hit exists. In that case just the command string itself is used to find a match.

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


细节建议

  1. Dockerfile书写顺序按照更新频度升序排列

    镜像分层是子层依赖父层, 对应到镜像构建缓存机制中, 如果某一层未命中缓存, 那么其剩下的层都不会使用缓存. 因此如果需要最大利用缓存机制, 推荐将变化频度低的指令尽量放上面, 变化频度高的指令放下面.

  2. FROM指令建议

    • 使用官方基础镜像
    • 指定具体镜像标签
  3. LABEL指令建议

    • 添加作者, 版本, 时间等信息
  4. RUN指令建议

    • 尽量使用一个RUN指令完成
    • 使用set -o pipefail避免管道错误被忽略
    • 指定需安装的软件包具体版本
    • 清空yumapt的缓存
    • 禁止使用yum upgradeapt upgrade
  5. ADDCOPY指令建议

    • File复制使用COPY, Tarball复制使用ADD
    • 不建议ADD从远程URL下载包, 推荐使用curlwget方式
    • 提前在build context目录下定义好文件权限
    • 使用指令的--chown选项指定文件属主和属组
  6. USER指令建议

    • If a service can run without privileges, use USER to change to a non-root user. Start by creating the user and group in the Dockerfile with something like RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres.
    • Consider an explicit UID/GID.
    • Consider setting /sbin/nologin to user's shell.
    • Avoid installing or using sudo as it has unpredictable TTY and signal-forwarding behavior that can cause problems. Consider using "gosu" instead.
    • Lastly, to reduce layers and complexity, avoid switching USER back and forth frequently.

工具分析

使用静态分析工具, 能够避免常见的错误, 建立工程师自动遵循的最佳实践指南.

posted @ 2020-03-02 16:28  ZakZhu  阅读(701)  评论(0编辑  收藏  举报