最佳实践

  • 不安装无效的软件包
  • 理想情况下,每个镜像应该还有一个进程
  • 无法避免使用多进程时,应选择合理的初始化进程(init process)
  • 最小化层数
    • 最新版的docker只有COPY ADD RUN会创建新层。其他指令创建临时层,不会增加镜像大小。
    • 多条指定可以通过连字符连接成为一条指令以减少层数
    • 通过多段构建减少镜像层数
  • 优先把变更频率低的编译放在镜像底层,以便使用 build cache
  • 复制文件时,每个文件应该独立复制,确保每个文件变更时,只影响该文件对应的缓存

WeChat31c6d92e40440cfe2a1cf1eb3f6eb3a8.png

.dockerignore file

在build镜像时不想包含的内容需要放进.dockerignore,否则build时会将所指定的目录中的文件全部加载,然后在开始build。如果文件比较多,加载时间会比较长。
.dockerignore 常见用法

  1. # comment
  2. */temp*
  3. */*/temp*
  4. temp?

规则

规则 行为
# comment Ignored.
*/temp* 排除根目录的任何一级目录下以 temp 开头的文件或者目录。比如 /somedir/temporary.txt或 /somedir/temp
*/*/temp* 排除根目录的任何二级目录下以 temp 开头的文件或者目录。
比如, /somedir/subdir/temporary.txt
temp? 排除根目录下以 temp 开头的文件或者目录。如, /tempa and /tempb
*/.go 排除任何层级目录下以 .go 结尾的文件或者目录。

FROM

三种格式

  1. FROM [--platform=<platform>] <image> [AS <name>]
  2. FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
  3. FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
  • FROM在一个Dockerfile中可以多次出现
  • AS 可以用在多次阶段构建时被后边的 FROM 或者 COPY —from= 引用
  • —platform可以是 linux/amd64, linux/arm64, or windows/amd64
  • 在FROM之前的ARG是独立的,只能被FROM使用,不能被FROM后的指令使用

RUN

  • RUN <command> 默认用 /bin/sh -c (Linux) 或 cmd /S /C (Windows) 执行
  • RUN ["executable", "param1", "param2"] (exec form)

下面的三种形式的效果相同。

  1. RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
  1. RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
  1. RUN ["/bin/bash", "-c", "echo hello"]

CMD 和 ENTRYPOINT

在使用 Dockerfile 时,有一个叫作 ENTRYPOINT 的原语。实际上,它和 CMD 都是 Docker 容器进程启动所必需的参数,完整执行格式是:ENTRYPOINT CMD

默认情况下,Docker 会提供一个隐含的 ENTRYPOINT,即: /bin/sh -c 。所以,在不指定 ENTRYPOINT 时,比如在这个例子里,实际上运行在容器里的完整进程是: /bin/sh -c "python app.py" ,即 CMD 的内容就是 ENTRYPOINT 的参数。

启动容器时执行的Shell命令,同CMD类似,只是由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序。

CMD用于容器启动后默认执行的命令,支持三种格式,多条CMD仅最后一条生效。
Exec 格式:CMD [“executable”,”param1”,”param2”](推荐格式)
CMD [“param1”,”param2”] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。
Shell 格式:CMD command param1 param2

ENTRYPOINT用于容器启动以后执行的命令,支持两种格式,多条ENTRYPOINT仅最后一条生效。
Exec 格式:ENTRYPOINT [“executable”, “param1”, “param2”](推荐格式)
Shell 格式:ENTRYPOINT command param1 param2

docker run -entrypoint可替换ENTRYPOINT

区别:
如docker run 指定了其他命令,CMD 指定的默认命令和参数将被忽略,而ENTRYPOINT的命令和参数一定会执行。

如何使用

完整格式 ENTRYPOINT CMD

  • ENTRYPOINT和CMD使用其中一种,都可启动程序
  • CMD定义的是NETRYPOINT的默认行为,可以在run时使用命令行传递其他可选参数,使容器有多种行为
  • 这里的行为和exec时互不影响


LABEL

LABEL是镜像的元数据。

  1. LABEL <key>=<value> <key1>=<value1> <key2>=<value2> ...

配合label过滤器可以在查询时过滤镜像,如下

  1. docker images -f label=<key>=<value>

MAINTAINER (deprecated)

使用LABEL来替换

  1. LABEL maintainer="SvenDowideit@home.org.au"

EXPOSE

  1. EXPOSE <port> [<port>/<protocol>...]

举例

  1. EXPOSE 80/tcp
  2. EXPOSE 80/udp

EXPOSE可以被 -p 覆盖

  1. docker run -p 80:80/tcp -p 80:80/udp ...

如果使用docker run -P,则会生成一个随机端口映射到EXPOSE

ENV

设置的变量可以在后续的指令中和容器环境中被使用。

  1. ENV <key> <value>
  2. ENV <key>=<value> ...

在实际使用的时候可以覆盖

  1. docker run --env <key>=<value> ...

ADD 和 COPY

ADD 拷贝文件或目录,或者URL下载到镜像中,如果是URL或压缩包,会自动下载或自动解压。
COPY的功能相同,只是不支持下载解压,推荐用 ADD

  1. COPY [--chown=<user>:<group>] src ... dest

USER

为RUN、CMD和ENTRYPOINT执行Shell命令指定运行用户,例如:

  1. USER <user>[:<usergroup>]
  2. USER <UID>[:<UID>]

VOLUME

Volume 机制,允许你将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作。

  1. VOLUME ["/data"]

修改挂载点

  1. $ docker run -v /test ...
  2. $ docker run -v /home:/test ...

第一种情况,没有显示声明宿主机目录, Docker 就会默认在宿主机上创建一个临时目录 /var/lib/docker/volumes/[VOLUME_ID]/_data,然后把它挂载到容器的 /test 目录上。
第二种情况,Docker 就直接把宿主机的 /home 目录挂载到容器的 /test 目录上。

WORKDIR

设置工作目录,在这些指令中生效;也是容器的运行的目录。
RUN, CMD, ENTRYPOINT, COPY and ADD

  1. WORKDIR /path/to/workdir

ARG

在build时参数 --build-arg 被指定,可以设置默认值;但会被ENV覆盖
可以设置默认值

  1. FROM busybox
  2. ARG user1=someuser
  3. ARG buildno=1

预先定义的 ARG

  1. HTTP_PROXY
  2. http_proxy
  3. HTTPS_PROXY
  4. https_proxy
  5. FTP_PROXY
  6. ftp_proxy
  7. NO_PROXY
  8. no_proxy

ONBUILD

可以为镜像添加触发器。
当我们在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响。
但是当我们编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。
需要注意的是,如果是再利用B镜像构造新的镜像时,那个ONBUILD指令就无效了,也就是说只能再构建子镜像中执行,对孙子镜像构建无效。其实想想是合理的,因为在构建子镜像中已经执行了。

HEALTHCHECK

告诉Docker如何测试容器以检查它是否仍在工作,即健康检查,例如:

  1. HEALTHCHECK --interval=5m --timeout=3s \
  2. CMD curl -f http://localhost/ || exit 1

  其中,一些选项的说明:

  • —interval=DURATION (default: 30s):每隔多长时间探测一次,默认30秒
  • — timeout= DURATION (default: 30s):服务响应超时时长,默认30秒
  • —start-period= DURATION (default: 0s):服务启动多久后开始探测,默认0秒
  • —retries=N (default: 3):认为检测失败几次为宕机,默认3次

  一些返回值的说明:

  • 0:容器成功是健康的,随时可以使用
  • 1:不健康的容器无法正常工作
  • 2:保留不使用此退出代码

STOPSIGNAL

SHELL