多年前的一個夜晚,風雨大做,一個名叫Docker的年輕人來到Linux帝國拜見帝國的長老。nginx
「Linux長老,天下程序員苦於應用部署久矣,我要改變這一現狀,但願長老你能幫幫我」程序員
長老回答:「哦,小小年紀,口氣不小,先請入座,你有何所求,願聞其詳」web
Docker坐下後開始侃侃而談:「當今天下,應用開發、測試、部署,各類庫的依賴紛繁複雜,再加上版本之間的差別,常常出如今開發環境運行正常,而到測試環境和線上環境就出問題的現象,程序員們飽受此苦,是時候改變這一情況了。」redis
Docker回頭看了一眼長老接着說到:「我想作一個虛擬的容器,讓應用程序們運行其中,將它們須要的依賴環境總體打包,以便在不一樣機器上移植後,仍然能提供一致的運行環境,完全將程序員們解放出來!」編程
Linux長老聽聞,微微點頭:「年輕人想法不錯,不過聽你的描述,好像虛擬機就能解決這個問題。將應用和所依賴的環境部署到虛擬機中,而後作個快照,直接部署虛擬機不就能夠了嗎?」跨域
Docker連連搖頭說到:「長老有所不知,虛擬機這傢伙笨重如牛,體積又大,動不動就是以G爲單位的大小,由於它裏面要運行一個完整的操做系統,因此跑起來格外費勁,慢就不說了,還很是佔資源,一臺機器上跑不了幾臺虛擬機就把性能拖垮了!而我想要作一個輕量級的虛擬容器,只提供一個運行環境,不用運行一個操做系統,全部容器中的系統內核仍是和外面的宿主機共用的,這樣就能夠批量複製不少個容器,輕便又快捷」網絡
Linux長老站了起來,來回踱步了幾圈,思考片刻以後,突然拍桌子大聲說到:「真是個好想法,這個項目我投了!」app
Docker眼裏見光,喜上眉梢,「這事還真離不開長老的幫助,要實現我說的目標,對進程的管理隔離都相當重要,還望長老助我一臂之力!」編程語言
「你稍等」,Linux長老轉身回到內屋。沒多久就出來了,手裏拿了些什麼東西。編輯器
「年輕人,回去以後,儘管放手大幹,我賜你三個錦囊,若遇難題,可依次拆開,必有大用」
Docker開心的收下了三個錦囊,拜別Linux長老後,冒雨而歸。
受到長老的鼓勵,Docker充滿了幹勁,很快就準備啓動他的項目。
做爲一個容器,首要任務就是限制容器中進程的活動範圍——能訪問的文件系統目錄。決不能讓容器中的進程去肆意訪問真實的系統目錄,得將他們的活動範圍劃定到一個指定的區域,不得越雷池半步!
到底該如何限制這些進程的活動區域呢?Docker遇到了第一個難題。
苦思良久未果,Docker終於忍不住拆開了Linux長老送給本身的第一個錦囊,只見上面寫了兩個函數的名字:chroot & pivot_root。
Docker從未使用過這兩個函數,因而在Linux帝國四處打聽它們的做用。後來得知,經過這兩個函數,能夠修改進程和系統的根目錄到一個新的位置。Docker大喜,長老真是誠不欺我!
有了這兩個函數,Docker開始想辦法怎麼來「僞造」一個文件系統來欺騙
容器中的進程。
爲了避免露出破綻,Docker很聰明,用操做系統鏡像文件掛載到容器進程的根目錄下,變成容器的rootfs,和真實系統目錄如出一轍,足能夠以假亂真:
$ ls /
bin dev etc home lib lib64 mnt opt proc root run sbin sys tmp usr var
文件系統的問題總算解決了,可是Docker不敢懈怠,由於在他內心,還有一個大問題一直困擾着他,那就是如何把真實系統所在的世界隱藏起來,別讓容器中的進程看到。
好比進程列表、網絡設備、用戶列表這些,是決不能讓容器中的進程知道的,得讓他們看到的世界是一個乾淨如新的系統。
Docker內心清楚,本身雖然叫容器,但這只是表面現象,容器內的進程其實和本身同樣,都是運行在宿主操做系統上面的一個個進程,想要遮住這些進程的眼睛,瞞天過海,實在不是什麼容易的事情。
Docker想過用HOOK的方式,欺騙進程,但實施起來工做太過複雜,兼容性差,穩定性也得不到保障,思來想去也沒想到什麼好的主意。
正在束手無策之際,Docker又想起了Linux長老送給本身的錦囊,他趕忙拿了出來,打開了第二個錦囊,只見上面寫着:namespace。
Docker仍是不解其中之意,因而又在Linux帝國處處打聽什麼是namespace。
通過一陣琢磨,Docker總算是明白了,原來這個namespace是帝國提供的一種機制,經過它能夠劃定一個個的命名空間,而後把進程劃分到這些命名空間中。
而每一個命名空間都是獨立存在的,命名空間裏面的進程都沒法看到空間以外的進程、用戶、網絡等等信息。
這不正是Docker想要的嗎?真是踏破鐵鞋無覓處,得來全不費功夫!
Docker趕忙加班加點,用上了這個namespace,將進程的「視野」鎖定在容器規定的範圍內,如此一來,容器內的進程似乎被施上了障眼法,再也看不到外面的世界。
文件系統和進程隔離的問題都解決了,Docker內心的石頭總算是放下了。內心着急着想測試本身的容器,可又好奇這最後一個錦囊寫的是什麼,因而打開了第三個錦囊,只見上面寫着:CGroup。
這又是什麼東西?Docker仍然看不懂,不過這一次管不了那麼許多了,先運行起來再說。
試着運行了一段時間,一切都在Docker的計劃之中,容器中的進程都能正常的運行,都被他構建的虛擬文件系統和隔離出來的系統環境給欺騙了,Docker高興壞了!
很快,Docker就開始在Linux帝國推廣本身的容器技術,結果大受歡迎,收穫了無數粉絲,連nginx、redis等一衆大佬都紛紛入駐。
然而,鮮花與掌聲的背後,Docker殊不知道本身即將大難臨頭。
這天,Linux帝國內存管理部的人扣下了Docker準備「處決」掉他,Docker一臉詫異的問到,「到底發生了什麼事,爲何要對我下手?」
管理人員厲聲說到:「帝國管理的內存快被一個叫Redis的傢伙用光了,如今要挑選一些進程來殺掉,很差意思,你中獎了」
Redis?這傢伙不是我容器裏的進程嗎?Docker心中一驚!
「兩位大人,我認識帝國的長老,麻煩通融通融,找別人去吧,Redis那傢伙,我有辦法收拾他」
沒想到他還認識帝國長老,管理人員猶豫了一下,就放了Docker到別處去了。
驚魂未定的Docker,思來想去,若是不對容器中的進程加以管束,那簡直太危險了!除了內存,還有CPU、硬盤、網絡等等資源,若是某個容器進程霸佔着CPU不放手,又或者某個容器進程瘋狂寫硬盤,那早晚得連累到本身身上。看來必須得對這些進程進行管控,防止他們幹出出格的事來。
這時候,他想起了Linux長老的第三個錦囊:CGroup!說不定能解這燃眉之急。
通過一番研究,Docker如獲至寶,原來這CGroup和namespace相似,也是Linux帝國的一套機制,經過它能夠劃定一個個的分組,而後限制每一個分組可以使用的資源,好比內存的上限值、CPU的使用率、硬盤空間總量等等。系統內核會自動檢查和限制這些分組中的進程資源使用量。
Linux長老這三個錦囊簡直太貼心了,一個比一個有用,Docker心裏充滿了感激。
隨後,Docker加上了CGroup技術,增強了對容器中的進程管控,這才鬆了一口氣。
在Linux長老三個錦囊妙計的加持下,Docker可謂風光一時,成爲了Linux帝國的大名人。
然而,能力越大,責任越大,讓Docker沒想到的是,新的挑戰還在後面。