更详细的资料可以参考 dockerfile_best-practices 和 Dockerfile reference
Dockerfile介绍
Dockerfile是由一系列命令和参数构成的脚本,一个Dockerfile里面包含了构建整个image的完整命令。Docker通过docker build从上到下的顺序运行Dockerfile中的一系列命令自动构建image
一般包含
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时执行指令
使用方法
docker build命令从Dockerfile和context构建image。context是PATH或URL处的文件。PATH本地文件目录。 URL是Git repository的位置。context以递归方式处理。因此,PATH包括任何子目录,URL包括repository及submodules
常用指令
FROM
指定基础镜像,必须为第一个命令。如果不以任何镜像为基础,那么写法为:FROM scratch,接下来所写的指令将作为镜像的第一层开始
语法格式 | 示例 | 备注 |
---|---|---|
FROM <image> [As <name>] | FROM mysql | |
FROM <image>[:<tag>] [As <name>] | FROM mysql:5.6 | tag是可选的 |
FROM <image>[@<digest>] [As <name>] | FROM mysql:xxxxxxxxx | digest是可选的 |
使用docker images –digests可以显式digest
[root@test25 ~]# docker images --digests
……
java 8-jdk sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d d23bdf5b1b1b 19 months ago 643MB
- tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
- 无论什么时候,尽可能使用最新的官方仓库作为你的的镜像基础
- 在Doekcerfile文件中ARG是唯一一个优先FROM的指令
- FROM可在同一个Dockerfile文件多次设置用来创建多个镜像,或者使用一个构建阶段作为另外一个构建阶段的依赖。只需要在每条新FROM前面提交输出的最后一个 镜像ID,每条FROM指令都会清除先前指令创建的任何状态
- 可以通过添加AS name到FROM指令,将名称赋予新的构建阶段。该名称可用于后续FROM和 COPY –from=<name|index>指令,以引用此阶段构建的镜像
RUN
RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像,构建时执行,区别于CMD,CMD在容器启动的时候运行
语法格式 | 示例 | 备注 |
---|---|---|
RUN <command> | RUN /bin/bash -c ‘source $HOME/.bashrc; echo $HOME’ | shell执行,RUN后面直接跟shell命令 |
RUN [“executable”, “param1”, “param2”] | RUN [“/bin/bash”, “-c”, “echo hello”] | exec执行,类似于函数调用 |
注意
- RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定–no-cache参数
- Dockerfile中每一个指令都会建立一层,多少个RUN就构建了多少层镜像,写多个RUN会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错,为使Dockerfile 更加易读,易懂和便于维护,复杂的 RUN 语句用反斜杠()分割成多行
可能apt-get是run使用频率最高的应用,因为它安装了包,注意以下两点
- 避免RUN apt-get upgrade和dist-upgrade,因为父镜像中的许多“essential”包无法在非特权容器内升级 。如果父镜像中包含的包已过期,请与其维护人员联系。如果您知道有foo需要更新的特定包,请使用 apt-get install -y foo自动更新。
- 始终在同一 声明中结合RUN apt-get update使用
RUN apt-get update && apt-get install -y \
package-bar
RUN 指令可以使用管道
RUN wget -O - https://some.site | wc -l > /number
CMD
构建容器后调用,也就是在容器启动时才进行调用。
语法格式 | 示例 | 备注 |
---|---|---|
CMD [“executable”,”param1”,”param2”] | CMD [“/usr/bin/wc”,”–help”] | 执行可执行文件,优先 |
CMD [“param1”,”param2”] | CMD [“- -help”] | 设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数 |
CMD command param1 param2 | CMD echo “This is a test.” | wc - | 执行shell内部命令 |
注意:
- CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
- 这里边包括参数的一定要用双引号,不能是单引号,原因是参数传递后,docker解析的是一个JSON array
LABEL
用于为镜像指定标签,添加元数据
语法格式 | 示例 | 备注 |
---|---|---|
LABEL <key>=<value> <key>=<value> <key>=<value> … | LABEL version=”1.0” | 多个LABEL最好就写成一行,如太长需要换行的话则使用\符号 |
注意:
- 使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
- LABEL会继承基础镜像种的LABEL,如遇到key相同,则值覆盖
EXPOSE
指定于外界交互的端口,即容器在运行时监听的端口
语法格式 | 示例 | 备注 |
---|---|---|
EXPOSE <port> [<port>/<protocol>…] | EXPOSE 8081 8082 |
注意:
- EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
- 默认是TCP
ENV
设置环境变量
语法格式 | 示例 | 备注 |
---|---|---|
ENV <key> <value> | ENV name yuling | 一次设置一个 |
ENV <key>=<value> … | ENV name=yueling age=100 | 一次设置多个 |
ADD
一个复制命令将本地文件复制到容器中,tar类型文件会自动解压。可以访问网络资源,类似wget
语法格式 | 示例 | 备注 |
---|---|---|
ADD <src>… <dest> | ADD hom* /mydir/ ADD test relativeDir/ |
示例为通配、绝对路径 相对路径 |
ADD [“<src>”,… “<dest>”] | ADD “test a” “/absoluteDir/” | 示例为带空格、绝对路径 |
注意:
- <dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径
- <src>可以是一个本地文件或者是一个本地压缩文件(可以是Dockerfile所在目录的一个相对路径),还可以是一个url
- 尽量不要把<scr>写成一个文件夹,如果<src>是一个文件夹了,复制整个目录的内容,包括文件系统元数据
与Dockerfile不在同一目录的文件怎么使用ADD命令?
比如docker build -t test-image:latest -f /src/build/Dockerfile /src
Dockerfile必须在context即“/src:目录或其子目录。假如/src有两个目录build和code,Dockerfile在/src/build下,你要把code目录加进去,在Dockerfile里就可以写”ADD code /code”
COPY
复制命令,功能类似ADD,但是不会自动解压文件,也不能访问网络资源
语法格式 | 示例 | 备注 |
---|---|---|
COPY <src>… <dest> | COPY hom* /mydir/ COPY test relativeDir/ |
示例为通配、绝对路径 相对路径 |
COPY [“<src>”,… “<dest>”] | COPY “test a” “/absoluteDir/” | 示例为带空格、绝对路径 |
注意:
- 不会自动解压文件,也不能访问网络资源
- src的相对路径为Dockerfile所在目录
ENTRYPOINT
启动时的默认命令,配置给容器一个可执行的命令,这意味着在每次使用镜像创建容器时一个特定的应用程序可以被设置为默认程序。同时也意味着该镜像每次被调用时仅能运行指定的应用。ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,指定多个时靠后的设置会覆盖前面的设置,而只执行最后的ENTRYPOINT指令
语法格式 | 示例 | 备注 |
---|---|---|
ENTRYPOINT [“executable”, “param1”, “param2”] | ENTRYPOINT [“top”, “-b”] | |
ENTRYPOINT command param1 param2 | ENTRYPOINT top -b |
与CMD比较:
- 都是只能写一条,如果写了多条,那么只有最后一条生效
- 都是容器启动时才运行,运行时机相同
- ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖
- 如果我们在Dockerfile种同时写了ENTRYPOINT和CMD——如果CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数;如果CMD是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效
VOLUME
用于指定持久化目录,实现挂载功能,授权访问从容器内到主机上的目录。用于containers之间共享数据,将本地文件夹或者其他容器中的文件夹挂在到这个容器中等
语法格式 | 示例 | 备注 |
---|---|---|
VOLUME [“/path/to/dir”] | VOLUME [“/var/log/”] VOLUME /var/log VOLUME /var/log /var/db |
[“/path/to/dir”]可以是一个JsonArray ,也可以是多个值 |
注意:
- 容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失,所以当数据需要持久化时用这个命令。
- 一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统
- 卷可以容器间共享和重用 可以关注参数 –volumes-from
- 容器并不一定要和其它容器共享卷
- 修改卷后会立即生效
- 对卷的修改不会对镜像产生影响
- 卷会一直存在,直到没有任何容器在使用它
USER
指定运行容器时的用户名或UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
语法格式 | 示例 | 备注 |
---|---|---|
USER user[:group] | USER spotlight | 使用spotlight用户 |
USER uid[:gid] |
注:
- 使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
WORKDIR
类似于cd命令。设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次。
语法格式 | 示例 | 备注 |
---|---|---|
WORKDIR /path/to/workdir | WORKDIR /root WORKDIR child |
最后的工作目录是/root/child |
注意:
- 通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
ARG
设置变量命令,用于指定传递给构建运行时的变量。ARG命令定义了一个变量,在docker build创建镜像的时候,使用 –build-arg <varname>=<value>来指定参数
语法格式 | 示例 | 备注 |
---|---|---|
ARG <name>[=<default value>] | ARG name ARG age=100 |
注意:
- 如果用户在build镜像时指定了一个参数没有定义在Dockerfile中,那么将有一个Warning:[Warning] One or more build-args [foo] were not consumed
- ARG定义的参数默认值,当build镜像时没有指定参数值,将会使用这个默认值
ONBUILD
用于设置镜像触发器
语法格式 | 示例 | 备注 |
---|---|---|
ONBUILD [INSTRUCTION] | ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build –dir /app/src |
注意:
- 当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发
只对当前镜像的子镜像生效。
比如当前镜像为A,在Dockerfile种添加:ONBUILD RUN ls -al 这个 ls -al 命令不会在A镜像构建或启动的时候执行,此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。
STOPSIGNAL
该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,或SIGNAME格式的信号名,例如SIGKILL
语法格式 | 示例 | 备注 |
---|---|---|
STOPSIGNAL signal | STOPSIGNAL 9 |
HEALTHCHECK
HEALTHCHECK指令告诉Docker如何测试容器以检查它是否仍在工作。即使服务器进程仍在运行,这也可以检测到陷入无限循环且无法处理新连接的Web服务器等情况。
当容器指定了运行状况检查时,除了正常状态外,它还具有运行状况。这个状态最初是starting。每当健康检查通过时,它就会变成healthy(以前的状态)。经过一定数量的连续失败后,它就变成了unhealthy
语法格式 | 示例 | 备注 |
---|---|---|
HEALTHCHECK [OPTIONS] CMD command | 通过在容器内运行命令来检查容器运行状况 | |
HEALTHCHECK NONE | 禁用从基础映像继承的任何运行状况检查 |
- HEALTHCHECKDockerfile中只能有一条指令。如果列出多个,则只有最后一个HEALTHCHECK生效
SHELL
SHELL指令允许覆盖用于shell形式的命令的默认shell 。Linux上的默认shell是[“/bin/sh”, “-c”],而在Windows上[“cmd”, “/S”, “/C”]。
语法格式 | 示例 | 备注 |
---|---|---|
SHELL [“executable”, “parameters”] | SHELL [“powershell”, “-command”] |
- SHELL指令必须以JSON格式写入Dockerfile
- SHELL指令可以多次出现。每条SHELL指令都会覆盖所有先前的SHELL指令,并影响所有后续指令
MAINTAINER(废弃)
维护者信息
语法格式 | 示例 | 备注 |
---|---|---|
MAINTAINER <name> | MAINTAINER yueling |
~不足之处请指正 ~