什么是Dockerfile
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。它们简化了从头到尾的流程并极大的简化了部署工作。Dockerfile从FROM命令开始,紧接着跟随者各种方法,命令和参数。其产出为一个新的可以用于创建容器的镜像。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
Dockerfile 指令详解
Dockerfile有十几条命令可用于构建镜像,下文将简略介绍这些命令。
FROM
FROM命令可能是最重要的Dockerfile命令。改命令定义了使用哪个基础镜像启动构建流程。基础镜像可以为任意镜 像。如果基础镜像没有被发现,Docker将试图从Docker image index来查找该镜像。FROM命令必须是Dockerfile的首个命令。
在 Docker Store 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如nginx 、 redis 、 mongo 、mysql 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 node 、 openjdk 、 python 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。
如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如ubuntu 、 debian 、 centos 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。
# Usage: FROM [image name]
FROM centos
除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch 。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
FROM scratch
COPY 复制文件
COPY 指令将从构建上下文目录中 的文件/目录复制到新的一层的镜像内的 位置。
格式:
COPY ...
COPY ["",... ""]
可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则。
可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git进行管理的时候。
ADD
ADD命令有两个参数,源和目标。它的基本作用是从源系统的文件系统上复制文件到目标容器的文件系统。如果源是一个URL,那该URL的内容将被下载并复制到容器中。
# Usage: ADD [source directory or URL] [destination directory]
ADD /my_app_folder /my_app_folder
CMD
和RUN命令相似,CMD可以用于执行特定的命令。和RUN不同的是,这些命令不是在镜像构建的过程中执行的,而是在用镜像构建容器后被调用。
ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。比如 可以是一个 URL ,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 去。下载后的文件权限自动设置为 600 ,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。
版权声明:本文为博主原创文章,转载请附上博文链接!
# Usage 1: CMD application "argument", "argument", ..
CMD "echo" "Hello docker!"
ENTRYPOINT
配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。
ENTRYPOINT 帮助你配置一个容器使之可执行化,如果你结合CMD命令和ENTRYPOINT命令,你可以从CMD命令中移除“application”而仅仅保留参数,参数将传递给ENTRYPOINT命令。
# Usage: ENTRYPOINT application "argument", "argument", ..
# Remember: arguments are optional. They can be provided by CMD
# or during the creation of a container.
ENTRYPOINT echo
# Usage example with CMD:
# Arguments set with CMD can be overridden during *run*
CMD "Hello docker!"
ENTRYPOINT echo
ENV
ENV这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN ,还是运行时的应用,都可以直接使用这里定义的环境变量。这些变量以”key=value”的形式存在,并可以在容器内被脚本或者程序调用。这个机制给在容器中运行应用带来了极大的便利。格式有两种:
ENV
ENV = =...
# Usage: ENV key value
ENV SERVER_WORKS 4
EXPOSE
EXPOSE用来指定端口,使容器内的应用可以通过端口和外界交互。EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
# Usage: EXPOSE [port]
EXPOSE 8080
MAINTAINER
我建议这个命令放在Dockerfile的起始部分,虽然理论上它可以放置于Dockerfile的任意位置。这个命令用于声明作者,并应该放在FROM的后面。
# Usage: MAINTAINER [name]
MAINTAINER authors_name
RUN
RUN命令是Dockerfile执行命令的核心部分。它接受命令作为参数并用于创建镜像。不像CMD命令,RUN命令用于创建镜像(在之前commit的层之上形成新的层)。其格式有两种:
shell 格式: RUN ,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式
RUN echo '
Hello, Docker!
' > /usr/share/nginx/html/index.htmlexec 格式: RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式
# Usage: RUN [command]
RUN yum install -y nginx
USER
USER命令用于设置运行容器的UID。USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。 WORKDIR 是改变工作目录, USER 则是改变之后层的执行 RUN , CMD 以及 ENTRYPOINT 这类命令的身份。当然,和 WORKDIR 一样, USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。
# Usage: USER [UID]
USER 1000
VOLUME
VOLUME命令用于让你的容器访问宿主机上的目录。容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
# Usage: VOLUME ["/dir_1", "/dir_2" ..]
VOLUME ["/data"]
WORKDIR
WORKDIR命令用于设置CMD指明的命令的运行目录。使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在, WORKDIR 会帮你建立目录。
# Usage: WORKDIR /path
WORKDIR ~/
ARG 构建参数
构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是, ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。
Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg = 来覆盖。
格式: ARG [=]