什么是Dockerfile
Dockerfile是一个包含用于组合映像的命令的文本文档,可以使用在命令行中调用任何命令,Docker通过读取Dockerfile中的指令自动生成映像。
docker build命令用于从Dockerfile构建映像.可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerfile。
基本结构:
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
文件说明:
Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。
Dockerfile逆向
逆向分析镜像有两种方法。
一种是 docker history 可以看到每一层的配置,但包括了从底层镜像开始的所有配置,所以会很杂乱。
docker history --no-trunc
--no-trunc 参数,不截断数据
另一种是 docker save 导出 tar 包,解压后,不仅可以得到每一层的配置,还能详细的看到每一层的文件增删情况。
Dockerfile 构建镜像:
- 从 base 镜像运行一个容器。
- 执行一条指令,对容器做修改。
- 执行类似 docker commit 的操作,生成一个新的镜像层。
- Docker 再基于刚刚提交的镜像运行一个新容器。
- 重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕。
常用命令详解
(https://docs.docker.com/engine/reference/builder/#environment-replacement )
- FROM指定基础镜像,如:
FROM <image>:<tag>
- MAINTAINER指明该镜像的作者和其电子邮件,如:
MAINTAINER third"xxxxxxx@qq.com"
- RUN
构建镜像时内部执行的命令,比如安装软件、配置基础环境,可使用 \ 来换行,如:
RUN <command>
也可以使用exec格式RUN [“executable”, “param1”, “param2”]的命令,如:
RUN ["apt-get","install","-y","nginx"]
要注意的是,executable是命令,后面的param是参数
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定–no-cache参数,如:docker build --no-cache
- COPY
将主机的文件复制到镜像内,如果目的位置不存在,Docker会自动创建所有需要的目录结构,它只是单纯的复制,并不会去做文件提取和解压工作,也不能访问网络资源。
COPY <file>... <src>
注意:需要复制的目录一定要放在Dockerfile文件的同级目录下,因为构建环境将会上传到Docker守护进程,而复制是在Docker守护进程中进行的。任何位于构建环境之外的东西都是不可用的。COPY指令的目的的位置则必须是容器内部的一个绝对路径。
- ADD
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
如:
ADD <src>... <dest>
- EXPOSE
暴露镜像的端口供主机做映射,启动镜像时,使用-P参数来讲镜像端口与宿主机的随机端口做映射。使用方式(可指定多个):
EXPOSE <port> [<port>...]
注:
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
- WORKDIR
在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录。如
WORKDIR /path/to/workdir
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录
- USER
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在之前创建所需要的用户
USER hadoop
注:使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
- ONBUILD:用于设置镜像触发器
ONBUILD [INSTRUCTION]
示例:
ONBUILD ADD . /app/src
注:
当我们在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响。
但是当我们编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。
需要注意的是,如果是再利用B镜像构造新的镜像时,那个ONBUILD指令就无效了,也就是说只能再构建子镜像中执行,对孙子镜像构建无效。其实想想是合理的,因为在构建子镜像中已经执行了,如果孙子镜像构建还要执行,相当于重复执行,这就有问题了。
利用ONBUILD指令,实际上就是相当于创建一个模板镜像,后续可以根据该模板镜像创建特定的子镜像,需要在子镜像构建过程中执行的一些通用操作就可以在模板镜像对应的dockerfile文件中用ONBUILD指令指定。 从而减少dockerfile文件的重复内容编写。
- ENV:设置环境变量
`ENV <key> <value>`
<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
ENV <key>=<value> ...
可以设置多个变量,每个变量为一个"=“的键值对,如果中包含空格,可以使用\来进行转义,也可以通过”"来进行标示;另外,反斜线也可以用于续行ARG指令定义了用户可以在编译时或者运行时传递的变量ENV指令是在dockerfile里面设置环境变量,不能在编译时或运行时传递。
- VOLUME:用于指定持久化目录
VOLUME /data/db /data/configdb
注:VOLUME 主机目录 容器目录
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
- CMD
容器启动时需要执行的命令,如:
CMD /bin/bash
同样可以使用exec语法,如
CMD ["/bin/bash"]
CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。当有多个CMD的时候,只有最后一个生效。
- ENTRYPOINT
> ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
> ENTRYPOINT command param1 param2 (shell内部命令)
ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
CMD和ENTRYPOINT的区别
CMD和ENTRYPOINT同样作为容器启动时执行的命令,区别有以下几点:
• CMD的命令会被 docker run 的命令覆盖而ENTRYPOINT不会
• CMD和ENTRYPOINT都存在时,CMD的指令变成了ENTRYPOINT的参数,