Docker 和虚拟机的一些对比 [翻译]

本文翻译自:《Docker: Git for deployment -- Scout》,我的感受它的内容和标题不对,因此就没有直译过来,要是我理解错了请帮忙纠正。php

我据说了 Docker 多么使人惊叹,可是它并无征服个人心,直到我提出一个实际的问题:【若是 Scout 使用 Docker 来部署,它会让咱们的部署变得更顺利吗?】html

如下是三个案例:node

高效地模拟线上环境

咱们线上有 16 台服务器,若是我尝试在本地使用 VirtualBox 配置每一个实例 512 MB内存,那么它将占用我笔记本的两倍内存(说明他笔记本只有 4G 内存),VirtualBox 须要有许多多余的开支来管理每一个子操做系统,Docker 在这方面是不同的——容器共享同一个操做系统,更有多是一样的二进制包文件和库文件,它能够运行在一台 Docker 主机上运行好几百个容器。mysql

老方法

我不能在本地彻底地模拟线上环境,让咱们来看一下经过 Vagrant 启动一台机器须要花多久:git

$ time vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'squeeze64-ruby193'...
...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
...

real  1m32.052s

启动一个镜像须要一分半钟,若是我须要修改一个配置文件并检测是否可以正常工做,那么须要重启镜像,那又是可怕的一分半钟。sql

若是你配置的有错,那将是一个残忍的惩罚。(每次修改就须要一分半钟才能看到结果)docker

使用 Docker

能想像 Docker 有多轻便吗?当你在 Docker 容器里面运行程序,你甚至可能不会注意到他们不是直接在主机上运行的,在下面的例子中,我从标记的 "rails" 镜像中启动一个 Docker 容器来运行 Rails 应用(Dockerfile):数据库

root@precise64:~# docker run rails
2013-08-26 20:21:14,600 CRIT Supervisor running as root (no user in config file)
2013-08-26 20:21:14,603 WARN Included extra file "/srv/docker-rails/Supervisorfile" during parsing
2013-08-26 20:21:14,736 INFO RPC interface 'supervisor' initialized
2013-08-26 20:21:14,740 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2013-08-26 20:21:14,754 INFO supervisord started with pid 1
2013-08-26 20:21:15,783 INFO spawned: 'rails' with pid 10
2013-08-26 20:21:16,841 INFO success: rails entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

只须要两秒钟就完成了容器的启动和 supervisor 的启动(用来启动 Rails 应用的管理程序)ubuntu

总之,Docker 可以让你在测试机上彻底地模拟线上环境,它是如此的简单,让我能够真正地进行全站测试了。缓存

更简单快速地建立镜像

传统方法

若是你用脚本从一个基本的镜像建立一个虚拟机镜像(例如:在 Ubuntu 上建立 Rails stack),若想把这个都作的正确是很是痛苦的,除非你常常的在作这个,看看安装 Ruby 依赖的一些信息吧:

$ time apt-get install -y -q ruby1.9.1 ruby1.9.1-dev rubygems1.9.1 irb1.9.1 build-essential libopenssl-ruby1.9.1 libssl-dev zlib1g-dev
Reading package lists...
Building dependency tree...
The following extra packages will be installed:
....
Setting up libalgorithm-merge-perl (0.08-2) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place

real 1m22.470s

而后,尝试去安装 NodeJS 的依赖,可是你忘记了添加 Node 到 apt 库中

$apt-get install -y nodejs
...
E: Unable to locate package nodejs

等你把这个问题解决了,想在新的基本镜像上运行你的脚本。
你须要从新安装 Ruby,还须要在安装 Node 以前,忍受没必要要的 82 秒时间,真是痛苦至极。

使用 Docker 的方式

把建立镜像的步骤写入到 Dockerfile 文件中,看懂 Dockerfile 很是容易,由于里面就是你输入的命令,第一次安装 Ruby 不会比其它方式快,可是请看咱们再次经过 Dockerfile 建立一个镜像:

FROM ubuntu:12.04
RUN apt-get update

## MYSQL
RUN apt-get install -y -q mysql-client libmysqlclient-dev

## RUBY
RUN apt-get install -y -q ruby1.9.1 ruby1.9.1-dev rubygems1.9.1 irb1.9.1 build-essential libopenssl-ruby1.9.1 libssl-dev zlib1g-dev
root@precise64:/# time docker build -t="dlite/appserver" .
Uploading context 92160 bytes
Step 1 : FROM ubuntu:12.04
 ---> 8dbd9e392a96
Step 2 : RUN apt-get update
 ---> Using cache
 ---> b55e9ee7b959
Step 3 : RUN apt-get install -y -q mysql-client libmysqlclient-dev
 ---> Using cache
 ---> dc92be6158b0
Step 4 : RUN apt-get install -y -q ruby1.9.1 ruby1.9.1-dev rubygems1.9.1 irb1.9.1 build-essential libopenssl-ruby1.9.1 libssl-dev zlib1g-dev
 ---> Using cache
 ---> 7038022227c0
Successfully built 7038022227c0

real    0m0.848s

哇哦,为何安装 Ruby 连一秒都不到? 看那些 Keys (例如:dc92be6158b0 ),Docker 不会从新运行 Dockerfile 中的每一行命令,会检查那是否是已经运行过的命令,是的话直接从缓存中取回对文件的修改。
作的如此神奇,是由于 Docker 使用了 AuFS 文件系统(union file system)

总之,Docker 让咱们反复地建立一个镜像再也不那么痛苦,对于已经成功的后面就不须要再等了。I'm not perfect and Docker doesn't punish me when I make mistakes.

部署镜像,不更新基础设施

传统的作法

Scout和其它部署同样,很长的时间在运行虚拟机,使用 Puppet 来更新全部的基础设施,可是常常会很是的痛苦。

若是咱们部署更新到咱们的栈,Puppet 会在每台虚拟机运行更新,这会花去许多的时间——即便是一个小小的改变,Puppet 须要检查所其它全部的都检查一遍。在部署的时间会出问题:若是咱们安装 Memcached 时网络有点问题,apt-get install memcached 就会执行失败。

回滚到主要的改变经过不会像咱们想像的那么平稳,(例如更新 Ruby 的版本)
这些老是并非 Puppet 的问题, PuppetChef 是一个工具,当你要在一直运行的多台虚拟机上运行命令时,它会给你到多台机器上去运行,能够节省许多时间。

Docker 的作法

部署镜像——不修改已经存在的虚拟机,你会 100% 有肯定在本地能够运行的,在生产环境也能运行。

镜像很是地大是吗?在 Docker 上不是这样的,请记住容器不会运行在宿主机上,它使用 union file system,当咱们改变一个镜像,咱们只须要新的一层。(说的好高大上,彻底听不懂,后面能够看看 union file system 为什么如此强大)

例如,在应用服务器上安装 Memcached,建立一个新的镜像,而后给它打上一个 tagdlite/appserver-memcached,它是基于 dlite/appserver 这个镜像的,dlite 是我在 index.docker.io 上的用户名。

root@precise64:/# time docker build -t="dlite/appserver-memcached" .
Uploading context 92160 bytes
Step 1 : FROM appserver
 ---> 8dbd9e392a96
Step 2 : RUN apt-get update
 ---> Using cache
 ---> b55e9ee7b959
Step 3 : RUN apt-get install -y -q memcached
 ---> Running in 2a2a689daee3
Reading package lists...
Building dependency tree...
...
Starting memcached: memcached.
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
 ---> 2a2a689daee3
Successfully built 2a2a689daee3

real    0m13.289s
user    0m0.132s
sys 0m0.376s

只用了 13 秒就安装好了 MemcachedDockerfile 在执行时会优先使用已经安装成功的缓存,这个速度我喜欢。。。

把刚才的操做提交到仓库

root@precise64:/# time docker push dlite/appserver-memcached
The push refers to a repository [dlite/appserver-memcached] (len: 1)
Processing checksums
Sending image list
Pushing repository dlite/appserver-memcached (1 tags)
Pushing 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c
Image 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c already pushed, skipping
...
Pushing tags for rev [ad8f8a3809afcf0e2cff1af93a8c29275a847609b05b20f7b6d2a5cbd32ff0d8] on {https://registry-1.docker.io/v1/repositories/dlite/appserver-memcached/tags/latest}

real    0m28.710s

在线上服务器把镜像下载下来

root@prod:/# time docker pull dlite/appserver-memcached
Pulling repository dlite/appserver-memcached
Pulling image ad8f8a3809afcf0e2cff1af93a8c29275a847609b05b20f7b6d2a5cbd32ff0d8 (latest) from dlite/appserver-memcached

real    0m15.749s

只用了 15 秒就把 dlite/appserver-memached 镜像下载下来了,镜像只有 10 MB 它使用 appserver 为基础镜像。

root@precise64:~# docker images
REPOSITORY            TAG                 ID                  CREATED             SIZE
appserver             latest              7038022227c0        3 days ago          78.66 MB (virtual 427.9 MB)
appserver-memcached   latest              77dc850dcccc        16 minutes ago      10.19 MB (virtual 438.1 MB)

咱们不须要下载所有的镜像,只须要下载添加 Memcached 的改变就能够了。

大多数状况下,咱们的修改很是的小,因此下载一个新的镜像会很是地快。

启动一个新的 Docker 容器很快,上传和下载一个新的镜像也很轻量。

与其在现有的虚拟机上弄的乱七八糟,不如启动一个新的容器,而后把旧的容器删除就行了。

使人情奇的(Mind blown!)
它意味着咱们不须要去担忧统一性,咱们不会去修改现有的虚拟机,只是启动一个新的容器。那也意味着回滚也就是垂手可得的事!Memcached 挂了?直接中止使用 dlite/appserver-memcached 而后启动 dlite/appserver-memcached 的容器就行了。

不足之处

生态还不是很完善,对于分布式配置 / 协调和服务发现没有好的解决方案(那是博文之前,如今应该很不同了,可参考:《腾讯Gaia:万台规模的Docker应用实践)》

咱们如何作到新应用服务窗口启动了,自动更改 HAProxy 的 配置文件?

新的数据库容器启动了,应用服务器如何自动与数据库容器通讯?

如何让不一样主机的 Docker 窗口通讯?

即将到来的 Flynn.io 将会解决这些问题,上面的问题将再也不是问题(如今这些老是早就不是问题了, Docker 的生态圈已经很是完善,国内 DaoCloud 在这方面就是领头羊,正在使用它的加速。)

Docker 能够像 Git 同样部署

建立一个项目的时候,开发者能够去使用 Git 来提高性能和灵活性。 Git 鼓励实验新的东西,而且在你作错了不会给你带来不少的麻烦事:在一个分支去作你的实验,若是作遭了,只须要 git rebasegit reset, Git 能够很简单地就建立一个分支和推送一个分支。

Docker 鼓励实验操做,容器启动很是地快,建立一个镜像更是很是地快,使用别的镜像作为基本镜像也很是的容易,部署更个镜像很是地快,最后但一样重要的是,回滚也很是地方便。

快速 + 灵活 = 部署将会更快乐

相关文章
相关标签/搜索