炒個冷飯LXC,試問Docker你憑啥這么火?
每次掃到Docker融資數據,腦子里就會冒出來一個問題:Docker咋就這火呢!那誰,爹都不要了,咋還這么火?9500萬美金的D輪,到底值不值?
事情是這樣的,這兩年我們不斷聽到container、“容器”、Container、Docker...... “容器”大火,但大多數人知道“容器”,估計不是從linux,不是從LXC, 都是因為Docker才知道的吧?不得不說,這就是Docker的厲害之處。
先說說LXC~~LXC中文就是Linux容器工具,linux原生支持的容器,可以追溯到2009年,源于cgroup和namespaces在Linux內核方面的發展,是一種輕量級的容器虛擬化技術,最大效率隔離進程和資源。它可以把傳統虛擬技術以及后來的Xen、KVM的VM進程像HOST進程一樣運行管理, 所以創建和銷毀都非常輕。
2013年,Docker橫空出世,Docker是啥呢?就是一個基于LXC 的高級容器引擎。Docker做了件什么事呢?打包!你可以在一個容器里寫完之后,裝箱打包成一個鏡像,然后輕松部署在不同的運行環境里。Docker解決了運行環境依賴問題,不再有“為啥明明剛才在我那里可以跑起來到你這里就不行”的問題。如果說LXC著眼點在于提供輕量級的虛擬技術,扎根在虛擬機,那Docker則定位于應用。Docker所為人稱道的portability、application-centric、versioning等等超越傳統虛擬技術的優點都跟它的封裝性密不可分。開發和測試裝個docker, pull下image,再也不用受困于不同的開發環境、系統依賴和配置文件。。。是不是瞬間天亮了?
Docker這個發明magic package的故事,就完了嗎?當然不是,問題來了~~ 為什么呢?有人就問了,那我log怎么辦呢?掛在數據卷里!ssh怎么搞呢?用docker exec! 呃,那如果我要跑cron呢?抱歉,沒法子哦。。。說了那么多,Docker的底層鏡像操作系統的設計,僅僅是把一個個進程打包封裝在一個個盒子里,相互隔離,運來運去,別的事情,它一概就不管了。。。。Docker不管多進程應用程序、不管設計、也不管其他服務,而且還stateless... 你是不是要崩潰了??
真相了,是不是?有一個比喻說的很好,Docker不是萬靈藥,它本身也不是一個app或者app的一個部件,而是OS/ubuntu的一個最小單位的磚頭塊,盡管這是史上最牛X的黃金磚。。。然而在生產環境下,實際上更具有挑戰性的問題是,如何能讓成千上萬個Docker封裝的executable magic package有機協同工作,誰來安排誰來管?那就需要一個強大高能的編排系統來運作,Caicloud就是這個高能者~~~(頓時形象高大起來^ ^)
之前Docker的libcontainer,到最近Docker最新版本1.10里移除了對LXC的support,Docker和LXC的分家有很多原因,也勢在必行,但不管未來咋樣,也無法抹殺Docker和LXC之間的傳承。呃,我不是LXC派來的臥底,今天炒的這碗冷飯是說,LXC雖然已經不被Docker支持,但并沒有過時,依然是經典的容器技術;兒子不要爹了,可爹還是那個爹。。。。。。有興趣就來一起玩一玩Docker的老爹吧~~~ 只要你有比較新版本的linux kernel, 就可以建立一個LXC虛機系統來生成運行容器,LXC容器也可以嵌套,可以用cgroup來限定資源。。。
下面參考的這是一篇翻譯自Stephane Graber主頁的文章,LXC系統目前由一個兩人的團隊領導:來自Ubuntu的Stephane Graber和Serge Hallyn, LXC是由Ubuntu支持的。
那么什么是LXC?
你們之中大部分人很應該已經知道什么是LXC了,但是在這里,我們這樣定義:
“LXC是一個為Linux內核包含特征的用戶接口。通過強大的API和簡單的工具,它可以讓Linux用戶輕松的創建和托管系統或者應用程序容器。”
我和Serge Hallyn是LXC的兩個上游維護者之一。每個月,項目都有著里程碑式的積極發展,并且在二月份會發布一個穩定版本。到目前為止,它已經被67個來自不同背景和公司的貢獻者開發。
LXC1.0
那么1.0版本到底發布了什么呢?
好的,簡單的說,它將是第一個真正穩定的LXC版本,也是第一個我們將
支持5年的bug修正版本。它也是包括在Ubuntu14.04LTS里面的一個,將和Ubuntu在2014年4月一起發布。
與之一起的是,穩定的API,一組綁定,很多有趣的新特點。這些新的特點會在下一期的帖子里詳細闡述,并且支持大范圍的主機和客機分布(包括Andriod)。
如何使用它?
我猜你們之中大部分人都將會一直使用Ubuntu。在接下來的少數帖子中,我會一直在Ubuntu14.04上使用目前上游的每日構建,我們維護每日構建的時間分別是:12.04,12.10,13.04,13.10,以及14.04,所以如果想要最新的上游代碼,可以使用我們的PPA。
另外,LXC也是在Ubuntu中直接使用的,在Ubuntu12.04LTS之后也十分有用。你可以選擇這樣一個版本,就是無論你在發布哪個,它都會跟著這個版本,或者你可以使用我們維護的那個布丁版本。
如果想要自己創建,可以這么做(但是如果你在你的linux發行版上面可以是直接使用軟件包,我們不推薦這個方法):
git clone git://github.com/lxc/lxc
cd lxc
sh autogen.sh
You will probably want to run theconfigure script with --help and then set the paths
./configure
make
sudo make install
關于第一個容器
對了, 容器才是我們這篇帖子真正的目標對吧?
好的,那既然你已經安裝了LXC,滿懷希望地使用Ubuntu打包,那么事情就簡單了:
Create a "p1" container usingthe "ubuntu" template and the same version of Ubuntu
and architecture as the host. Pass"-- --help" to list all available options.
sudo lxc-create -t ubuntu -n p1
Start the container (in the background)
sudo lxc-start -n p1 -d
Enter the container in one of thoseways## Attach to the container's console (ctrl-a + q to detach)
sudo lxc-console -n p1
Spawn bash directly in the container(bypassing the console login), requires a >= 3.8 kernel
sudo lxc-attach -n p1
SSH into it
sudo lxc-info -n p1
ssh ubuntu@<ip from lxc-info>
Stop the container in one of those ways
Stop it from within
sudo poweroff
Stop it cleanly from the outside
sudo lxc-stop -n p1
Kill it from the outside
sudo lxc-stop -n p1 -k
好了!這就是你的第一個容器了。你會注意到,所有東西都是在Ubuntu上面運行的。我們的內核支持所有LXC可能使用到的特點,我們的packages構建了橋梁和DHCP服務器,這樣容器在默認情況下就會使用。
LXC2.0 你的第二個容器
更多模版
現在呢,你應該已經有一個在運行的Ubuntu容器了,叫做“p1”,是使用默認模版簡潔“ubuntu”創建的。
但是LXC支持的比標準Ubuntu多很多。事實上,在目前的上游git(以及日常PPA),我們支持AlpineLinux,Alt Linux,Arch Linux,busybox,CentOS,Cirros,Debian,Fedora,OpenMandriva,OpenSUSE,Oracle,Plamo,sshd,Ubuntu云端以及Ubuntu。
以上那些都可以在/usr/share/lxc/templates里面找到。他們通常還有額外的高級選項,可以通過在“lxc-create”呼叫之后輸入“-—help”來實現(“--”可以從模版里分裂出“lxc-create”選項)。
再寫一個額外的模版也不是很困難的事情,他們基本上都是可執行文件(都是shell腳本,但是這不是必須的),采取了一整套標準參數,預計會在路徑中生成一個工作的根文件系統傳遞給他們。
需要注意的一點就是,由于工具丟失,所以不是所有的發行版都可以在發行版上自我啟動的。通常還是要試一試。我們總是喜歡將這些工作運行在更多的發行版上面,即使這么做意味著使用一些小技倆也在所不惜(比如,在fedora模版里,我們就是這么做的)。所以,如果你現下有不能運行的特定組合,歡迎使用補丁~
不管怎樣,先談現下,讓我們繼續往下說,現在我們來創建一個Oracle Linux容器,將其強制為32bit。
sudo lxc-create -t oracle -n p2 -- -a i386
在很多系統上,它一開始就會運行失敗,并告訴你要安裝“rpm”包才可以,bootstrap也有需要這樣的安裝的理由。所以安裝“rpm”,然后再次嘗試。
在下載完RPMs之后一段時間,容器就會被創建了,然后再:
sudo lxc-start -n p2
你會被Oracle Linux登陸提示歡迎使用(root/root)
那么現在,既然你已經開啟容器了,沒有將“-d”傳遞給“lxc-start”,那么你就不得不將其關閉,再將shell弄回來(你不能將一個在背景情境下沒有初始化開的的容器分離)。
那現在如果你很好奇為什么Ubuntu有兩個版本。目前我正在使用的Ubuntu模版用“deboostrap”基本上從頭創建您的容器,但是Ubuntu云端模版(ubuntucloud)下載了一個預生成云鏡像(與你在EC2或者其他云端服務上得到的完全一樣),并開啟。這個鏡像包括初始化云,還支持標準云元數據。
這完全是個人選擇問題,個人喜歡哪個就可以選哪個。我個人建議是擁有一個本地鏡像,這樣的話“ubuntu”模版對我來說就快多了,我知道所有東西都已經在我之前從檔案文件那里下載,并且已經在本地組裝了,因此我更加信任它。
關于模版的最后一個注解。大多數都使用本地緩存,所以最初的容器引導程序進程緩慢,對于一種架構,容器的首次啟動會比較緩慢,之后的啟動會比較快,因為有本地緩存。
自動啟動
那么,如果你想要在開機時序自動開啟容器會怎么樣呢?
其實,上述情況在Ubuntu上和其他的通過使用一些初始腳本和符號連接的發行版上面早就已經是支持的了,但是最近(兩天前),這就已經在上游實施了,干勁利落。
所以這就是自動啟動容器如何的:
可能就像你所知道的,每個容器通常在/var/lib/lxc/<container name>/config下面都有一個配置文件。
那個文件就是key=value,在lxc.conf(5),有效keys清單會被詳細列出來。
可用的啟動相關值有:
§ lxc.start.auto = 0 (disabled) or 1(enabled)
§ lxc.start.delay = 0 (delay in second towait after starting the container)
§ lxc.start.order = 0 (priority of thecontainer, higher value means starts earlier)
§ lxc.group = group1,group2,group3,… (groupsthe container is a member of)
當你的機器啟動的時候,初始腳本就會要求“lxc-autostart”來以正確順序開啟所有已經給定的組的容器(默認情況下,是所有容器而不是任意一個),并且等待這些容器之間的特定時間。
要闡述清楚,編輯/var/lib/lxc/p1/config 并且貼這幾行到文件里:
lxc.start.auto = 1
lxc.group = Ubuntu
以及 /var/lib/lxc/p2/config,并貼上這幾行:
lxc.start.auto = 1
lxc.start.delay = 5
lxc.start.order = 100
那么做意味著,只有p2容器會在開機時間啟動(因為這些如果沒有一個組的話就是系統默認情況),順序值是沒有關系的,因為它是獨立的,初始腳本在你繼續之前會停留5秒。
通過“lxc-ls”可以檢查什么容器是自動啟動的:
stgraber@castiana:~$ sudo lxc-ls --fancy
NAME STATE IPV4 IPV6 AUTOSTART
p1 RUNNING 10.0.3.128 2607:f2c0:f00f:2751:216:3eff:feb1:4c7f YES (ubuntu)
p2 RUNNING 10.0.3.165 2607:f2c0:f00f:2751:216:3eff:fe3a:f1c1 YES
你也可以通過“lxc-autostart“命令手動啟動那些容器,這個命令可以讓你啟動/停止/中止/重新啟動任意用lxc.start.auto=1標記的容器。
比如,你可以這么做:
sudo lxc-autostart –a
這個命令會開啟任意有lxc.start.auto=1(忽略lxc.group值),這在我們的情況下意味著它將第一開啟p2(由于order=100),然后等待5秒(因為delay=5),然后開啟p1,并且之后馬上調回來。
如果在那時你想要中止ubuntu里面的所有容器,你可以這么做:
sudo lxc-autostart -r -g Ubuntu
你也可以通過這些命令中的任意一個來輸入“-L”,這些命令僅僅只是影響打印哪個容器,以及會造成怎樣的延遲,但是事實上并不會有影響(對于與其它腳本集成還是有好處的)。
凍結你的容器
有時候容器可能正在運行守護進程,這個進程需要時間來關閉或者重啟,但是你不要想去運行容器,因為你在那個時間點不是主動使用它的。
在這些情況下,可以使用“sudo lxc-freeze -n <container name>” 。這個僅僅凍結了容器里所有的進程所以他們不會得到任何時間分配的調度器。然而進程還是會存在,而且會繼續使用他們之前所使用的存儲。
一旦你再次需要服務,只要調用 “sudo lxc-unfreeze -n <container name>” ,所有進程就會重新啟動。
連網
你可能已經注意到在配置文件里,當你正在設置自動啟動設置的時候,LXC有一個相對靈活的網絡配置。
系統默認設置下,在Ubuntu里,我們每個容器指定一個“veth”設備,這個在主機上橋接成一個“lxcbr0”橋,在這個上面,我們跑一個最小 dnsmasq DHCP 服務器。
對于大多數人,那都是很好的。你可能想要一些東西略微再復雜一點,比如容器里的多網絡接口,或者通過物理的網絡接口,等等。這些的細節都列在lxc.conf(5)里面了,所以我在這里就不再贅述,但是這里有個簡單的例子可以做:
lxc.network.type = veth
lxc.network.hwaddr = 00:16:3e:3a:f1:c1
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.name = eth0
lxc.network.type = veth
lxc.network.link = virbr0
lxc.network.name = virt0
lxc.network.type = phys
lxc.network.link = eth2
lxc.network.name = eth1
有了這個設置,我的容器就會有3個接口,虛擬接口0在lxcbro橋都是尋常VETH設備,虛擬接口1是主機的,虛擬接口2是移動到容器里面(它會在容器正運行的時候從主機上面消失),virt0則是虛擬網橋的兩個接口。
那兩個接口都沒有mac地址或者網絡信號設置,所以他們會在啟動時間獲得一個隨機的mac地址(非永久),而且,它將由容器決定連接。
附接
如果你正在運行一個最近的內核,也就是3.8以及3.8版本以上,你可能會用到“lxc-attach”工具。它最基本的特點就是在運行的容器里面給你一個標準的shell:
sudo lxc-attach -n p1
你可能也會從腳本使用它在容器里運行動作,比如:
sudo lxc-attach -n p1 -- restart ssh
但是,它的效率遠大于上述,舉個例子,比如:
sudo lxc-attach -n p1 -e -s'NETWORK|UTSNAME'
在上述情況下,你會得到一個shell,就是 “root@p1” (thanks toUTSNAME),正在運行“ifconfig -a” ,從這里可以列出一個容器的網絡接口清單。輸入“e“也意味著cgroup,apparmor,… 從那個shell開啟的任意進程都不會被限制。
這有時候對于繁衍一個位于主機上并且在容器里面或者pid域名里面的軟件是很有幫助的。
通過設備到一個運行的容器上面
能夠按照意愿進入或者脫離一個容器當然是很好的,但是如果能夠在你的主機上通過一些隨機設備進入,那會是怎么樣的?
系統默認設置,LXC將會避免任意的,比如通過運用設備cgroup當成過濾機制作為通道進入。你也可以編輯容器配置來允許額外設備,然后重啟容器。
但是有一個只提一次的事情,就是這里也有一個非常方便的工具叫“lxc-device”,有了它,你就只需要做:
sudo lxc-device add -n p1 /dev/ttyUSB0/dev/ttyS0
這個命令會添加 (mknod) /dev/ttyS0,以及同類型的/major/minor as /dev/ttyUSB0 到容器里,然后添加相匹配的cgroup入口來允許從容器進入。
同樣,這個容器也允許從主機移動網絡設備到容器里面。
來自: http://dockone.io/article/1075