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 鼓勵實驗操做,容器啓動很是地快,建立一個鏡像更是很是地快,使用別的鏡像作爲基本鏡像也很是的容易,部署更個鏡像很是地快,最後但一樣重要的是,回滾也很是地方便。

快速 + 靈活 = 部署將會更快樂

相關文章
相關標籤/搜索