Docker是一个新的容器化技术,它轻巧,易移植,能够“build once, configure once and run anywhere”。Docker 跟传统的虚拟化方式相比具有众多的优势,如启动快、系统资源利用率高、应用性能高同时系统开销小等。
对于每个开发和运维人员来说,应该都曾因环境不一致、运维工作繁重而头疼,最希望的就是一次创建或配置,可以在任意地方正常运行。利用Docker,开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。实现快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的,可以大量地节约开发、测试、部署的时间。
提到Docker镜像的创建,就不能不讲一下Dockerfile。什么是Dockerfile?直白一点,Dockerfile就是个文件,内容是一系列的指令,用来自动化创建镜像,将你从耗时又乏味的手动创建镜像中解放出来。使用docker build
命令,可以自动的执行Dockerfile中的指令进行镜像的创建。
DockerFile命令格式示例:
# Comment
INSTRUCTION arguments
指令是不区分大小写的,但是约定大写,以便更清晰的区分指令和参数。 Dockerfile中的指令是顺序执行的。第一条指令必须为FROM
,用来指定该镜像是基于哪个基础镜像创建的。 以#
开始的行是注释,如果#
不在一行的开头,则会被认为是参数的一部分。如:
# Comment
RUN echo 'we are running some # of cool things'
可以使用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 六个命令。下面为大家一一介绍。
FROM 格式为 FROM <image>
或FROM <image>:<tag>
,该命令用来指定该镜像是基于哪个基础镜像创建的。
MAINTAINER 格式为 MAINTAINER <name>
,用来指定维护者的信息。
RUN 格式为 RUN <command>
或RUN ["executable", "param1", "param2"]
。 前者将在 shell 终端中运行命令,即/bin/sh -c
;后者则使用 exec
执行。如果想要使用其它终端,可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]
。 每条 RUN
指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。
ENTRYPOINT ENTRYPOINT用来配置容器启动后执行的命令,并且不会被 docker run
提供的参数覆盖。ENTRYPOINT也有两种格式: ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
(shell中执行)。 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。
USER 用来指定运行容器时的用户名或 UID,后续的RUN
也会使用指定用户。格式为USER daemon
。 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres
。要临时获取管理员权限可以使用gosu
,而不推荐 sudo
。
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
为后续的 RUN
、CMD
、ENTRYPOINT
指令配置工作目录。可以使用多个 WORKDIR
指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
ONBUILD [INSTRUCTION]
配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
相信看到这里,大家都可以使用Dockerfile创建自己需要的镜像了。 当然从Ubuntu等基础镜像中创建需要的镜像还有有些麻烦的,比如,要创建一个java开发所需的镜像需要tomcat、mysql等。大家不妨试试我们的产品--网易蜂巢(现已更名为网易云计算基础服务)。网易云计算基础服务提供了丰富的基础镜像,而且可以根据需要创建自定义镜像,构建后的镜像保存在平台的后端分布式文件系统中,保证构建数据安全性。 同时提供一站式开发运维方案,低成本搭建环境,快速开发和部署服务端应用程序,并且简化了系统维护工作,从而使用户把更多精力聚焦在业务实现上,及时应对市场变化。 网易蜂巢现已开放注册,更有 充1送30 的活动,期待你的到来呦。
本文来自网易实践者社区,经作者祝剑锋授权发布。