Docker 镜像、容器和 Dockerfile 三者之间的关系如上图所示
使用 Dockerfile 定义镜像,运行镜像启动容器。
官文: https://docs.docker.com/engine/reference/builder/
官文Blog :Best practices for writing Dockerfiles
## Dockerfile文件格式
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# 1、第一行必须指定 基础镜像信息
FROM ubuntu
# 2、维护者信息
MAINTAINER docker_user docker_user@email.com
# 3、镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 4、容器启动执行指令
CMD /usr/sbin/nginx
Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动执行指令。
https://docs.docker.com/engine/reference/builder/#from
FROM 指定所创建镜像的基础镜像
MAINTAINER 制定维护者信息
RUN 运行命令
CMD 容器启动是默认执行的命令
LABEL 指定生成镜像的元数据标签信息
EXPOSE 声明镜像内服务所监听的端口
ENV 指定环境变量
ADD 复制指定src路径的内容到容器的dest路径下,如果src为tar文件,则自动解压到dest路径下
copy 复制指定src路径的内容到镜像的dest路径下
ENTERPOINT 指定镜像的默认入口
VOLUME 创建数据卷挂载点
USER 指定运行容器是的用户名或UID
WORKDIR 配置工作目录
ARG 指定镜像内使用的参数
ONBUILD 配置当所创建的镜像作为其他镜像的基础镜像时,所执行创建操作指令
STOPSIGAL 容器退出信号值
HEALTHCHECK 如何进行健康检查
SHELL 指定使用shell的默认shell类型
下面详细展开
https://docs.docker.com/engine/reference/builder/#from
FROM 指令用于指定其后构建新镜像所使用的基础镜像。FROM 指令必是 Dockerfile 文件中的首条命令,启动构建流程后,Docker 将会基于该镜像构建新镜像,FROM 后的命令也会基于这个基础镜像。
通过 FROM 指定的镜像,可以是任何有效的基础镜像。
需要注意的事项如下:
https://docs.docker.com/engine/reference/builder/#run
在镜像的构建过程中执行特定的命令,并生成一个中间镜像。
RUN <command>
#exec格式
RUN ["executable", "param1", "param2"]
https://docs.docker.com/engine/reference/builder/#copy
COPY 指令将从构建上下文目录中 <源路径>
的文件/目录复制到新的一层的镜像内的<目标路径>
位置
COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"]
和 RUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。
COPY package.json /usr/src/app/
<源路径>
可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>
可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。
ADD 指令和 COPY 的格式和性质基本一致。
在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。
另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
设置环境变量
格式有两种:
ENV <key> <value>
这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。
为构建的镜像设置监听端口,使容器在运行时监听
EXPOSE <port> [<port>...]
EXPOSE 指令并不会让容器监听 host 的端口,如果需要,需要在 docker run 时使用 -p、-P 参数来发布容器端口到 host 的某个端口上。
VOLUME用于创建挂载点,即向基于所构建镜像创始的容器添加
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。
CMD用于指定在容器启动时所要执行的命令
CMD 有以下三种格式:
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
省略可执行文件的 exec 格式,这种写法使 CMD 中的参数当做 ENTRYPOINT
的默认参数,此时 ENTRYPOINT
也应该是 exec 格式,具体与 ENTRYPOINT
的组合使用,参考 ENTRYPOINT
。
与 RUN 指令的区别:RUN 在构建的时候执行,并生成一个新的镜像,CMD 在容器运行的时候执行,在构建时不进行任何操作。
ENTRYPOINT 指定这个容器启动的时候要运行的命令,可以追加命令. ENTRYPOINT 用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置为默认程序。
ENTRYPOINT 有以下两种形式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
ENTRYPOINT
与 CMD
非常类似,不同的是通过docker run
执行的命令不会覆盖 ENTRYPOINT
,而docker run命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT
。
Dockerfile
中只允许有一个 ENTRYPOINT
命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT
指令。
ENTRYPOINT
,且会覆盖 CMD
命令指定的参数。如,执行docker run <image> -d
时,-d 参数将被传递给入口点。
docker run --entrypoint
重写 ENTRYPOINT
入口点。如:可以像下面这样指定一个容器执行程序:
ENTRYPOINT ["/usr/bin/nginx"]
USER 用于指定运行镜像所使用的用户
USER daemon
使用USER指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。以下都是合法的指定试:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
使用USER指定用户后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过 docker run 运行容器时,可以通过 -u 参数来覆盖所指定的用户。
WORKDIR用于在容器内设置一个工作目录
https://docs.docker.com/engine/reference/builder/#workdir
WORKDIR /path/to/workdir
通过WORKDIR设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。
如,使用WORKDIR设置工作目录:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
在以上示例中,pwd 最终将会在 /a/b/c 目录中执行。在使用 docker run 运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
LABEL用于为镜像添加元数据,元数以键值对的形式指定:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。
推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。 如,通过LABEL指定一些元数据:
LABEL version="1.0" description="artisanLearnDocker" by="artisan"
指定后可以通过docker inspect查看:
docker inspect itbilu/test
"Labels": {
"version": "1.0",
"description": "artisanLearnDocker",
"by": "ITartisan"
},
ARG用于指定传递给构建运行时的变量:
ARG <name>[=<default value>]
如,通过ARG指定两个变量:
ARG site
ARG build_user=artisan
以上我们指定了 site 和 build_user 两个变量,其中 build_user 指定了默认值。
在使用 docker build 构建镜像时,可以通过 --build-arg <varname>=<value>
参数来指定或重设置这些变量的值。
docker build --build-arg site=artisan.com -t artisan/test .
这样我们构建了 artisan/test 镜像,其中site会被设置为 artisan.com,由于没有指定 build_user,其值将是默认值artisan。
ONBUILD用于设置镜像触发器
ONBUILD [INSTRUCTION]
当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。 如,当镜像被使用时,可能需要做一些处理:
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
STOPSIGNAL用于设置停止容器所要发送的系统调用信号:
STOPSIGNAL signal
所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。
SHELL用于设置执行命令(shell式)所使用的的默认 shell 类型:
SHELL ["executable", "parameters"]
SHELL在Windows环境下比较有用,Windows 下通常会有 cmd 和 powershell 两种 shell,可能还会有 sh。
这时就可以通过 SHELL 来指定所使用的 shell 类型:
FROM microsoft/windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello