p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px 'Helvetica Neue'; color: #555555}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px 'Helvetica Neue'; color: #555555}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px 'Helvetica Neue'; color: #555555; min-height: 15.0px}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px 'Helvetica Neue'; color: #101010; min-height: 15.0px}
p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #aaaaaa; background-color: #f8f8ff}
p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 19.0px 'Helvetica Neue'; color: #555555}
p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco}
p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #008080; background-color: #f8f8ff}
p.p11 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #555555; background-color: #f8f8ff}
p.p12 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #002d7a; background-color: #f8f8ff}
p.p13 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #dd2244; background-color: #f8f8ff}
p.p14 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #016fe0; background-color: #f8f8ff}
p.p15 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; min-height: 16.0px}
p.p16 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #b85c00; background-color: #f8f8ff}
p.p17 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #009999; background-color: #f8f8ff}
p.p19 {margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px 'Helvetica Neue'; color: #555555}
li.li1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px 'Helvetica Neue'; color: #555555}
li.li5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #555555}
li.li6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #aaaaaa; background-color: #f8f8ff}
li.li7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; color: #999999; background-color: #f8f8ff}
li.li18 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px 'Helvetica Neue'; color: #101010}
span.s1 {letter-spacing: 0.0px}
span.s2 {text-decoration: underline ; letter-spacing: 0.0px; color: #101010}
span.s3 {font: 12.0px Monaco; letter-spacing: 0.0px; color: #000000}
span.s4 {letter-spacing: 0.0px; background-color: transparent}
span.s5 {color: #008080}
span.s6 {letter-spacing: 0.0px; color: #008080}
span.s7 {letter-spacing: 0.0px; color: #002d7a}
span.s8 {letter-spacing: 0.0px; color: #016fe0}
span.s9 {letter-spacing: 0.0px; color: #000000; background-color: transparent}
span.s10 {letter-spacing: 0.0px; color: #555555}
span.s11 {font: 12.0px Monaco}
span.s12 {font: 12.0px Monaco; letter-spacing: 0.0px}
span.s13 {font: 12.0px Monaco; letter-spacing: 0.0px; background-color: #f8f8ff}
span.s14 {letter-spacing: 0.0px; color: #009999}
span.s15 {letter-spacing: 0.0px; color: #323333}
span.s16 {letter-spacing: 0.0px; color: #dd2244}
span.s17 {text-decoration: underline ; letter-spacing: 0.0px}
table.t1 {border-collapse: collapse}
td.td1 {width: 26.0px; background-color: #eeeeee}
td.td2 {width: 558.0px}
td.td3 {border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #cbcbcb #cbcbcb #cbcbcb #cbcbcb; padding: 0.0px 5.0px 0.0px 5.0px}
td.td4 {width: 606.0px}
td.td5 {width: 637.0px}
td.td6 {width: 875.0px}
td.td7 {width: 695.0px}
td.td8 {width: 1244.0px}
ol.ol1 {list-style-type: decimal}
ul.ul1 {list-style-type: square}
最近接觸PAAS相關(guān)的知識秀睛,在研發(fā)過程中開始使用Docker搭建了自己完整的開發(fā)環(huán)境谴仙,感覺生活在PAAS時代的程序員真是幸福,本文會簡要介紹下Docker是什么梆惯,如何利用Docker來搭建自己的開發(fā)環(huán)境(本文主要是面向Mac OS X)备韧,以及期間所遇到的一些坑和解決方案劫樟。(本文會要求你對PAAS、LXC织堂、CGroup叠艳、AUFS有一定的了解基礎(chǔ),請自行Google )
大背景–虛擬化技術(shù)歷史
計算機虛擬化技術(shù)由來已久易阳,從硬件仿真到全虛擬化附较,再到準(zhǔn)虛擬化和操作系統(tǒng)虛擬化,各種技術(shù)粉墨登場潦俺,種類繁多拒课,說實在的有點眼花繚亂和復(fù)雜徐勃;但用戶的核心訴求一直是比較簡單的,降低信息技術(shù)(IT)的運營成本早像,提高資源利用率僻肖,提高安全性和可靠性等等;雖說用戶的核心訴求比較簡單卢鹦,但每個時代的需求場景卻是不同的臀脏。在大型機時代,虛擬化技術(shù)被用來支持多個用戶能夠同時使用大型機冀自,在x86架構(gòu)時代揉稚,隨著企業(yè)服務(wù)的大規(guī)模部署,虛擬化技術(shù)主要是用來提高企業(yè)資源的利用率凡纳,而現(xiàn)如今窃植,隨著云計算時代的到來帝蒿,人們對應(yīng)用的安全性荐糜、隔離性越來越高,對于部署的標(biāo)準(zhǔn)化以及虛擬機的性能要求越來越高「鸪現(xiàn)如今暴氏,一種叫Linux容器的虛擬化技術(shù)逐漸得到廣泛的應(yīng)用,它的優(yōu)點有許多绣张,本文不一一贅述答渔,有太多的文章可以參考。
什么是Docker侥涵?
docker的英文本意是碼頭工人沼撕,也就是搬運工,這種搬運工搬運的是集裝箱(Container)芜飘,集裝箱里面裝的可不是商品貨物务豺,而是任意類型的App,Docker把App(叫Payload)裝在Container內(nèi)嗦明,通過Linux Container技術(shù)的包裝將App變成一種標(biāo)準(zhǔn)化的笼沥、可移植的、自管理的組件娶牌,這種組件可以在你的latop上開發(fā)奔浅、調(diào)試、運行诗良,最終非常方便和一致地運行在production環(huán)境下汹桦。
Docker的核心底層技術(shù)是LXC(Linux Container),Docker在其上面加了薄薄的一層鉴裹,添加了許多有用的功能舞骆。這篇stackoverflow上的問題和答案很好地詮釋了Docker和LXC的區(qū)別灵嫌,能夠讓你更好的了解什么是Docker, 簡單翻譯下就是以下幾點:
Docker提供了一種可移植的配置標(biāo)準(zhǔn)化機制葛作,允許你一致性地在不同的機器上運行同一個Container寿羞;而LXC本身可能因為不同機器的不同配置而無法方便地移植運行;
Docker以App為中心赂蠢,為應(yīng)用的部署做了很多優(yōu)化绪穆,而LXC的幫助腳本主要是聚焦于如何機器啟動地更快和耗更少的內(nèi)存;
Docker為App提供了一種自動化構(gòu)建機制(Dockerfile)虱岂,包括打包玖院,基礎(chǔ)設(shè)施依賴管理和安裝等等;
Docker提供了一種類似git的Container版本化的機制第岖,允許你對你創(chuàng)建過的容器進(jìn)行版本管理难菌,依靠這種機制,你還可以下載別人創(chuàng)建的Container蔑滓,甚至像git那樣進(jìn)行合并郊酒;
Docker Container是可重用的,依賴于版本化機制键袱,你很容易重用別人的Container(叫Image)燎窘,作為基礎(chǔ)版本進(jìn)行擴展;
Docker Container是可共享的蹄咖,有點類似github一樣褐健,Docker有自己的INDEX,你可以創(chuàng)建自己的Docker用戶并上傳和下載Docker Image澜汤;
Docker提供了很多的工具鏈蚜迅,形成了一個生態(tài)系統(tǒng);這些工具的目標(biāo)是自動化俊抵、個性化和集成化谁不,包括對PAAS平臺的支持等;
那么Docker有什么用呢务蝠?對于運維來說拍谐,Docker提供了一種可移植的標(biāo)準(zhǔn)化部署過程,使得規(guī)牧蠖危化轩拨、自動化、異構(gòu)化的部署成為可能甚至是輕松簡單的事情院喜;而對于開發(fā)者來說亡蓉,Docker提供了一種開發(fā)環(huán)境的管理方法,包括映像喷舀、構(gòu)建砍濒、共享等功能淋肾,而后者是本文的主題。
Docker的安裝和構(gòu)成
Docker官方本身提供了非常具體的安裝教程爸邢,這里不說具體的安裝過程樊卓,請參考Docker安裝(Mac系統(tǒng)),重要的是描述下原理和安裝完成后的結(jié)構(gòu)杠河,好對Docker更好的了解碌尔。 由于LXC本身不支持Mac內(nèi)核,因此需要跑一個VirtualBox虛擬機(TinyCoreLinux)來安裝券敌,幸好Docker社區(qū)提供了一個非常方便的工具boot2docker(其實就是一個VBoxManage的包裝shell腳本)唾戚,用于安裝Mac下的整個Docker環(huán)境。具體的結(jié)構(gòu)如下:
如圖所示待诅,安裝完成后叹坦,具體情況如下:
在Mac的home目錄~/.boot2docker下創(chuàng)建了虛擬機所需要的文件,其中boot2docker.iso是虛擬機映像卑雁,這是一個由CD-ROM引導(dǎo)的TinyCoreLinux系統(tǒng)募书;而boot2docker-vm.vmdk文件則是你的虛擬機磁盤,你所有的持久化數(shù)據(jù)都存放在這里序厉,包括docker創(chuàng)建的lxc容器等文件锐膜。
在Mac下,docker被分為客戶端docker-client和服務(wù)端docker-daemon兩部分弛房,如果是在linux(比如ubuntu),實際上則是同一個可執(zhí)行文件同時充當(dāng)客戶端和服務(wù)端而柑。docker-daemon可以監(jiān)聽unix scoket文捶,也可以在tcp socket(默認(rèn)端口為4234),docker-client會通過一個叫DOCKER_HOST的環(huán)境變量讀取服務(wù)地址和端口媒咳,因此你應(yīng)該在你的bash_profile文件里面添加這么一行:
Crayon Syntax Highlighter v2.6.7 export DOCKER_HOST=tcp://127.0.0.1:4243
1
2
export DOCKER_HOST=tcp://127.0.0.1:4243
?
[Format Time: 0.0033 seconds]?
docker-daemon跑在虛擬機上粹排,這個程序?qū)嶋H上就是接收docker-client發(fā)送過來的消息命令,創(chuàng)建涩澡、啟動和銷毀lxc容器顽耳,以及docker本身的版本管理、映像存儲等等 運行你的第一個docker容器 安裝完成后妙同,就差不多可以開始創(chuàng)建和運行docker容器了射富,在這之前,你首先得下載一個Image粥帚,什么是Image胰耗?我們先來了解docker的2個基礎(chǔ)概念:Image和Container。
Container和Image 在Docker的世界里芒涡,Image是指一個只讀的層(Layer)柴灯,這里的層是AUFS里的概念卖漫,最直觀的方式就是看一下docker官方給出的圖:
Docker使用了一種叫AUFS的文件系統(tǒng),這種文件系統(tǒng)可以讓你一層一層地疊加修改你的文件赠群,最底下的文件系統(tǒng)是只讀的羊始,如果需要修改文件,AUFS會增加一個可寫的層(Layer)查描,這樣有很多好處店枣,例如不同的Container可以共享底層的只讀文件系統(tǒng)(同一個Kernel),使得你可以跑N多個Container而不至于你的硬盤被擠爆了叹誉!這個只讀的層就是Image鸯两!而如你所看到的,一個可寫的層就是Container长豁。
那Image和Container的區(qū)別是什么钧唐?很簡單,他們的區(qū)別僅僅是一個是只讀的層匠襟,一個是可寫的層钝侠,你可以使用docker commit 命令,將你的Container變成一個Image酸舍,也就是提交你所運行的Container的修改內(nèi)容帅韧,變成一個新的只讀的Image,這非常類似于git commit命令啃勉,感覺真棒忽舟!
實際上這就是Docker對Container映像的版本管理基石,AUFS文件系統(tǒng)實在是太美妙了淮阐,更多細(xì)節(jié)可以參考DotCloud的這篇文章叮阅。
運行和退出
在了解了Image和Container的概念后,我們可以開始下載一個Image泣特,Docker的好處就是提供了一個類似github的Image倉庫管理浩姥,你可以非常方便pull別人的Image下來運行,例如状您,我們可以下載一個ubuntu Image:
Crayon Syntax Highlighter v2.6.7
docker pull ubuntu:13.10?
1
2
docker pull ubuntu:13.10?
?
[Format Time: 0.0008 seconds]
這里的13.10是一個Tag勒叠,類似于git的tag,這里的tag可以為你制定一個ubuntu的版本膏孟。下載完成后眯分,執(zhí)行docker images命令可以列出你已經(jīng)下載或者自己構(gòu)建的image:(請允許我使用可愛的馬賽克 :) )
你可以看到ubuntu:13.10的大小為178MB,以及它的IMAGE ID骆莹。 現(xiàn)在我們開始運行一個Container颗搂,命令很簡單,例如我們想運行一個執(zhí)行Shell終端的Container:
如你看到的幕垦,你已經(jīng)進(jìn)入到一個Shell里面丢氢,可以執(zhí)行你想執(zhí)行的任何命令傅联,就和在ubuntu里面一樣,進(jìn)去后默認(rèn)是在根目錄/下疚察,可以看到經(jīng)典的unix/linux目錄結(jié)構(gòu)蒸走,以及你所運行的bash版本等信息。你可以給你的Container定一個名字貌嫡,通過–name選項比驻,例如這里命名了shell,日后你就可以直接用這個名字引用Contanier岛抄。
退出一個Container也很簡單别惦,你直接exit就好了。 其他更多的命令這里不做贅述夫椭,因為官方的文檔已經(jīng)非常全面掸掸,這里只是給一個直觀的初步印象。下面進(jìn)入主題蹭秋。
利用Docker搭建開發(fā)環(huán)境
我們先看看程序員在搭建開發(fā)環(huán)境時遇到的一些問題:
軟件安裝麻煩扰付,比如很多公司都使用redhat,一般開發(fā)人員又不給root仁讨,安裝一個nginx或者是mysql都得自己下載編譯安裝 權(quán)限問題羽莺,沒有root,一些軟件無法運行洞豁,例如dnsmasq盐固;
沒有root,無法修改hosts族跛,無法netstat -nptl闰挡,無法tcpdump,無法iptable
隔離性差礁哄,例如不同的開發(fā)人員如果在同一臺主機環(huán)境下共享開發(fā),雖然是用戶隔離溪北,但端口如果不規(guī)范可能會沖突桐绒;同一個Mysql如果權(quán)限管理不好很有可能誤刪別人的數(shù)據(jù)
可移植性差,例如和生產(chǎn)環(huán)境不一致之拨,開發(fā)人員之間也無法共享茉继;更嚴(yán)重的情況是當(dāng)有新人入職時,通常需要又折騰一遍開發(fā)環(huán)境蚀乔,無法快速搭建
這些問題可以通過在本地搭建虛擬機來解決烁竭,但虛擬機是一個很笨重的解決方案,Docker是一個非常輕量級的方案吉挣,而且還擁有虛擬機沒有的一些功能派撕,例如標(biāo)準(zhǔn)化Image婉弹,Image共享等,更重要的是终吼,利用Docker镀赌,你可以運行非常多的容器,在你的Mac下搭建一個分布式的開發(fā)環(huán)境根本不是什么大的問題际跪,而且對內(nèi)存商佛、磁盤和cpu的消耗相比傳統(tǒng)的虛擬機要低許多,這些都要歸功于AUFS和LXC這兩大神奇的技術(shù)姆打。
構(gòu)建基礎(chǔ)Image
想要搭建一個節(jié)省磁盤空間和擴展性良好的開發(fā)環(huán)境良姆,最重要的第一步就是構(gòu)建一個基礎(chǔ)性的Image,比如你的主要開發(fā)語言是Ruby幔戏,那么你肯定需要一個已經(jīng)安裝好以下工具的基礎(chǔ)Image:
ruby
bundler
gem
然后在此基礎(chǔ)上玛追,你可以擴展這個基礎(chǔ)的Image(下面叫base)為不同的開發(fā)環(huán)境,例如rails评抚,或者是nats豹缀。當(dāng)然,你的這個base也可以從別人的Image擴展而來慨代,還記得我們剛剛pull下來的ubuntu:13.10這個Image嗎邢笙?你可以從這個Image擴展開始構(gòu)建你的base,如何做呢侍匙?Docker提供了一種標(biāo)準(zhǔn)化的DSL方式氮惯,你只需要編寫一個Dockerfile,運行docker build指令想暗,就可以構(gòu)建你自己的Image妇汗,這有點像Makefile和make命令一樣,只是大家要構(gòu)建的內(nèi)容和構(gòu)建語言不同说莫。
Dockerfile的語法請參考Dockerfile Reference杨箭,這里給出上面提到的Ruby開發(fā)的base Dockerfile示例:
Crayon Syntax Highlighter v2.6.7
FROM ubuntu:13.10?
RUN apt-get update?
RUN apt-get install -y ruby ruby-dev gem?
RUN gem install bundler?
1
2
3
4
5
FROM ubuntu:13.10?
RUN apt-get update?
RUN apt-get install -y ruby ruby-dev gem?
RUN gem install bundler?
?
[Format Time: 0.0020 seconds]
這里只用到了很簡單的2個指令:FROM和RUN,F(xiàn)ROM指定了我們要擴展的Image储狭,RUN指定我們要運行的命令互婿,這里是安裝ruby,gem辽狈、bundler等軟件挎挖。寫好Dockerfile后零蓉,運行以下指令就可以創(chuàng)建你的base image了:
Crayon Syntax Highlighter v2.6.7
docker build --rm -t dev:base .?
1
2
docker build --rm -t dev:base .?
?
[Format Time: 0.0010 seconds]
-t 選項是你要構(gòu)建的base image的tag,就好比ubuntu:13.10一樣 –rm 選項是告訴Docker在構(gòu)建完成后刪除臨時的Container,Dockerfile的每一行指令都會創(chuàng)建一個臨時的Container蝙茶,一般你是不需要這些臨時生成的Container的 如你所想,我們可以像運行ubuntu:13.10那樣運行我們的base了:
Crayon Syntax Highlighter v2.6.7
docker run -i -t --name ruby dev:base irb?
1
2
docker run -i -t --name ruby dev:base irb?
?
[Format Time: 0.0011 seconds]
這里我們使用dev:base這個Image運行了一個irb解釋器(Ruby的交互式解釋器)。 在構(gòu)建完base之后,你可以依樣畫葫蘆構(gòu)建你的rails環(huán)境琐旁,很簡單,只需要FROM dev:base躯保,然后RUN安裝你的rails組件就可以了旋膳,不再贅述。最終你可能構(gòu)建的開發(fā)環(huán)境是這樣的:
如上圖所示途事,base和service都是從ubutnu:13.10繼承而來验懊,他們作為不同的基礎(chǔ)開發(fā)環(huán)境,base是ruby開發(fā)環(huán)境(也許命名為dev:ruby更為合適尸变?)义图,而service是一些基礎(chǔ)數(shù)據(jù)服務(wù),例如mysql召烂,memcache碱工,我建議將這些第三方組件集中在一個Container中,因為他們的環(huán)境不經(jīng)常修改奏夫,可以作為一種底層服務(wù)Container運行怕篷,除非你需要構(gòu)建分布式的服務(wù),例如memcache集群酗昼,那可以繼續(xù)拆分廊谓。
指定Image入口
當(dāng)你構(gòu)建完你的base Image和其他應(yīng)用的Image之后,你就可以啟動這些Image了麻削,還記得前面我們給出的運行命令嗎蒸痹?
Crayon Syntax Highlighter v2.6.7
docker run -i -t --name shell dev:base /bin/bash?
1
2
docker run -i -t --name shell dev:base /bin/bash?
?
[Format Time: 0.0012 seconds]
這里我們運行了一個bash,這樣你就可以在shell里面執(zhí)行你所想要執(zhí)行的任何命令了呛哟,但是我們有時候并不想每次都啟動一個shell叠荠,接著再在shell里面啟動我們的程序,比如一個mysql扫责,而是想一啟動一個容器榛鼎,mysql服務(wù)就自動運行了,這很簡單鳖孤,Dockerfile提供了CMD和ENTRYPOINT這2個指令借帘,允許你指定一個Image啟動時的默認(rèn)命令。CMD和ENTRYPOINT的區(qū)別是CMD的參數(shù)可以由docker run指令指定的參數(shù)覆蓋淌铐,而ENTRYPOINT則不可以。例如我們想運行一個memcached服務(wù)蔫缸,可以這么寫Dockerfile:
Crayon Syntax Highlighter v2.6.7
FROM ubuntu:13.10?
RUN apt-get install -y memcached CMD memcached -u root -p 40000?
1
2
3
FROM ubuntu:13.10?
RUN apt-get install -y memcached CMD memcached -u root -p 40000?
?
[Format Time: 0.0017 seconds]
或者可以這么寫:
Crayon Syntax Highlighter v2.6.7
FROM ubuntu:13.10?
RUN apt-get install -y memcached ENTRYPOINT ["memcached", "-u", "root", "-p", "40000"]?
1
2
3
FROM ubuntu:13.10?
RUN apt-get install -y memcached ENTRYPOINT ["memcached", "-u", "root", "-p", "40000"]?
?
[Format Time: 0.0018 seconds]
注意不要把memcached啟動為后臺進(jìn)程腿准,即加上-d選項,否則docker啟動的container會馬上stop掉,這點我也覺得比較意外吐葱。 接著我們build這個Image:
Crayon Syntax Highlighter v2.6.7
docker build -t dev:memcache .?
1
2
docker build -t dev:memcache .?
?
[Format Time: 0.0010 seconds]
這樣街望,當(dāng)你build完你的Image后,你可以直接將該Image運行為一個容器弟跑,它會自動啟動mysql服務(wù):
Crayon Syntax Highlighter v2.6.7
docker run --name memcache_service -d dev:memcache?
1
2
docker run --name memcache_service -d dev:memcache?
?
[Format Time: 0.0011 seconds]
注意使用-d (detach) 選項灾前,這樣這個container就會作為后臺進(jìn)程運行了,接著你可以使用docker ps命令查看是否有在運行孟辑。
磁盤映射
大部分時候你會需要把你host主機(宿主)上的目錄映射到Container里面哎甲,這樣你就非常方便地在host主機上編輯代碼,然后直接就可以在Container里面運行它們饲嗽,而不用手動copy到Container里面再重啟Container炭玫。按理將host的目錄映射到guest(指Container)上應(yīng)該是一件很容易的事情,就好像VMWare那樣貌虾,但可惜的是吞加,由于Mac上的Docker多了一層虛擬機,因此多了一層周折尽狠,你必須先VM上的目錄通過sshfs mount到host(指Mac)上衔憨,然后再將你的目錄或文件copy到這個mount的目錄,再將VM上的這個目錄映射到Container里袄膏,聽起來比較拗口践图,畫個圖會清晰很多。
如上圖所示哩陕,VM里面的/mnt/sda1/dev/目錄(你需要自己創(chuàng)建)通過sshfs命令mount到了host主機(Mac)的~/workspace/dev/目錄 平项,而VM里的/mnt/sda1/dev/目錄又被映射到了Container的/src/目錄下,這樣你就可以在Container里面的/src/目錄下訪問你的host文件了悍及。具體如何做呢闽瓢?首先你需要安裝sshfs命令,然后將VM的password寫到一個文件中心赶,例如~/.boot2docker/b2d-passwd扣讼,在用sshfs命令mount起VM的/mnt/sda1/dev目錄:
Crayon Syntax Highlighter v2.6.7
brew install sshfs?
cat tcuser > ~/.boot2docker/b2d-passwd?
sshfs docker@localhost:/mnt/sda1/dev ~/workspace/dev -p 2022 -o reconnect -o password_stdin < ~/.boot2docker/b2d-passwd?
1
2
3
4
brew install sshfs?
cat tcuser > ~/.boot2docker/b2d-passwd?
sshfs docker@localhost:/mnt/sda1/dev ~/workspace/dev -p 2022 -o reconnect -o password_stdin < ~/.boot2docker/b2d-passwd?
?
[Format Time: 0.0026 seconds]
接著你在run一個Container的時候需要通過-v選項來將/mnt/sda1/dev/映射到/src目錄:
Crayon Syntax Highlighter v2.6.7
docker run -i -t dev:base -v /mnt/sda1/dev:/src /bin/bash?
1
2
docker run -i -t dev:base -v /mnt/sda1/dev:/src /bin/bash?
?
[Format Time: 0.0015 seconds]
這樣你就可以在你的Container的/src目錄下看到你host里的文件了。 磁盤映射還有2個地方需要注意:
你的文件實際上是存儲在VM里面的缨叫,也就是說你需要將你的目錄或者文件copy到VM里面椭符,你sshfs之后,就是copy到~/workspace/dev目錄下
千萬不要sshfs mount非/mnt/sda1下的目錄耻姥,因為VM里面跑的是TinyCoreLinux销钝,這個OS的rootfs是臨時性的(放在內(nèi)存的,實際上就是boot2docker.iso文件里面的一個rootfs)琐簇,因此其根目錄/下的東西(包括/home)根本不會持久化蒸健,只有/mnt/sda1這個目錄下的才能持久化座享。如果你放在/home目錄下,只要VM一重啟似忧,就會丟失的渣叛,/mnt/sda1則不會,實際上就是那個~/.boot2docker-vm.vmdk文件掛載到了/mnt/sda1目錄下
端口映射
和磁盤映射一樣盯捌,你有時候會需要將Container的端口映射到host主機上淳衙,同樣蛋疼的是,由于多了一層VM饺著,端口映射也顯得比較麻煩箫攀。首先你需要設(shè)置VirtualBox的端口映射,然后再將Container的端口映射到你的VM里面:
具體是這么做的瓶籽,通過2條命令:
Crayon Syntax Highlighter v2.6.7
boot2docker ssh -L 8000:localhost:8000?
docker run -i -t -p 8000:8000
1
2
3
boot2docker ssh -L 8000:localhost:8000?
docker run -i -t -p 8000:8000
?
[Format Time: 0.0015 seconds]
也就是說在docker run的時候通過-p選項指定要映射的端口到VM匠童,而boot2docker ssh命令則是將VM的8000端口映射到了host(Mac)的8000端口,這樣你就可以通過Mac的localhost:8000訪問Container的8000端口了塑顺。 其實汤求,有另一種解決方案就是你不用映射到host(Mac),而是直接登錄到VM里面進(jìn)行訪問就好了严拒,boot2docker ssh就可以登錄到VM扬绪,這樣就類似于你的host是ubuntu,但這種解決方案的問題是這個ubuntu太弱了(TinyCoreLinux)裤唠,如果你在這個ubuntu里面開發(fā)代碼挤牛,或者是運行瀏覽器,是非常蛋疼的事情种蘸,關(guān)鍵還是這個ubuntu是每次重啟都會復(fù)原的墓赴!所以我建議還是做多一層映射好了。 最后航瞭,實際上在VM里面诫硕,你是可以直接訪問所有的Container的端口的,因為VM到Container的網(wǎng)絡(luò)都是橋接的刊侯。
其他的一些坑
在使用的過程中章办,還遇到一些不少的坑:
/etc/hosts文件無法修改,這樣你就不能自己做域名解析
VM的系統(tǒng)時間是UTC +0000的滨彻,而且貌似無法修改
Container的IP無法指定為靜態(tài)IP藕届,因此每次重啟Container時,IP可能會變化
第1個問題的解決方案是通過安裝dnsmasq軟件來做域名解析:
Crayon Syntax Highlighter v2.6.7
# 首先亭饵,在你的Container里面安裝dnsmasq軟件:
apt-get install dnsmasq
# 將以下文本添加到 /etc/dnsmasq.conf文件的最后:
listen-address=127.0.0.1 resolv-file=/etc/resolv.dnsmasq.conf conf-dir=/etc/dnsmasq.d user=root
# 接著在/etc/dnsmasq.d/目錄下新建一個文件休偶,隨意起個名字
vi /etc/dnsmqsq.d/dns.conf
# 指定你要映射的域名,例如google.com辜羊,則將下面貼進(jìn)dns.conf文件
address="/google.com/172.17.0.4"
# 最后退出容器椅贱,重啟啟動容器時懂算,通過-dns選項指定域名服務(wù)器
docker run -i -t -dns 127.0.0.1 -dns 8.8.8.8 dev:base /bin/bash
# 一定要注意上面添加google的域名服務(wù)器8.8.8.8,否則你訪問不了外網(wǎng)
# 進(jìn)去Container后庇麦,啟動dnsmasq,這樣你就能夠ping google.com了
/etc/init.d/dnsmasq start
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 首先喜德,在你的Container里面安裝dnsmasq軟件:
?
apt-get install dnsmasq
?
# 將以下文本添加到 /etc/dnsmasq.conf文件的最后:
?
listen-address=127.0.0.1 resolv-file=/etc/resolv.dnsmasq.conf conf-dir=/etc/dnsmasq.d user=root
?
# 接著在/etc/dnsmasq.d/目錄下新建一個文件山橄,隨意起個名字
?
vi /etc/dnsmqsq.d/dns.conf
?
# 指定你要映射的域名,例如google.com舍悯,則將下面貼進(jìn)dns.conf文件
?
address="/google.com/172.17.0.4"
?
# 最后退出容器航棱,重啟啟動容器時,通過-dns選項指定域名服務(wù)器
?
docker run -i -t -dns 127.0.0.1 -dns 8.8.8.8 dev:base /bin/bash
?
# 一定要注意上面添加google的域名服務(wù)器8.8.8.8萌衬,否則你訪問不了外網(wǎng)
?
# 進(jìn)去Container后饮醇,啟動dnsmasq,這樣你就能夠ping google.com了
?
/etc/init.d/dnsmasq start
?
[Format Time: 0.0044 seconds]
第2個問題的解決方案就稍微麻煩些秕豫,起碼我沒有找到更好的解決方案朴艰,我是將boot2docker.iso文件重新制作一次來解決這個問題的:
Crayon Syntax Highlighter v2.6.7
# 首先你需要將boot2docker.iso文件mount到一個目錄下
hdiutil mount ~/.boot2docker/boot2docker.iso
# 系統(tǒng)會mount到/Volumes/boot2docker目錄下,然后你最好將這下面的東西copy出來到一個另外的目錄混移,這樣我們好制作一張新的ISO
cp -r /Volumes/boot2docker/* ~/tmp/
# 接著我們修改以下文件
vi ~/tmp/boot/isolinux/isolinux.cfg
# 將其中的以下這行修改:
append loglevel=3 user=docker console=ttyS0 console=tty0 nomodeset norestore base
# 修改為:(其實就是加了tz的啟動參數(shù))祠墅,然后保存
append tz=CST-8 loglevel=3 user=docker console=ttyS0 console=tty0 nomodeset norestore base
# 接著你必須在ubuntu環(huán)境下重新制作ISO文件,你可以利用docker跑一個ubuntu歌径,哈哈毁嗦,假設(shè)你將boot2docker目錄copy到了ubuntu的/src/目錄下,那么接著這么做
# 安裝xorriso命令
apt-get install xorriso
# 構(gòu)建ISO映射
xorriso -as mkisofs -J -R -V boot2docker -no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -o /boot2docker.iso /src/
# 這樣就生成了/boot2docker.iso文件回铛,最后你就可以替換到VM的啟動ISO文件了狗准,然后重啟VM了
boot2docker restart
# 最后你必須設(shè)置你的VM為正確的時間,使用date -s 命令茵肃,最后用date命令查看腔长,你就能看到CST時區(qū)的正確時間了
Sun Mar 30 00:27:13 CST 2014
# 對于你啟動的container,你都必須重新設(shè)置TZ環(huán)境變量免姿,否則即使VM是CST-8饼酿,你的container還是UCT +00:00的時間
export TZ='CST-8'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 首先你需要將boot2docker.iso文件mount到一個目錄下
?
hdiutil mount ~/.boot2docker/boot2docker.iso
?
# 系統(tǒng)會mount到/Volumes/boot2docker目錄下,然后你最好將這下面的東西copy出來到一個另外的目錄胚膊,這樣我們好制作一張新的ISO
?
cp -r /Volumes/boot2docker/* ~/tmp/
?
# 接著我們修改以下文件
?
vi ~/tmp/boot/isolinux/isolinux.cfg
?
# 將其中的以下這行修改:
?
append loglevel=3 user=docker console=ttyS0 console=tty0 nomodeset norestore base
?
# 修改為:(其實就是加了tz的啟動參數(shù))故俐,然后保存
?
append tz=CST-8 loglevel=3 user=docker console=ttyS0 console=tty0 nomodeset norestore base
?
# 接著你必須在ubuntu環(huán)境下重新制作ISO文件,你可以利用docker跑一個ubuntu紊婉,哈哈药版,假設(shè)你將boot2docker目錄copy到了ubuntu的/src/目錄下,那么接著這么做
?
# 安裝xorriso命令
?
apt-get install xorriso
?
# 構(gòu)建ISO映射
?
xorriso -as mkisofs -J -R -V boot2docker -no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -o /boot2docker.iso /src/
?
# 這樣就生成了/boot2docker.iso文件喻犁,最后你就可以替換到VM的啟動ISO文件了槽片,然后重啟VM了
?
boot2docker restart
?
# 最后你必須設(shè)置你的VM為正確的時間何缓,使用date -s 命令,最后用date命令查看还栓,你就能看到CST時區(qū)的正確時間了
?
Sun Mar 30 00:27:13 CST 2014
?
# 對于你啟動的container碌廓,你都必須重新設(shè)置TZ環(huán)境變量,否則即使VM是CST-8剩盒,你的container還是UCT +00:00的時間
?
export TZ='CST-8'
?
[Format Time: 0.0084 seconds]
第三個問題暫時無法解決(可能需要編輯底層的LXC配置文件)谷婆。
docker的限制以及后續(xù)的一些想法
docker其實還是有一些限制的:
要求你的環(huán)境是Linux的,而且內(nèi)核必須很新(>= 2.6.27 (29))辽聊,這其實是LXC本身的限制纪挎,和docker無關(guān)
docker的Container目前host是不能修改的,當(dāng)然有解決方案(dnsmasq)
docker的Container也暫時無法指定靜態(tài)IP
用docker作為開發(fā)環(huán)境甚至是生產(chǎn)環(huán)境其實還有很多地方值得嘗試:
在團(tuán)隊內(nèi)部構(gòu)建本地的倉庫跟匆,標(biāo)準(zhǔn)化所有的開發(fā)環(huán)境异袄,使得團(tuán)隊的新人可以快速上手
在生產(chǎn)環(huán)境部署docker,這其實是PAAS的虛擬化和自動化的一種方式玛臂,利用LXC和Docker能夠更便捷地實施PAAS
嘗試用docker做分布式集群模擬和測試烤蜕,成本會更加低廉,更加容器維護(hù)
參考文章
Linux虛擬化技術(shù)
利用Linux容器實現(xiàn)可移植的應(yīng)用部署
如何修改host
Building a Development With Docker
boot2docker的build
PAAS Under the Hood
您可能感興趣的文章
把Sheepdog裝進(jìn)OpenStack
自動增量升級方案的設(shè)計及實現(xiàn)
FastDFS使用經(jīng)驗分享