每一条指令构建一层,描述该层如何构建。

术语

镜像构建上下文(Context)

docker是c/s架构,分客户端和服务端,客户端通过rest api与服务端通信完成各种任务。docker build 时,会将指定的上下文目录下的文件打包发给服务端(你可以使用.dockerignore 来除去不传的文件),那么像COPY、ADD这些涉及添加文件的指令,就能将发到服务器的文件打包进镜像中。这些命令,在操作源文件(src)是相对目录时,都是相对发到服务端的上下文目录的。

工作目录(WORKDIR)

镜像的工作目录。那么所有涉及操作的目标目录(dest)是相对目录时,一般是相对于该目录的。

指令

ARG

该指令一般用来指定构建时的变量默认值。from指令支持由第一个from之前出现的任何arg指令声明的变量

ARG设置默认值,供FROM命令使用:

  1. ARG VERSION=latest
  2. FROM busybox:${VERSION} # 解析结果:busybox:latest
  3. RUN echo done
  4. # 构建命令:docker build .

ARG设置默认值,供FROM和其他命令一起使用:

  1. ARG VERSION=latest
  2. FROM busybox:${VERSION} # 解析结果:busybox:latest
  3. ARG VERSION ## 如果非FROM命令也想使用FROM之前声明的变量的默认值,这里一定要来个空声明,后续命令才能使用
  4. RUN echo $VERSION # 解析结果:echo latest
  5. # 构建命令:docker build .

多次声明且初始化同一个变量:

  1. ARG VERSION=latest
  2. FROM busybox:${VERSION} # 解析结果:busybox:latest
  3. ARG VERSION=1.0.0
  4. RUN echo $VERSION # 解析结果:echo 1.0.0
  5. ARG VERSION=1.0.1
  6. RUN echo $VERSION # 解析结果:echo 1.0.1
  7. # 构建命令:docker build .

通过CLI覆盖内部声明的同名变量:

  1. ARG VERSION=1.0.0
  2. FROM busybox:${VERSION} # 解析结果:busybox:latest
  3. ARG VERSION=1.0.1
  4. RUN echo $VERSION # 解析结果:busybox:latest
  5. ARG VERSION=1.0.2
  6. RUN echo $VERSION # 解析结果:busybox:latest
  7. # 构建命令: docker build --build-arg VERSION=latest .

FROM

该指令用来指定基础镜像。
用法

  1. FROM <image> [AS <name>]
  2. FROM <image>[:<tag>] [AS <name>]
  3. FROM <image>[@<digest>] [AS <name>]
  • ARG 是唯一一个可先于FROM的命令
  • FROM 可以在出现多次,来创建多个镜像。或者把其中一个作为另外一个的依赖。注意只需在每条新的from指令之前记录commit输出的最后一个映像id。每条from指令都清除以前指令创建的任何状态。
  • 也可以通过将as name添加到from指令中,为新的生成阶段指定一个名称。该名称可以在后续的fromcopy --from=<name index>指令中使用,以引用在此阶段中生成的图像。
  • 标记或摘要值是可选的。如果忽略其中任何一个,则生成器默认采用最新的标记。如果生成器找不到标记值,则返回错误。

    ENV

    该指令用来声明变量。变量可在其他指令当中解析使用。

    声明语法

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

应用语法

  • $variable_name
  • ${``variable_name``} 带有大括号的写法可以解决没有空格的变量名字。如 ${for}_bar
  • ${variable:-word} 表示指示如果设置了变量,则结果将是该值。如果未设置变量,则结果为word。
  • ${variable:+word} 表示指示如果设置了变量,则结果为word,否则结果为空字符串。

word 可以是任何字符串,包括其他环境变量。

可以使用环境变量的命令

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • FROM
  • LABEL
  • STOPSIGNAL
  • USER
  • VOLUME
  • WORKDIR

    案例

  1. FROM busybox
  2. ENV foo /bar
  3. WORKDIR ${foo} # WORKDIR /bar
  4. ADD . $foo # ADD . /bar
  5. COPY \$foo /quux # COPY $foo /quux
  1. ENV abc=hello
  2. ENV abc=bye def=$abc # def=hell
  3. ENV ghi=$abc # ghi=bye

RUN

该指令用来定义每一层如何构建。每一条RUN指令执行后,都会commit这层修改,构成新的镜像。
RUN指令有2种形式:

  • RUN <command> (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
  • RUN ["executable", "param1", "param2"] (exec form)

如果2种方式执行命令是 shell, 那么就会存在环境变量替换。

CMD

该指令如果有多条,只有最后一个有效。
RUN指令有3种形式:

  • CMD ["executable","param1","param2"] (exec form, this is the preferred form)
  • CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
  • CMD command param1 param2 (shell form)

第一种方式和第三种方式的区别是:
第三种方式会放到shell来执行,即: /bin/sh -c "command param1 param2", 也就是说如果镜像里没有安装shell, 这种方式就执行失败。第一种方式则直接执行命令,不会借助shell来执行命令。

CMD指令在构建镜像阶段不执行。

LABEL

改制指令用来给镜像增加metadata,具有继承性,可包含多条LABEL指令。

EXPOSE

该指令用来通知docker,当前容器监听的端口。
使用方法:

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

该指令可以多次使用。如果不指定协议,默认是tcp。

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

可以在容器启动的时候,使用 -p来覆盖 EXPOSE 设置:

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

ADD

该指令用来复制文件、目录、远程文件到镜像的文件系统下。
使用方法:

  • ADD [--chown=<user>:<group>] <src>... <dest>
  • ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] (this form is required for paths containing whitespace)

COPY

该指令和ADD之指令一样,唯独比ADD少一个功能,就是不能添加远程文件。

ENTRYPOINT

该命令通常用来配置一个可执行命令,指定容器启动后运行的第一个命令。

该指令有2种用法:

  • ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
  • ENTRYPOINT command param1 param2 (shell form)

CMD 和 ENTRYPOINT 协作关系:

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

VOLUMN

在的镜像内创建了不可改变的目录。
用法:

  1. VOLUME ["/data"]

构建阶段,在volume声明之后,声明目录下发生的数据变化,都会被丢失。
宿主挂载的目录只能在容器启动时指定。

USER

该命令用来指定RUN CMD ENTRYPOINT等命令的用户和用户组。
用法:

  1. USER <user>[:<group>] # or
  2. USER <UID>[:<GID>]

WORKDIR

该指令用来制定容器的工作目录,可以使用多次,如果是相对目录,那么也是相对前一次制定的工作目录:

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

参考

官方dockerfile文档