當聽到很多人在說Docker是多麼多麼的棒,很多新潮的孩子都在使用它時,我決定在我的開發環境上也來嘗試下。在下面的這篇文章中,我將講解在Mac OS X怎樣建立Postgres,Elasticsearch和Redis。
什麼是Docker
Docker用輕量容器把一個APP從它啟動並執行OS中隔離開。它把APP放入到一個孤立的盒子中,對外只呈現需要使用的檔案夾和連接埠。
這樣,基於建立和使用APP的容器是可重用,共用的。目前,在Docker集中已經存在了15,000種以上的容器。Docker就像一個商店的存放庫,當你需要建立一個你想要的APP時,你首先去挑出它,然後把它下載下來開啟即可。
在OS X上安裝Docker
Docker不是天生就能運行在OS X上的,它需要一個包含LINUX容器的Linux核心。因此,當你想像我一樣要安裝OS X時,你將需要一套虛擬器。
不要使用boot2docker
當試圖讓docker工作時,我發現“非常容易”安裝。這將使用一個稱之為boot2docker的工具,該工具是一個像virtualBox的虛擬機器上的瘦封裝。
我馬上發現,這個工具有一些嚴重的問題,例如:在一個穩定點下將會終止任何擷取Docker的進程。我不想在這方面浪費太多的體力和腦細胞,所以我繼續尋找了一個可替代的解決方案。
使用Vargrant
自從Vagrant的1.6版本之後,已經整合了支援Docker的配套組件。Vargrant是一種類似於VirtualBox的虛擬軟體,它採用一種聲明Ruby DSL的方法來描述你的環境。
我非常喜歡這種定義虛擬環境的方式,因為當你的環境發生故障時,你可以記錄下來當時的資訊,再次開始使用,而不用遺漏下大量的類似環境變數的資訊。
安裝Stuff
首先,讓我們瀏覽下我們需要安裝的各種事宜。
Homebrew安裝:
ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
Cask安裝:
brew tap caskroom/homebrew-cask brew install brew-cask
Vagrant 和 VirtualBox安裝:
brew cask install virtualbox brew cask install vagrant
Vagrant檔案
一個vagrant檔案來描述一個使用Ruby DSL虛擬機器環境的需求。當描述Docker容器時,Vagrant使每一個容器都好像在使用自己專屬的虛擬機器一樣。事實上這是一個假象,因為每一個Docker容器實際上是允許在各種的代理虛擬機器上的。
因此,兩個vagrant檔案是非常必須的,一個檔案是用來定義代理虛擬機器(Provisioner),另外一個檔案是用來定義Docker容器的(Providers)。
代理虛擬Vagrant檔案
代理虛擬Vagrant檔案被叫做:Vagrantfile.proxy
VAGRANTFILE_API_VERSION = "2"Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "hashicorp/precise64" config.vm.provision "docker" config.vm.provision "shell", inline: "ps aux | grep 'sshd:' | awk '{print $2}' | xargs kill" config.vm.network :forwarded_port, guest: 6379, host: 6379 config.vm.network :forwarded_port, guest: 5432, host: 5432 config.vm.network :forwarded_port, guest: 9200, host: 9200end
這使用hashicorp/precise64 Ubuntu 12.04的64位來處理代理虛擬機器。它也提供Docker和一些神奇的shell命令來讓Docker工作。
最後的事情就是設定轉送連接埠了。它使用config.vm.network來為Redis, Elasticsearch 和Postgres來進行配置,用代理虛擬機器映射到OS X。
Docker 容器的 Vagrant 檔案
這是Vagrantfile的主要內容:
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "redis" do |v| v.vm.provider "docker" do |d| d.image = "dockerfile/redis" d.volumes = ["/var/docker/redis:/data"] d.ports = ["6379:6379"] d.vagrant_vagrantfile = "./Vagrantfile.proxy" end end config.vm.define "elasticsearch" do |v| v.vm.provider "docker" do |d| d.image = "dockerfile/elasticsearch" d.ports = ["9200:9200"] d.vagrant_vagrantfile = "./Vagrantfile.proxy" end end config.vm.define "postgres" do |v| v.vm.provider "docker" do |d| d.image = "paintedfox/postgresql" d.volumes = ["/var/docker/postgresql:/data"] d.ports = ["5432:5432"] d.env = { USER: "root", PASS: "abcdEF123456", DB: "root" } d.vagrant_vagrantfile = "./Vagrantfile.proxy" end endend
這個檔案定義了三個容器: Redis , Elasticsearch, 和 Postgres 帶有圖片dockerfile/redis, dockerfile/elasticsearch 和 paintedfox/postgresql。
每個檔案定義 vagrant_vagrantfile 作為 proxy VM 檔案,這使得它們在同一個 proxy 虛擬機器上運行。
Redis 和 Postgres 的 volumes 定義是為了它們的資訊可以儲存在 proxy VM 上,而不是在容器中。這也是容器可以更刪除或升級而資料不會丟失的原因。下一步是映射這些檔案從proxy VM 到 OS X ,但是沒必要讓其運轉著。
每個容器上的 ports 定義哪個連接埠轉到 proxy VM 。這些需要匹配 proxy VM 到 OS X 的連接埠。
Postgres 容器也定義了需要設定它的伺服器的環境變數。這些可以用來在OS X 裡設定預設的Postgres 伺服器,通過設定環境變數 PGHOST=localhost PGUSER=root PGPASSWORD=abcdEF123456 來實現。
使用Vagrant工作
在你的Vagrant檔案相同的目錄內,你可以運行:
vagrant up --provider=docker
第一次運行這個時,Vagrant將下載然後啟動proxy VM,然後下載並啟動Docker容器。在這些初始化下載之後每次運行Vagrant都將重複使用現有的圖片。
可以查看Docker容器的狀態:
應該輸出一些東西類似:
複製代碼 代碼如下:
Current machine states:
redis running (docker)
elasticsearch running (docker)
db running (docker)
要測試Docker容器是否正確運行,可以使用 Redis 和 Postgres 用戶端, 和 curl for Elasticsearch。只需要檢查redis-cli和psql到伺服器的串連,和curl http://localhost:9200響應。
如果需要串連到proxy VM(非常有助於調試),運行vagrant global-status,這將列出所有VM,包括proxy。然後調用vagrant ssh <ID>,ID為proxy的ID。建議不要手動改變這個proxy VM,使用一個Chef(或類似的)指令碼,這樣改變可以更容易的測試和分布。
效能
使用虛擬化時,第一個問題總是會問“效能的影響有多少?”。要找出效能影響是多麼的糟糕,我的同事和我都做了一個Postgres,在相同的硬體上做了Elasticsearch 和 Redis 加強測試。唯一的區別是一個測試有本機安裝的軟體而另一個有Docker自訂容器。帶有本機軟體的運行了2分鐘,而帶有容器的運行了3分鐘。
這個效能影響並不像我想象的那樣小,甚至可能會更糟。即使這樣,我將繼續使用Docker做開發,但並不推薦大家將它作為所有開發環境問題的靈丹妙藥。
注意:一些其他使用Vagrant 和 Docker的限制在 這裡 列出
總結
我還看不到"Vagrant with Docker"的路在哪裡。不過,在看過可能的情況後,我不禁思考它可以用於什麼其他地方。另外,它是我遇到過的最好玩的虛擬化,樂趣就在於編程。