DockerFile指令详解

DockerFire常用指令
DockerFire常用指令

基础知识

  • 每个保留关键字(指令)都是必须是大写字母
  • 执行从上到下顺序 执行
  • “#”表示注释
  • 每一个指令都会创建提交一个新的镜像层

FROM 指定基础镜像

通过FROM指定的镜像,可以是任何有效的基础镜像,但FROM有以下限制:

  • Dockerfile中第一条非注释命令必须是FROM

  • 在一个Dockerfile文件中创建多个镜像时,FROM可以多次出现。只需在每个新命令FROM之前,记录提交上次的镜像ID

  • tagdigest是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像

选择基础镜像的三个原则:

  • 官方镜像优于非官方的镜像
  • 固定版本的Tag,而不是每次都使用latest
  • 功能满足,选择体积小的镜像
1
2
3
4
5
6
格式:
  FROM <image>
  FROM <image>:<tag>
  FROM <image>@<digest>
示例:
  FROM mysql:5.6

MAINTAINER 维护者信息

1
2
3
4
5
6
格式:
MAINTAINER <name>
示例:
MAINTAINER docker_user
MAINTAINER docker_user@email.com
MAINTAINER docker_user <docker_user@email.com>

COPY 复制文件

COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的<目标路径>位置。

<源路径>可以是多个,甚至可以是通配符,<目标路径>可以是容器内的绝对路径,也可以是相对于工作目录的相对路径,目标路径不存在会自动创建

此外,源文件的各种元数据都会保留。如读、写、执行权限、文件变更时间等。

1
2
3
4
5
6
7
格式:
COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"]
示例:
COPY package.json /usr/src/app/ # 添加 "package.json" 到 /usr/src/app/
COPY hom* /mydir/ # 添加所有以"hom"开头的文件
COPY hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"

ADD 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。tar类型文件会自动解压,可以访问网络资源。

在 Docker 官方的 【Dockerfile 最佳实践文档]】中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。而且ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

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

1
2
3
4
5
6
7
8
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/

ENV 设置环境变量

ENV指令就是设置环境变量,后面的其它指令,还是运行时的应用,都可以直接使用这里定义的环境变量。

这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法。

docker run的时候可以使用 -e 覆盖或者添加变量

1
2
3
4
5
6
格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
示例:
ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"

ARG 构建参数

ARG用于指定传递给构建镜像时的变量,使用 docker build 构建镜像时,可以通过 --build-arg <varname>=<value> 参数来指定或重设置这些变量的值。

1
2
3
4
5
格式:
ARG <name>[=<default value>]
示例:
ARG site
ARG build_user=IT笔录

EXPOSE 暴露端口

EXPOSE 指令并不会让容器监听 host 的端口,如果需要,需要在 docker run 时使用 -p-P 参数来发布容器端口到 host 的某个端口上。

1
2
格式:
VOLUME ["/data"]

USER 指定当前用户

USER 用于指定运行镜像所使用的用户,使用USER指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。

使用USER指定用户后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过 docker run 运行容器时,可以通过 -u 参数来覆盖所指定的用户。

1
2
3
4
5
6
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group

WORKDIR 指定工作目录

WORKDIR用于在容器内设置一个工作目录,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。WORKDIR 指定的工作目录,必须是提前创建好的,可以看成cd命令。

在使用 docker run 运行容器时,可以通过 -w 参数覆盖构建时所设置的工作目录。

1
2
3
4
5
6
WORKDIR /a
WORKDIR b
WORKDIR c

#pwd 最终将会在 /a/b/c 目录中执行(WORKDIR可以看作是cd命令)
RUN pwd

LABEL 为镜像添加元数据

LABEL用于为镜像添加元数据,元数以键值对的形式指定,一条LABEL可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。

推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像

1
2
3
4
格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
  LABEL version="1.0" description="这是一个Web服务器" by="Docker"

ONBUILD 镜像触发器

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

1
2
3
4
5
格式:
ONBUILD [INSTRUCTION]
示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

RUN 构建执行命令

在镜像的构建过程中执行特定的命令,并生成一个中间镜像

  • RUN 命令将在当前 image 中执行任意合法命令并提交执行结果
  • RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定 --no-cache 参数,如:docker build --no-cache
1
2
3
4
5
6
7
8
9
10
11
12
13
shell 格式
格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式
格式:
RUN ["可执行文件", "参数1", "参数2"]

示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]

CMD 容器启动命令

CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

一个Dockerfile仅仅最后一个CMD起作用,docker run命令如果指定了命令会覆盖CMD命令。

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

1
2
3
4
5
6
7
格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...] # 推荐
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
示例:
CMD echo "This is a test."
CMD ["/usr/bin/wc","--help"]  

ENTRYPOINT 容器启动命令

ENTRYPOINT指定这个容器启动的时候要运行的命令,可以追加命令。

Dockerfile 中只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT 指令。

ENTRYPOINT 与 CMD 非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而是追加,且会覆盖 CMD 命令指定的参数