Dockerfile的使用
Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
指令
FROM 指定基础镜像
基础镜像是必须指定的,而 FROM
就是指定 基础镜像,因此一个 Dockerfile
中 FROM
是必备的指令,并且必须是第一条指令。
scratch
: 空白镜像,以scratch
为基础镜像的话意味不以任何镜像为基础
RUN 执行命令
- shell格式:
RUN <命令>
1
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
- exec格式:
RUN ["可执行文件", "参数1", "参数2"]
每个RUN
指令都会在镜像上新建一层,所以尽量在一个RUN
指令中执行更多的命令,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM debian:stretch
RUN set -x; buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
COPY 复制文件
格式:
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
COPY
指令将从构建上下文目录中 <源路径>
的文件/目录复制到新的一层的镜像内的 <目标路径>
位置。
在使用该指令的时候还可以加上 --chown=<user>:<group>
选项来改变文件的所属用户及所属组。
ADD 更高级的复制文件
比如 <源路径>
可以是一个 URL
,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径>
去。下载后的文件权限自动设置为 600
,如果这并不是想要的权限,那么还需要增加额外的一层 RUN
进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN
指令进行解压缩。所以不如直接使用 RUN
指令,然后使用 wget
或者 curl
工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。
如果 <源路径>
为一个 tar
压缩文件的话,压缩格式为 gzip
, bzip2
以及 xz
的情况下,ADD
指令将会自动解压缩这个压缩文件到 <目标路径>
去。
CMD 容器启动命令
CMD
指令的格式和 RUN
相似,也是两种格式:
shell
格式:CMD <命令>
exec
格式:CMD ["可执行文件", "参数1", "参数2"...]
- 参数列表格式:
CMD ["参数1", "参数2"...]
。在指定了ENTRYPOINT
指令后,用CMD
指定具体的参数。
区别:
- RUN命令执行命令并创建新的镜像层,通常用于安装软件包
- CMD命令设置容器启动后默认执行的命令及其参数,但CMD设置的命令能够被
docker run
命令后面的命令行参数替换 - ENTRYPOINT配置容器启动时的执行命令(不会被忽略,一定会被执行,即使运行
docker run
时指定了其他命令)
ENTRYPOINT 入口点
ENTRYPOINT
的目的和 CMD
一样,都是在指定容器启动程序及参数。ENTRYPOINT
在运行时也可以替代,不过比 CMD
要略显繁琐,需要通过 docker run
的参数 --entrypoint
来指定。
当指定了 ENTRYPOINT
后,CMD
的含义就发生了改变,不再是直接的运行其命令,而是将 CMD
的内容作为参数传给 ENTRYPOINT
指令,换句话说实际执行时,将变为
1
<ENTRYPOINT> "<CMD>"
ENV 设置环境变量
格式有两种:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
ARG 构建参数
格式:ARG <参数名>[=<默认值>]
构建参数和 ENV
的效果一样,都是设置环境变量。所不同的是,ARG
所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。
VOLUME 定义匿名卷
格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile
中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
1
VOLUME /data
EXPOSE 暴露端口
格式为 EXPOSE <端口1> [<端口2>...]
。
EXPOSE
指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P
时,会自动随机映射 EXPOSE
的端口。
要将 EXPOSE
和在运行时使用 -p <宿主端口>:<容器端口>
区分开来。-p
,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE
仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
WORKDIR 指定工作目录
格式为 WORKDIR <工作目录路径>
。
使用 WORKDIR
指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR
会帮你建立目录。
USER 指定当前用户
格式:USER <用户名>[:<用户组>]
USER
指令和 WORKDIR
相似,都是改变环境状态并影响以后的层。WORKDIR
是改变工作目录,USER
则是改变之后层的执行 RUN
, CMD
以及 ENTRYPOINT
这类命令的身份。
HEALTHCHECK 健康检查
格式:
HEALTHCHECK [选项] CMD <命令>
:设置检查容器健康状况的命令HEALTHCHECK NONE
:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK
指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。
ONBUILD 为他人作嫁衣裳
格式:ONBUILD <其它指令>
ONBUILD
是一个特殊的指令,它后面跟的是其它指令,比如 RUN
, COPY
等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
LABEL 为镜像添加元数据
LABEL
指令用来给镜像以键值对的形式添加一些元数据(metadata)。
1
LABEL <key>=<value> <key>=<value> <key>=<value> ...
SHELL 指令
格式:SHELL ["executable", "parameters"]
构建镜像
1
docker build -t nginx:v3 .
.
代表当前目录,是docker构建镜像上下文的路径
docker build
命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎