的日常工作中会经常进行镜像构建操作。构建Docker镜像非常简单,而且方法也有几种。
3.3.1. 手工创建
这个方法最简单直接的方法。其流程是启动一个容器,在里面进行一些列安装、配置操作,然后运行docker commit命令来将容器commit为一个新镜像。
$ sudo docker run -t -i ubuntu bash root@c4be1df52810:/# apt-get update root@c4be1df52810:/# apt-get -y install redis-server root@c4be1df52810:/# exit
通过下面的命令得到刚才容器的ID号并进行commit操作。
$ sudo docker ps -q -l c4be1df52810 $ sudo docker commit -m="manually created image" -a="bin liu" -run='{"CMD":["/usr/bin/redis-server"], "PortSpecs": ["6379"]}' c4be1df52810 liubin/redis:manually Warning: '-run' is deprecated, it will be removed soon. See usage. 744ce29b2fcf0ad7ad8b2a89c874db51376c3fdd65d1f4f0c6f233b72f8c3400
注意上面的警告信息,在docker commit命令指定-run选项已经不被推荐了,这里为了说明这个例子而故意使用了这个选项。建议创建镜像还是使用Dockerfile的方式,即能将创建过程代码化、透明化,还能进行版本化。
再次运行docker images命令,就应该能看到我们刚才通过docker commit命令创建的镜像了(镜像ID为744ce29b2fcf,镜像名为liubin/redis:manually)。
3.3.2. 使用Dockerfile文件
使用Dockerfile构建Docker镜像
这是一个官方推荐的方法,即将构建镜像的过程代码化,比如要安装什么软件,拷贝什么文件,进行什么样的配置等都用代码进行描述,然后运行docker build命令来创建镜像文件。官方的自动构建即是基于保存在GitHub等代码托管服务上的Dockerfile进行的。Dockerfile即是具体的用于构建的配置文件名,也是这类文件的类型名称。
使用Dockerfile构建Docker镜像非常简单,我们只需要创建一个名为Dockerfile的文件,并编写相应的安装、配置脚本就可以了。我们还是以上面安装Redis服务为例,看看如何使用Dockerfile构建一个镜像。
首先,创建一个redis文件夹(文件夹名任意,无任何限制),并进入该文件夹,然后创建一个Dockerfile文件。这个文件的文件名是固定的,其内容如下。
FROM ubuntu MAINTAINER bin liuRUN apt-get update RUN apt-get -y install redis-server EXPOSE 6379 ENTRYPOINT ["/usr/bin/redis-server"]
Dockerfile文件的语法非常简单,每一行都是一条指令,注释则以#开头。每条指令都是“指令名称 参数”的形式,指令名称一般都是大写。比如FROM指令表明了我们的镜像的基础镜像(严格来说叫父镜像,我们的所有操作都将以此镜像为基础),这里是ubuntu,但实际上它可以是存在的任何镜像,比如liubin/ruby。RUN指令则用来在构建过程中执行各种命令、脚本,比如这里是apt-get命令,你也可以指定一个很复杂很长的脚本文件路径。AUFS有42层文件系统的限制注 7,这时候我们可以通过在RUN指令中执行多条命令,即cmd1 && cmd2 && cmd3 && ...这种形式就可以可避免该问题了。EXPOSE表示此镜像将对外提供6379端口的服务。ENTRYPOINT则指定了启动该镜像时的默认运行程序。
注 7 https://github.com/dotcloud/docker/issues/1171
具体的Dockerfile语法在官方网站注 8有详细说明,相信花个10分钟就能通读一遍,这里唯一比较容易混淆的就是ENTRYPOINT和CMD指令了,关于它们的区别,还是留作每位读者自己的课题去研究一下吧。
注 8 https://docs.docker.com/reference/builder/
Dockerfile准备好了之后,运行docker build命令即可构建镜像了。
$ sudo docker build -t liubin/redis:dockerfile .
这里-t表示为构建好的镜像设置一个仓库名称和Tag(如果省略Tag的话则默认使用latest)。最后的一个.表示Dockerfile文件的所在路径,由于我们是在同一文件夹下运行docker build命令,所以使用了.。
由于篇幅所限,这里我们就省略了docker build命令的输出。不过如果你亲自动手执行docker build命令的话,那么从它的输出应该很容易理解,Dockerfile里的每一条指令,都对应着构建过程中的每一步,而且每一步都会生成一个新的类似容器的哈希值一样的镜像层ID。也正是这些层,使得镜像能共享很多信息,并且能进行版本管理、继承和分支关系管理等。这除了能节省大量磁盘空间之外,还能在构建镜像的时候通过使用已经构建过的层(即缓存)来大大加快了镜像构建的速度。比如在我们在使用Dockerfile进行构建镜像时,如果在某一步出错了,那么实际上之前步骤的操作已经被提交了,修改Dockerfile后再次进行构建的话,Docker足够聪明到则会从出错的地方开始重新构建,因为前面的指令执行结构都已经被缓存了。
如果你使用docker history命令来查看该镜像的历史信息,你会发现它的输出和docker build的记录是相匹配的,每一条Dockerfile中的指令都会创建一个镜像层。此命令还能查看每个镜像层所占空间大小,即SIZE列的内容。比如本例中MAINTAINER这样指令,实际上它只是关于镜像的元数据,并不占用额外的磁盘空间,所以它的层大小为0字节。而RUN apt-get -y install redis-server创建的层则会在镜像中增加文件,所以是需要占用磁盘空间的。
自动构建(Automated Builds)
Docker Hub的目的之一就是要成为应用程序交换的中转站,它还支持自动构建功能。自动构建的Dockerfile可以托管在GitHub或者Bitbucket上,当我们将代码提交并push到托管仓库的时候,Docker Hub会自动通过webhook来启动镜像构建任务。
配置自动构建很简单,只需要在Docker Hub中绑定GitHub或者Bitbucket账号就可以了,如何具体操作这里不做详细说明了。
3.3.3. 使用Packer
Packer注 10是一个通过配置文件创建一致机器镜像(identical machine images)的非常方便的工具。Packer同样出自Vagrant的作者Mitchell Hashimoto之手。它支持虚拟机VirtualBox和VMWare等虚拟机软件,以及Amazon EC2、DigitalOcean、GCE以及OpenStack等云平台,最新版的Packer也增加了对Docker的支持。
Packer的使用也比较简单,这里我们就举例说明了,读者可以自己试一下。
3.4. 发布镜像
如果你愿意,还可以将在本地制作镜像push到Docker Hub上和其他人分享你的工作成果。
首先你要有一个Docker Hub账号并已经为登录状态,这样才能往Docker Hub上push镜像文件。注册Docker Hub账号只能通过网站注册注 11,这里我们假设各位读者已经拥有Docker Hub了账号。
登录Docker Hub通过docker login命令。
登录成功后,我们就可以push镜像了。注意这里我们没有指定Tag,Docker知道如何去做。
$ sudo docker push liubin/redis
我们前面说过,镜像文件是分层的,很多镜像文件可以共用很多层。比如我们这次往服务器push镜像的时候,实际push的只有一层(744ce29b2fcf)而已,这是因为我们的镜像文件是基于ubuntu这个base镜像创建的,而ubuntu镜像早已经在远程仓库中了。
我们在层744ce29b2fcf中对应的操作是bash命令,并在容器中安装了Redis。而这次修改只有不到6M的容量增加,而如果只是修改配置文件的话,那么一次push操作可能只需要耗费几K的网络带宽而已。
4. DockerCon14总结
首届Docker大会(DockerCon14)于当地时间6月9日~6月10日在旧金山举行。相对于计划中的500个参会名额,最终有超过900人报名,并提交了超过150个演讲申请。
关于这次Docker大会的更多信息可以参考其官方网站:http://www.dockercon.com/。
4.1. Docker官方发布的产品和服务
4.1.1. Docker 1.0的发布及商业支持
在这次大会上最重要的事情莫过于Docker 1.0的发布了。Docker 1.0已经可以在Red Hat、Debian、Ubuntu、Fedora、SuSE等主流Linux系统下运行,在功能、稳定性以及软件质量上都已经达到了企业使用的标准,文档也更加系统、完善。并且提供了Docker Hub云服务,方便开发者和企业进行应用分发。最重要的是Docker, Inc.还宣布了对Docker的商业支持,尤其是对Docker 1.0版本的长期支持。此外,Docker, Inc.还会提供Docker相关的培训、咨询等工作。
4.1.2. Docker Engine + Docker Hub
同时从1.0开始,Docker的架构也发生了较大的变化。Docker已经从单一的软件转变为了一个构建、发布、运行分布式应用的平台。
新的Docker平台由Docker Engine(运行环境 + 打包工具)、Docker Hub(API + 生态系统)两部分组成。
Docker引擎
Docker引擎是一组开源软件,位于Docker平台的核心位置。它提供了容器运行时以及打包、管理等工具。
Docker Hub
Docker Hub是一个云端的分布式应用服务,它专注于内容、协作和工作流。
Docker Hub可以看作是原来Docker index服务的升级版。Docker Hub除了可以托管Docker镜像之外,还提供了包括更管理、团队协作、生命周期流程自动化等功能,以及对第三方工具和服务的集成。
在Docker, Inc.看来,典型的基于Docker Hub的软件开发生命周期为:在本地基于Docker引擎开发 -> 打包应用程序 -> 将应用程序push到Docker Hub -> 从Docker Hub上下载此应用镜像并运行。它将镜像构建的任务交给Dev,将镜像部署的任务交给Ops。