Docker — 云时代的程序分发方式
的正式发布?Azure入华?还是AWS落地中国?留在每个人大脑中的印象可能各不相同,但要是让笔者来排名的话那么Docker绝对应该算是第一位的。如果你之前听说过它的话,那么也许你会说“没错,就是它”,因为几乎世界各地的开发、运维都在谈论着Docker;如果你还没听说过Docker,那么我真的建议你花上10分钟来阅读本文。
运行私有Registry非常简单,这也是一个典型的Docker风格的应用发布例子。
注 6 为了方便区分,本文中运行命令的时候如果提示符为 $ ,表示实在宿主机(Ubuntu)中,如果是 # ,则表示是在Docker容器中
docker run 命令会启动一个容器。参数 ubuntu 指定了我们需要运行的镜像名称,后面的 bash 则指定了要运行的命令,注意这个命令是容器中的命令,而不是宿主机中的命令。参数 -i 用来为容器打开标准输入以和宿主机进行交互, -t 则会为容器分配一个终端。
在第一次启动某镜像的时候,如果我们本地还没有这个镜像,则Docker会先从远程仓库(Docker Hub)将容器的镜像下载下来,下载完成之后才会启动容器。
注意Docker里有一个很重要的概念就是容器ID或者镜像ID,比如这个例子里的 e54ca5efa2e9 。这个ID是一个容器或者镜像的唯一标识,它的长度为64位,不过很多时候都可以简写为12位,这也和Git很像。
Dockerfile文件的语法非常简单,每一行都是一条指令,注释则以 # 开头。每条指令都是“指令名称 参数”的形式,指令名称一般都是大写。比如 FROM 指令表明了我们的镜像的基础镜像(严格来说叫父镜像,我们的所有操作都将以此镜像为基础),这里是 ubuntu ,但实际上它可以是存在的任何镜像,比如 liubin/ruby 。 RUN 指令则用来在构建过程中执行各种命令、脚本,比如这里是 apt-get 命令,你也可以指定一个很复杂很长的脚本文件路径。AUFS有42层文件系统的限制 注 端口的服务。 ENTRYPOINT 则指定了启动该镜像时的默认运行程序。
build 命令的话,那么从它的输出应该很容易理解,Dockerfile里的每一条指令,都对应着构建过程中的每一步,而且每一步都会生成一个新的类似容器的哈希值一样的镜像层ID。也正是这些层,使得镜像能共享很多信息,并且能进行版本管理、继承和分支关系管理等。这除了能节省大量磁盘空间之外,还能在构建镜像的时候通过使用已经构建过的层(即缓存)来大大加快了镜像构建的速度。比如在我们在使用Dockerfile进行构建镜像时,如果在某一步出错了,那么实际上之前步骤的操作已经被提交了,修改Dockerfile后再次进行构建的话,Docker足够聪明到则会从出错的地方开始重新构建,因为前面的指令执行结构都已经被缓存了。
build 的记录是相匹配的,每一条Dockerfile中的指令都会创建一个镜像层。此命令还能查看每个镜像层所占空间大小,即 SIZE 列的内容。比如本例中 MAINTAINER 这样指令,实际上它只是关于镜像的元数据,并不占用额外的磁盘空间,所以它的层大小为0字节。而 RUN apt-get -y install redis-server 创建的层则会在镜像中增加文件,所以是需要占用磁盘空间的。
Docker Hub的目的之一就是要成为应用程序交换的中转站,它还支持自动构建功能。自动构建的Dockerfile可以托管在GitHub或者Bitbucket上,当我们将代码提交并push到托管仓库的时候,Docker Hub会自动通过webhook来启动镜像构建任务。
配置自动构建很简单,只需要在Docker Hub中绑定GitHub或者Bitbucket账号就可以了,如何具体操作这里不做详细说明了。
登录成功后,我们就可以push镜像了。注意这里我们没有指定Tag,Docker知道如何去做。
我们前面说过,镜像文件是分层的,很多镜像文件可以共用很多层。比如我们这次往服务器push镜像的时候,实际push的只有一层( 744ce29b2fcf )而已,这是因为我们的镜像文件是基于 ubuntu 这个base镜像创建的,而ubuntu 镜像早已经在远程仓库中了。
我们在层 744ce29b2fcf 中对应的操作是 bash 命令,并在容器中安装了Redis。而这次修改只有不到6M的容量增加,而如果只是修改配置文件的话,那么一次push操作可能只需要耗费几K的网络带宽而已。
私有仓库托管(Registry)/容器托管
这类服务主要进行私有仓库的托管,根据用户的托管仓库数量收费。Doccker Hub也提供私有仓库的收费套餐。
Quay除了能托管私有镜像之外,还能和GitHub集成,使用Dockerfile进行镜像构建。
Orchard也是一个和StackDock类似的Docker托管服务,它提供了便捷的命令行工具来运行各种Docker命令。同时它也提供免费的私有Registry服务,前面介绍的Fig工具就是此公司开发的。
笔者认为传统的云计算服务提供商除了在云主机上提供对容器的支持之外,说不定将来还会提供专门托管容器的服务。
软件工程师天生就是闲不住和想尽一切办法要提高自己效率的一群人。这里我们简单介绍两个方便进行Docker开发的工具。
Shipyard是一个Docker镜像和容器管理工具,除了基本的镜像构建,容器启动等功能之外,它还具有在浏览器中attach到容器的功能,并通过hipache 16 来进行容器之间的连接。同时它也支持跨节点的Docker管理和容器Metrics采集。
Fig是一个为了提高基于Docker开发的效率而创建的工具,它通过一个配置文件来管理多个Docker容器,非常适合组合使用多个容器进行开发的场景。
围绕Docker使用场景的开源集群管理软件有很多,比如Geard、Fleet、Consul及Serf等,这些软件都是随着Docker应运而生的;此外还有很多老牌的集群管理软件,比如Mesos等也可以很好的结合Docker使用。
Serf 注 25 是一个基于Gossip协议去中心的服务器发现和集群管理工具,它非常轻量,高可用并具备容错机制。
另外Clocker 注 29 这个项目也比较有意思,它基于Apache Brooklyn(目前还在孵化器中),能在多云环境下基于Docker容器进行应用部署。这个项目的扩展性很好,非常方便自己定制。不过项目还太年轻,要想使用的话恐怕还需要些时日。
CoreOS是一个精简版的Linux,可以运行在既有硬件或者云上,它也是一个最近备受关注的项目。CoreOS不提供类似yum或者apt类似的包管理工具,你不需要在CoreOS中安装软件,而是让程序都在Docker容器中去运行。CoreOS使用systemd和fleet来对容器进行管理,通过etcd进行服务发现和配置信息共享。
Project Atomic是最近才发布的一个项目,它也是一个瘦身版的Linux,只包含systemd/geard 注 33 /rpm-OSTree以及Docker组件,专门用来部署和管理Docker容器。它能在接近硬件裸机级别上高性能的运行大量容器,而且它还是基于SELinux的,在安全上也有保障。
而另一方面,我们知道除了LXC,Docker之外,还有很多其它容器技术,比如Zones,jail和LMCTFY等,那么试想这么多的容器之上,是否有统一接口、互相兼容或者在容器上加一层封装的可能性呢?比如让一种容器的镜像,能运行到其它容器中?Docker容器已经能互相连接了,会不会异构的容器之间也能进行某种交互呢?
Docker虽然入门和使用起来非常简单,但整个生态系统还是挺庞大的,而且其底层技术也都很复杂,由于篇幅有限及笔者学识不精,也只能说一些皮毛之事,最多只能算是抛块砖而已;而且笔者也有一种意犹未尽的感觉,但是由于篇幅所限,不能说到面面俱到,更多的内容,还请各位读者自己去深入挖掘。
总之笔者认为Docker还是非常有趣的一个东西,值得大家花些时间体验一下,相信在各位的工作中多多少少都能用的上Docker。