镜像的定制实际上就是定制每一层所添加的配置、文件。我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,这个脚本就是Dockerfile。Dockerfile是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
FROM指令
该指令指定基础镜像,然后对镜像进行定制。
FROM ubuntu:16.04
Docker还存在一个特殊的镜像,名为scratch,它表示一个空白镜像,如果你一scratch为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像的第一层。对于Linux下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch会让镜像体积更加小巧。
示例:
FROM scratch
…
RUN指令
RUN指令是用来执行命令行命令的。其格式有两种:
shell格式:RUN <命令>
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
exec格式: RUN [“可执行文件”, “参数1”, “参数2”]
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
COPY指令
复制文件指令,格式如下:
COPY <源路径> <容器内目标路径>
## 示例
COPY a.txt /usr/text/
## 多个源文件
COPY a.txt b.txt /usr/text/
## 通配符形式
COPY hom* /mydir/
COPY hom?.txt /mydir/
ADD指令
ADD和COPY的格式和性质基本一致。但是在COPY基础上增加了一些功能。比如<源路径>可以是一个URL,这种情况下,Docker引擎会试图去下载这个链接的文件放到<目标路径>去。
ADD适合需要自动解压缩的场合,因此可以遵循这样的原则,所有的文件复制均使用COPY指令,仅在需要自动解压缩的场合使用ADD。
CMD指令
就是用于指定容器主进程默认启动命令的。格式如下:
shell格式:CMD <命令>
exec格式: CMD [“参数1”,“参数2”, …]
参数列表格式:CMD [“参数1”,“参数2”, …]。在指定了ENTRYPOINT指定后,用CMD指定具体的参数。
ENTRYPOINT指令
ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数。ENTRYPOINT在运行时也可以替代,不过比CMD要略显繁琐,需要通过docker run 的参数 --entrypoint来指定。当指定了ENTRYPOINT后,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给ENTRYPOINT指令。
ENV指令
该指令用于设置环境变量,格式有两种:
ENV
ENV = =
这个指令很简单,就是设置环境变量而已,无论是后面的其他指令,如RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
ENV VERSION=1.0 DEBUG=on NAME="Leisure"
$VERSION # 使用环境变量
下列指令可以支持环境变量:ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD
ARG指令
ARG指令用于构建参数,和ENV的效果一样,都是设置环境变量。格式如下:
ARG <参数名>[=<默认值>]
和ENV不同的是,ARG所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用ARG保存密码之类的信息,因为docker history还是可以看到所有值的。
Dockerfile中的ARG指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令docker build中用–build-arg <参数名>=<值>来覆盖
VOLUME指令
该指令用于定义匿名卷,格式为:
VOLUME ["<路径1>","<路径2>", …]
VOLUME <路径>
VOLUME /data
运行时可以覆盖这个挂载设置:
docker run -d -v mydata:/data mysql:5.7
在这行命令中,就使用了mydata这个命名卷挂载到了/data这个位置,替代了Dockerfile中定义的匿名卷的挂载配置。
EXPOSE指令
该指令用于声明端口,格式为:
EXPOSE <端口1> [<端口2> …]
EXPOSE指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
声明端口的好处:
1)帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
2)在运行时使用随机端口映射时,也就是docker run -P时,会自动随机映射EXPOSE的端口。
WORKDIR指令
该指令用于指定工作目录,格式为:
WORKDIR <工作目录路径>
使用WORKDIR指令可以来指定工作目录(或称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR会帮你建立目录。
初学者可能把Dockerfile等同于Shell脚本来书写,这种错误理解还可能会导致初心下面这样的错误:
RUN cd /app
RUN echo "hello" > world.txt
如果将这个Dockerfile进行构建镜像运行后,会发现找不到/app/world.txt文件。
USER指令
该指令用于指定当前用户,格式为
USER <用户名>
USER指令和WORKDIR相似,都是改变环境状态并影响以后的层。USER只是帮你切换到指定用户,这个用户必须是事先建立好的,否则无法切换。
ONBUILD指令
ONBUILD是一个特殊的指令,它后面跟的是其他指令,比如RUN,COPY等,而这些指令,在当前镜像构件时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。Dockerfile中的其他指令都是为了定制当前镜像而准备的,唯有ONBUILD是为了帮助别人定制自己而准备的。
MAINTAINER指令
用于指定作者,格式为:
MAINTAINER
MAINTAINER leisure <leisure.wang>