快速理解Docker
作者:劉旭暉 Raymond 轉載請註明出處
是什麼
簡單的說Docker是一個構建在LXC之上的,基於程序容器(Processcontainer)的輕量級VM解決方案
拿現實世界中貨物的運輸作類比, 為了解決各種型號規格尺寸的貨物在各種運輸工具上進行運輸的問題,我們發明了集裝箱
Docker的初衷也就是將各種應用程式和他們所依賴的執行環境打包成標準的container/image,進而釋出到不同的平臺上執行
從理論上說這一概念並不新鮮, 各種虛擬機器Image也起著類似的作用
Docker container和普通的虛擬機器Image相比, 最大的區別是它並不包含作業系統核心
普通虛擬機器將整個作業系統執行在虛擬的硬體平臺上, 進而提供完整的執行環境供應用程式執行, 而Docker則直接在宿主平臺上載入執行應用程式. 本質上他在底層使用LXC啟動一個Linux Container,通過cgroup等機制對不同的container內執行的應用程式進行隔離,許可權管理和quota分配等
每個container擁有自己獨立的各種名稱空間(亦即資源)包括:
PID程序, MNT檔案系統, NET網路, IPC, UTS主機名等
與LXC有什麼不同
基本上你可以認為目前的Docker是LXC的一個高階封裝,提供了各種輔助工具和標準介面方便你使用LXC,
實際使用中,你一般不用關心底層LXC的細節,同時也不排將來docker實現基於非LXC方案的可能性
在LXC的基礎上, Docker額外提供的Feature包括:標準統一的打包部署執行方案,歷史版本控制, Image的重用,Image共享釋出等等
Container構建方案
除了LXC,Docker的核心思想就體現在它的執行容器構建方案上
為了最大化重用Image,加快執行速度,減少記憶體和磁碟footprint, Docker container
有了層級化的Image做基礎,理想中,不同的APP就可以既可能的共用底層檔案系統,相關依賴工具等,同一個APP的不同例項也可以實現共用絕大多數資料,進而以copy on write的形式維護自己的那一份修改過的資料等
歷史和生態環境
Docker專案從啟動到現在不過一年多時間,發展勢頭還是很迅猛的
2013.01 做為dotcloud內部專案開始啟動
2013.03.27 正式作為public專案釋出
2014.1被BLACK DUCK 評選為2013年10大開源新專案“TOP 10 OPEN SOURCE ROOKIE OF THE YEAR”
目前的狀態 ( 2014.3 )
Docker 0.8.1
10000+ github stars(top 50)
350+ contributors
1500+ fork
具體應用方面,可以看到百度至少在2013年10月份就已經成功使用Docker支援其BAE平臺的Paas服務
安裝執行和使用
Docker雖然是號稱build once, runeverywhere。但是實際上還是受其引擎依賴關係的限制的,目前的版本具體來說對系統要求:
- Linux Kernel 3.8+
- LXC support
- 64bit OS
- AUFS
以上要求,以ubuntu為例,需要12.04 配合 3.8kernel升級,或者 ubuntu 13.04+
在ubuntu12.04上,基本安裝步驟如下
sudoapt-get update sudo apt-get install linux-image-generic-lts-raringlinux-headers-generic-lts-raring
sudoapt-key adv --keyserver keyserver.ubuntu.com --recv-keys36A1D7869245C8950F966E92D8576A8BA88D21E9
sudosh -c "echo deb http://get.docker.io/ubuntudocker main\ > /etc/apt/sources.list.d/docker.list"
sudoapt-get update
sudoapt-get install lxc-docker
常用命令
分類列一下常用的CLI命令
- 倉庫相關
search/ pull / push / login etc.
例:docker pull ubuntu從倉庫下載ubuntuimage
- Images操作相關
images/ rmi / build / export / import / save /load etc.
例:docker images -t以樹形結構列出當前本地Image
- 執行相關
run / start / stop / restart / attach /kill etc.
docker run -i -t ubuntu /bin/bash啟動ubuntu image,並互動式的執行shell
- 雜項
Docker diff / commit
Dockerinfo / ps / inspect / port / logs / top / history etc.
常見問題
- 使用Non root 使用者
目前版本的docker由於使用Socket進行通訊,因此需要root使用者許可權 sudo xxx,或者將需要使用Dockerclient的使用者加入docker使用者組
sudogpasswd -a ${USER} docker
- 網路相關問題
當你在閘道器背後需要通過代理連線docker的index資料庫時,可以手動加上http_proxy環境變數來啟動dockerdaemon
更好的做法是修改/etc/default/docker ( on ubuntu ), 新增exporthttp_proxy=proxy_server:port
同樣,docker container 如果無法自動正確的從host環境中獲得DNS的配置,則需要手動指定DNS伺服器地址,這可以通過 docker -run --dns=xxx 來實現,也可以修改/etc/default/docker 新增例如DOCKER_OPTS="-dns 8.8.8.8"
- 特權模式
在正常情況下在container內部你沒有許可權操作device裝置,而當前版本中,container內部部分檔案例如/etc/hosts;/etc/hostname; /etc/resolve.conf等檔案是動態通過mount動態以只讀的形式載入上來的,理論上說你應該找到合適的方法去保證這些自動生成並載入的檔案的正確性 (例如通過--dns 設定 resolve.conf ),但是如果由於特殊原因你需要手動修改,那麼你可以通過特權模式啟動 docker client : docker run --privileged ,然後你可以解除安裝這些檔案,自己再建立新的版本
- 過多的層級依賴關係
以Layer的方式實現APP和相關library的cheap reuse和fast update是Docker的關鍵所在,不過受目前AUFS檔案系統的限制,預設Layer的層級最多隻能達到127(曾經只有42),在實際使用中有多種情況可能導致你的container的層級關係快速增長到這個極限值,撇開這麼多layer疊加以後AUFS的效率不談,更多情況下是你無法再更新構建你的image了
- 使用Dockerfile構建Image時,每條指令都會給最終的Image增加一層layer依賴關係.
- 以修改,提交,再修改再提交的方式不停的調整,更新你的Image
- 從倉庫中下載的別人的Image已經包含眾多的層級依賴關係,而你需要進一步更新以建立你自己的版本
前兩者在一定程度上還是你自己可能把控的,最後一種情況就沒辦法了。這個問題最終必將影響Docker的實際可用性,目前的解決方案包括:
- 使用Dockerfile時,儘可能合併多個操作:例如使用 "&&" 或 ";" 合併執行多個shell命令;將多個shell命令寫成指令碼,在dockerfile中新增並執行這個指令碼
- 通過Export再Import Image,丟棄所有歷史資訊和依賴關係,建立一個全新的image
將來可能的解決方案包括:
- 在Dockerfile中新增對多步操作的合併提交的支援
- 外部的image Flat工具的支援,目標是能夠保留歷史資訊等
- 非AUFS的其它Storage解決方案
Future development
雖然Docker目前預設使用LXC和AUFS,但是Docker的核心思想本身,並不強制繫結這兩者,0.8版本已經可以使用BTRFS,而整個Docker框架也改成了外掛式的架構,便於新增替換各個功能模組
例如更多的Storage方案的支援,規避AUFS當前的問題,除了LXC以外更多的虛擬化方案等