Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。我们一般会使用Dockerfile进行定制镜像(镜像的定制实际上就是定制每一层所添加的配置、文件)。
Dockerfile的基本结构
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。
常用指令:
FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。基础镜像是必须指定的。而 FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。我们可以从Docker store中使用官方的镜像作为基础镜像也可以使用scratch作为一个空白的基础镜像来进行定制。
语法:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
例:
FROM mysql:5.7
说明:
1.FROM 可以在单个 Dockerfile 镜像中多次出现以创建多个镜像,或者使用一个构建阶段作为另一个构建阶段的依赖项。只需在每条新 FROM 指令之前记下提交输出的最后一个镜像ID。每条 FROM 指令都清除先前的指令创建的任何状态;
2.tag 或 digest 值是可选的。如果省略其中任何一个,则构建器默认采用 latest 标记。如果找不到 tag 值,构建器将返回错误。
RUN 执行命令
RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:
1.shell 格式
RUN <命令>,就像直接在命令行中输入的命令一样。如:
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
会直接执行echo *****这条shell语句
2.exec 格式
RUN ["可执行文件", "参数1", "参数2"]
如:
RUN apt-get update
多条可以用&&链接如:
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
–auto-remove 删除无用的文件
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定–no-cache参数,如:docker build --no-cache
MAINTAINER: 维护者信息
格式: MAINTAINER <name>
构建镜像
docker build [选项] <上下文路径/URL/->
其中上下文URL中. 表示当前目录.当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个
路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就
会获得构建镜像所需的一切文件。
COPY 复制文件
COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"] 用于支持包含空格的路径,不会自动解压文件
如:
COPY package.json /usr/src/app/
COPY hom* /mydir/
<源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则。<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
ADD 复制文件
ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。比如 <源路径> 可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径> 去。下载后的文件权限自动设置为 600,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
CMD 容器启动命令
在容器启动时调用
shell 格式:CMD <命令>
exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
一般推荐第二种。这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 ",而不要使用单引号。
ENTRYPOINT 入口点
ENTRYPOINT 的目的和CMD一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:ENTRYPOINT-> CMD。
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
ENV 设置环境变量
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>... 如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
设置环境变量,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
ARG 构建参数
格式:ARG <参数名>[=<默认值>]
构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。
VOLUME 定义匿名卷
在容器运行时,尽量要保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。
格式为:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
VOLUME /data 指令时在运行时将数据自动挂载到/data中,如果要改变,则可以在运行容器时重新定义。
EXPOSE 暴露端口
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
格式: EXPOSE <端口1> [<端口2>...]
WORKDIR 指定工作目录
使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
格式: WORKDIR <工作目录路径>
USER 指定当前用户
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户。
USER <用户名>
HEALTHCHECK 健康检查
HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。和 CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效。
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK 支持下列选项:
--interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
--timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
--retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。
ONBUILD:用于设置镜像触发器
格式:ONBUILD <其它指令>
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。