Docker 镜像、容器 、Docker file
Docker 镜像、容器和 Dockerfile 三者之间的关系如上图所示
使用 Dockerfile 定义镜像,运行镜像启动容器。
概述
官文: https://docs.docker.com/engine/reference/builder/
官文Blog :Best practices for writing Dockerfiles
- Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。
- 镜像不包含任何动态数据,其内容在构建之后也不会被改变
- 镜像的定制实际上就是定制每一层所添加的配置、文件
如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
- Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
- 有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。
Docker File文件格式
## 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 分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动执行指令。
- 开始必须要指明所基于的镜像名称,
- 接下来一般会说明维护者信息;
- 后面则是镜像操作指令,例如 RUN 指令。每执行一条RUN 指令,镜像添加新的一层,并提交;
- 最后是 CMD 指令,来指明运行容器时的操作命令。
Docker File 解读
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类型
下面详细展开
1、FROM 指定基础镜像
https://docs.docker.com/engine/reference/builder/#from
FROM 指令用于指定其后构建新镜像所使用的基础镜像。FROM 指令必是 Dockerfile 文件中的首条命令,启动构建流程后,Docker 将会基于该镜像构建新镜像,FROM 后的命令也会基于这个基础镜像。
通过 FROM 指定的镜像,可以是任何有效的基础镜像。
需要注意的事项如下:
- FROM 必须 是 Dockerfile 中第一条非注释命令
- 在一个 Dockerfile 文件中创建多个镜像时,FROM 可以多次出现。只需在每个新命令 FROM 之前,记录提交上次的镜像 ID。
- tag 或 digest 是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像
2、RUN 执行命令
https://docs.docker.com/engine/reference/builder/#run
在镜像的构建过程中执行特定的命令,并生成一个中间镜像。
RUN <command> #exec格式 RUN ["executable", "param1", "param2"]
- RUN 命令将在当前 image 中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行 Dockerfile 中的下一个指令。
- 层级 RUN 指令和生成提交是符合 Docker 核心理念的做法。它允许像版本控制那样,在任意一个点,对 image 镜像进行定制化构建。
- RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定 --no-cache 参数,如:docker build --no-cache。
3、COPY 复制文件
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 进行管理的时候。
4、ADD 更高级的复制文件
ADD 指令和 COPY 的格式和性质基本一致。
在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。
另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
5、ENV 设置环境变量
设置环境变量
格式有两种:
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 下的行为是一致的。
6、EXPOSE
为构建的镜像设置监听端口,使容器在运行时监听
EXPOSE <port> [<port>...]
EXPOSE 指令并不会让容器监听 host 的端口,如果需要,需要在 docker run 时使用 -p、-P 参数来发布容器端口到 host 的某个端口上。
7、VOLUME 定义匿名卷
VOLUME用于创建挂载点,即向基于所构建镜像创始的容器添加
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
- 卷可以容器间共享和重用
- 容器并不一定要和其它容器共享卷
- 修改卷后会立即生效
- 对卷的修改不会对镜像产生影响
- 卷会一直存在,直到没有任何容器在使用它
VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。
8、CMD容器启动命令
CMD用于指定在容器启动时所要执行的命令
CMD 有以下三种格式:
CMD ["executable","param1","param2"] CMD ["param1","param2"] CMD command param1 param2
省略可执行文件的 exec 格式,这种写法使 CMD 中的参数当做 ENTRYPOINT
的默认参数,此时 ENTRYPOINT
也应该是 exec 格式,具体与 ENTRYPOINT
的组合使用,参考 ENTRYPOINT
。
与 RUN 指令的区别:RUN 在构建的时候执行,并生成一个新的镜像,CMD 在容器运行的时候执行,在构建时不进行任何操作。
9、ENTRYPOINT入口点
ENTRYPOINT 指定这个容器启动的时候要运行的命令,可以追加命令. ENTRYPOINT 用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置为默认程序。
ENTRYPOINT 有以下两种形式:
ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2
ENTRYPOINT
与CMD
非常类似,不同的是通过docker run
执行的命令不会覆盖ENTRYPOINT
,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT
。Dockerfile
中只允许有一个ENTRYPOINT
命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT
指令。- docker run运行容器时指定的参数都会被传递给
ENTRYPOINT
,且会覆盖CMD
命令指定的参数。如,执行docker run -d
时,-d 参数将被传递给入口点。 - 也可以通过
docker run --entrypoint
重写ENTRYPOINT
入口点。如:可以像下面这样指定一个容器执行程序:
ENTRYPOINT ["/usr/bin/nginx"]
10、USER 指定当前用户
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 参数来覆盖所指定的用户。
11、WORKDIR 指定工作目录
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参数覆盖构建时所设置的工作目录。
12、LABEL为镜像添加元数据
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" },
13、ARG构建参数
ARG用于指定传递给构建运行时的变量:
ARG <name>[=<default value>]
如,通过ARG指定两个变量:
ARG site ARG build_user=artisan
以上我们指定了 site 和 build_user 两个变量,其中 build_user 指定了默认值。
在使用 docker build 构建镜像时,可以通过 --build-arg =
参数来指定或重设置这些变量的值。
docker build --build-arg site=artisan.com -t artisan/test .
这样我们构建了 artisan/test 镜像,其中site会被设置为 artisan.com,由于没有指定 build_user,其值将是默认值artisan。
14、ONBUILD
ONBUILD用于设置镜像触发器
ONBUILD [INSTRUCTION]
当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。 如,当镜像被使用时,可能需要做一些处理:
[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
15、STOPSIGNAL
STOPSIGNAL用于设置停止容器所要发送的系统调用信号:
STOPSIGNAL signal
所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。
16、SHELL指令
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