集装箱这个想法已经在深刻地改变传统分布式系统的开发、测试和部署的流程了。传统的做法是,开发者写一个Makefile(或者其他描述,比如CMakeList、POM等)来说明如何把源码编译成二进制文件。随后,开发人员会在开发机上配置并且执行二进制文件,来作测试。测试人员会在测试机群上配置和执行,来作验证。而运维人员会在数据中心里的预发布环境和产品环境上配置和执行,这就是部署。因为开发机、测试机群、和产品环境里机器的数量和质量都不同,所以配置往往很不同。加上每个新版本的软件系统,配置方式难免有所差异,所以经常造成意外错误。以至于绝大部分团队都选择趁夜深人静、用户不活跃的时候,上线新版本,苦不堪言。
而利用集装箱概念的开发流程里,开发者除了写Makefile,还要写一个Dockerfile,来描述如何把二进制文件安装进一个集装箱镜像(container image),并且做好配置。而一个镜像就像一台配置好的虚拟机,可以在机群上启动多个实例(instance),而每个实例通常称为一个集装箱(container)。在自测的时候,开发者在开发机上执行一个或者多个集装箱;在验证时,测试人员在测试机群上执行集装箱;在部署时,运维人员在产品环境执行集装箱。因为执行的都是同样地集装箱,所以不容易出错。
这种流程更合理的划分了开发者和其他角色的工作边界,也大大简化了测试和部署工作。
boot2docker上节提到,Docker虚拟了网络地址空间和文件系统。实际上,它还虚拟了进程ID空间(pid space)等系统数据结构。这些功能是一个叫dockerd的daemon程序借助Linux内核中的control groups(又叫cgroups)功能实现的。
dockerd负责执行集装箱;就像VirtualBox负责执行虚拟机一样。而cgroup是Google的两个工程师Paul Menage和Rohit Seth贡献给Linux社区的。从他们的工作记录看,主要工作集中在2008和2009年。据说,Google开发它就是为了方便在自己的机群上部署各种Internet应用和离线处理系统。具体一点儿的故事,请看这篇Information Week上的帖子。。
因为cgroups功能只有Linux内核有,所以Docker目前只能运行在Linux上。可是,现在很多开发者都在用Mac。为了能让这些开发者方便的测试自己创作的集装箱镜像,Docker的开发者写了boot2docker——利用VirtualBox虚拟一个Linux主机,并且在上面安装dockerd。而命令行控制程序docker执行在Mac主机上,被配置成和虚拟Linux主机上的dockerd协作。
boot2docker的安装方式很简单:照着这个流程,下载并执行一个安装包即可。因为boot2docker利用了VirtualBox,所以安装它之前需要先装VirtualBox。Homebrew也提供了安装boot2docker的选项,但是可能因为bug导致dockerd和docker版本不同,没法协同工作。
在利用boot2docker在Mac上开始工作之前,还有几个注意事项。当我们在Linux主机上启动一个集装箱的时候,我们可以让Docker把主机的某些目录映射成集装箱内的目录。这样集装箱里的程序和主机上的程序共享数据,是一种方便的调试方式。但是在用boot2docker的时候,“主机”不是Mac,而是虚拟Linux主机。此时如果想把Mac上的目录映射到集装箱,先得将其通过VirtualBox映射到Linux主机。
另一个注意事项和端口转发有关。当我们把集装箱内的某个端口映射为主机的某个端口时,只是映射到了虚拟Linux主机;如果想让Mac上的程序能访问,还得把虚拟机端口通过VirtualBox映射成Mac上的端口。这些注意事项,在下文中会有详细解释。
CoreOS实际开发中的测试机群和产品环境通常都是用的Linux服务器。要在上面执行集装箱,也需要安装Docker。因为Docker的开发者提供各种Linux软件包,所以通常输入一个命令,即可安装Docker。比如在Ubuntu/Debian Linux里,这个命令是:
sudo apt-get install docker.io
但是目前最常用的用来执行Docker集装箱的Linux发行版本既不是Ubuntu、Debian也不是RedHat、Fedora,而是CoreOS。这个发行版本根本没有软件包管理程序,所以也不能通过输入某个命令来安装软件。但是CoreOS预装了Docker,所以可以制作集装箱镜像,或者下载别人发布的集装箱镜像来执行。目前,Amazon AWS和Google Compute Engine这两大云计算平台都提供预装了CoreOS的虚拟机。