Dockerfile初探

达芬奇密码2018-07-10 10:10

Docker简介

Docker是一个新的容器化技术,它轻巧,易移植,能够“build once, configure once and run anywhere”。Docker 跟传统的虚拟化方式相比具有众多的优势,如启动快、系统资源利用率高、应用性能高同时系统开销小等。

对于每个开发和运维人员来说,应该都曾因环境不一致、运维工作繁重而头疼,最希望的就是一次创建或配置,可以在任意地方正常运行。利用Docker,开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。实现快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的,可以大量地节约开发、测试、部署的时间。

Dockerfile简介及命令格式

提到Docker镜像的创建,就不能不讲一下Dockerfile。什么是Dockerfile?直白一点,Dockerfile就是个文件,内容是一系列的指令,用来自动化创建镜像,将你从耗时又乏味的手动创建镜像中解放出来。使用docker build命令,可以自动的执行Dockerfile中的指令进行镜像的创建。

DockerFile命令格式示例:

# Comment
INSTRUCTION arguments

指令是不区分大小写的,但是约定大写,以便更清晰的区分指令和参数。 Dockerfile中的指令是顺序执行的。第一条指令必须为FROM,用来指定该镜像是基于哪个基础镜像创建的。 以#开始的行是注释,如果#不在一行的开头,则会被认为是参数的一部分。如:

# Comment
RUN echo 'we are running some # of cool things'

如何使用Dockerfile

可以使用docker build命令从Dockerfile和context中构建镜像。build命令的context是指特定路径PATH(本地文件系统)或URL(git地址)中的文件。context是递归处理的,因此PATH包括其所有的子目录,同样的URL包括仓库和所有的子模块。build命令是由Docker daemon执行的,而不是由CLI执行。build处理的第一件事就是将全部的context (递归地)发送到 daemon 中。在大多数情况下,最好将Dockerfile放到一个空目录中,并且该目录只添加构建镜像时必需的文件。

tips:不要使用根目录 "/"作为PATH,因为这将导致build命令将整个硬盘的内容发送到Docker daemon中。

为了提高build的性能,可以通过在context中添加一个“.dockerignore”文件来排除一个文件和子目录。关于“.dockerignore”的使用请参考相关文档。

习惯上Dockerfile就以“Dockerfile”命名,并且在context的根目录中,可以使用docker build -f path 来指定文件系统中任意位置的Dockerfile。

Docker daemon会逐条执行Dockerfile中的指令,如果需要的话会commit每条指令的结果到一个新镜像中,之后输出新镜像的ID。Docker daemon会自动清理由你发送的context。

注意到每条指令是独立执行并且创建一个新镜像,因此RUN cd /tmp不会对下条指令有任何的影响。只要有可能,Docker就会重复使用中间镜像(cache)来显著地提高Docker build的构建速度。

示例

下面是一个创建Memcached的Dockerfile. 因为墙的问题,获取Ubuntu基础镜像可能速度很慢甚至失败,可以使用国内的镜像库,一些简单的Dockerfile可以使用小的基础镜像,比如busybox等。同样的,使用网易开源镜像站。

# Memcached
#
# VERSION       2.2

# use the ubuntu base image 
FROM ubuntu

MAINTAINER Victor Coisne victor.coisne@dotcloud.com

# make sure the package repository is up to date
RUN echo "deb http://mirrors.163.com/ubuntu/ precise main restricted universe multiverse" > /etc/apt/sources.list
RUN apt-get update

# install memcached
RUN apt-get install -y memcached

# Launch memcached when launching the container
ENTRYPOINT ["memcached"]

# run memcached as the daemon user
USER daemon

# expose memcached port
EXPOSE 11211

在这个示例中,使用了FROM、MAINTAINER、RUN、ENTRYPOINT、USER、EXPOSE 六个命令。下面为大家一一介绍。

  1. FROM 格式为 FROM <image>FROM <image>:<tag>,该命令用来指定该镜像是基于哪个基础镜像创建的。

  2. MAINTAINER 格式为 MAINTAINER <name>,用来指定维护者的信息。

  3. RUN 格式为 RUN <command>RUN ["executable", "param1", "param2"]。 前者将在 shell 终端中运行命令,即/bin/sh -c;后者则使用 exec 执行。如果想要使用其它终端,可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]。 每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。

  4. ENTRYPOINT ENTRYPOINT用来配置容器启动后执行的命令,并且不会被 docker run提供的参数覆盖。ENTRYPOINT也有两种格式: ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2(shell中执行)。 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

  5. USER 用来指定运行容器时的用户名或 UID,后续的RUN 也会使用指定用户。格式为USER daemon。 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要临时获取管理员权限可以使用gosu,而不推荐 sudo

  6. EXPOSE EXPOSE的作用是告诉 Docker 服务端容器暴露的端口号,供互联系统使用。格式为EXPOSE <port> [<port>...]。 在启动容器时需要通过参数 -P做端口映射。

除了实例中出现的命令,还有几个命令是比较重要且常用的,如

ENV <key> <value> 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。

ADD <src> <dest>复制指定的 到容器中的 。 其中 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。

COPY <src> <dest>复制本地主机的 (为 Dockerfile 所在目录的相对路径)到容器中的 。当使用本地目录为源目录时,推荐使用 COPY

VOLUME ["/data"]创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

WORKDIR /path/to/workdir为后续的 RUNCMDENTRYPOINT 指令配置工作目录。可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

ONBUILD [INSTRUCTION]配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。

后记:

相信看到这里,大家都可以使用Dockerfile创建自己需要的镜像了。 当然从Ubuntu等基础镜像中创建需要的镜像还有有些麻烦的,比如,要创建一个java开发所需的镜像需要tomcat、mysql等。大家不妨试试我们的产品--网易蜂巢(现已更名为网易云计算基础服务)。网易云计算基础服务提供了丰富的基础镜像,而且可以根据需要创建自定义镜像,构建后的镜像保存在平台的后端分布式文件系统中,保证构建数据安全性。 同时提供一站式开发运维方案,低成本搭建环境,快速开发和部署服务端应用程序,并且简化了系统维护工作,从而使用户把更多精力聚焦在业务实现上,及时应对市场变化。 网易蜂巢现已开放注册,更有 充1送30 的活动,期待你的到来呦。

本文来自网易实践者社区,经作者祝剑锋授权发布。