最佳实践
- 不安装无效的软件包
- 理想情况下,每个镜像应该还有一个进程
- 无法避免使用多进程时,应选择合理的初始化进程(init process)
- 最小化层数
- 最新版的docker只有COPY ADD RUN会创建新层。其他指令创建临时层,不会增加镜像大小。
- 多条指定可以通过连字符连接成为一条指令以减少层数
- 通过多段构建减少镜像层数
- 优先把变更频率低的编译放在镜像底层,以便使用 build cache
- 复制文件时,每个文件应该独立复制,确保每个文件变更时,只影响该文件对应的缓存
.dockerignore file
在build镜像时不想包含的内容需要放进.dockerignore
,否则build时会将所指定的目录中的文件全部加载,然后在开始build。如果文件比较多,加载时间会比较长。.dockerignore
常见用法
# comment
*/temp*
*/*/temp*
temp?
规则
规则 | 行为 |
---|---|
# comment |
Ignored. |
*/temp* |
排除根目录的任何一级目录下以 temp 开头的文件或者目录。比如 /somedir/temporary.txt或 /somedir/temp |
*/*/temp* |
排除根目录的任何二级目录下以 temp 开头的文件或者目录。比如, /somedir/subdir/temporary.txt |
temp? |
排除根目录下以 temp 开头的文件或者目录。如, /tempa and /tempb 。 |
*/.go | 排除任何层级目录下以 .go 结尾的文件或者目录。 |
FROM
三种格式
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
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)
下面的三种形式的效果相同。
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
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是镜像的元数据。
LABEL <key>=<value> <key1>=<value1> <key2>=<value2> ...
配合label过滤器可以在查询时过滤镜像,如下
docker images -f label=<key>=<value>
MAINTAINER (deprecated)
使用LABEL来替换
LABEL maintainer="SvenDowideit@home.org.au"
EXPOSE
EXPOSE <port> [<port>/<protocol>...]
举例
EXPOSE 80/tcp
EXPOSE 80/udp
EXPOSE可以被 -p
覆盖
docker run -p 80:80/tcp -p 80:80/udp ...
如果使用docker run -P
,则会生成一个随机端口映射到EXPOSE
。
ENV
设置的变量可以在后续的指令中和容器环境中被使用。
ENV <key> <value>
ENV <key>=<value> ...
在实际使用的时候可以覆盖
docker run --env <key>=<value> ...
ADD 和 COPY
ADD 拷贝文件或目录,或者URL下载到镜像中,如果是URL或压缩包,会自动下载或自动解压。
COPY的功能相同,只是不支持下载解压,推荐用 ADD
COPY [--chown=<user>:<group>] src ... dest
USER
为RUN、CMD和ENTRYPOINT执行Shell命令指定运行用户,例如:
USER <user>[:<usergroup>]
USER <UID>[:<UID>]
VOLUME
Volume 机制,允许你将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作。
VOLUME ["/data"]
修改挂载点
$ docker run -v /test ...
$ docker run -v /home:/test ...
第一种情况,没有显示声明宿主机目录, Docker 就会默认在宿主机上创建一个临时目录 /var/lib/docker/volumes/[VOLUME_ID]/_data,然后把它挂载到容器的 /test 目录上。
第二种情况,Docker 就直接把宿主机的 /home 目录挂载到容器的 /test 目录上。
WORKDIR
设置工作目录,在这些指令中生效;也是容器的运行的目录。RUN
, CMD
, ENTRYPOINT
, COPY
and ADD
WORKDIR /path/to/workdir
ARG
在build时参数 --build-arg
被指定,可以设置默认值;但会被ENV覆盖
可以设置默认值
FROM busybox
ARG user1=someuser
ARG buildno=1
预先定义的 ARG
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
ONBUILD
可以为镜像添加触发器。
当我们在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响。
但是当我们编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。
需要注意的是,如果是再利用B镜像构造新的镜像时,那个ONBUILD指令就无效了,也就是说只能再构建子镜像中执行,对孙子镜像构建无效。其实想想是合理的,因为在构建子镜像中已经执行了。
HEALTHCHECK
告诉Docker如何测试容器以检查它是否仍在工作,即健康检查,例如:
HEALTHCHECK --interval=5m --timeout=3s \
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:保留不使用此退出代码