程式設計師受苦久矣
多年前的一個夜晚,風雨大作,一個名叫Docker的年輕人來到Linux帝國拜見帝國的長老。
“Linux長老,天下程式設計師苦於應用部署久矣,我要改變這一現狀,希望長老你能幫幫我”
長老回答:“哦,小小年紀,口氣不小,先請入座,你有何所求,願聞其詳”
Docker坐下後開始侃侃而談:“當今天下,應用開發、測試、部署,各種庫的依賴紛繁複雜,再加上版本之間的差異,經常出現在開發環境執行正常,而到測試環境和線上環境就出問題的現象,程式設計師們飽受此苦,是時候改變這一狀況了。”
Docker回頭看了一眼長老接著說到:“我想做一個虛擬的容器,讓應用程式們執行其中,將它們需要的依賴環境整體打包,以便在不同機器上移植後,仍然能提供一致的執行環境,徹底將程式設計師們解放出來!”
Linux長老聽聞,微微點頭:“年輕人想法不錯,不過聽你的描述,好像虛擬機器就能解決這個問題。將應用和所依賴的環境部署到虛擬機器中,然後做個快照,直接部署虛擬機器不就可以了嗎?”
Docker連連搖頭說到:“長老有所不知,虛擬機器這傢伙笨重如牛,體積又大,動不動就是以G為單位的大小,因為它裡面要執行一個完整的作業系統,所以跑起來格外費勁,慢就不說了,還非常佔資源,一臺機器上跑不了幾臺虛擬機器就把效能拖垮了!而我想要做一個輕量級的虛擬容器,只提供一個執行環境,不用執行一個作業系統,所有容器中的系統核心還是和外面的宿主機共用的,這樣就可以批次複製很多個容器,輕便又快捷”
Linux長老站了起來,來回踱步了幾圈,思考片刻之後,忽然拍桌子大聲說到:“真是個好想法,這個專案我投了!”
Docker眼裡見光,喜上眉梢,“這事還真離不開長老的幫助,要實現我說的目標,對程序的管理隔離都至關重要,還望長老助我一臂之力!”
“你稍等”,Linux長老轉身回到內屋。沒多久就出來了,手裡拿了些什麼東西。
“年輕人,回去之後,儘管放手大幹,我賜你三個錦囊,若遇難題,可依次拆開,必有大用”
Docker開心的收下了三個錦囊,拜別Linux長老後,冒雨而歸。
【文章福利】需要C/C++ Linux伺服器架構師學習資料加群812855908(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等)
錦囊1:chroot & pivot_root受到長老的鼓勵,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
錦囊2:namespace
檔案系統的問題總算解決了,但是Docker不敢懈怠,因為在他心裡,還有一個大問題一直困擾著他,那就是如何把真實系統所在的世界隱藏起來,別讓容器中的程序看到。
比如程序列表、網路裝置、使用者列表這些,是決不能讓容器中的程序知道的,得讓他們看到的世界是一個乾淨如新的系統。
Docker心裡清楚,自己雖然叫容器,但這只是表面現象,容器內的程序其實和自己一樣,都是執行在宿主作業系統上面的一個個程序,想要遮住這些程序的眼睛,瞞天過海,實在不是什麼容易的事情。
Docker想過用HOOK的方式,欺騙程序,但實施起來工作太過複雜,相容性差,穩定性也得不到保障,思來想去也沒想到什麼好的主意。
正在一籌莫展之際,Docker又想起了Linux長老送給自己的錦囊,他趕緊拿了出來,打開了第二個錦囊,只見上面寫著:namespace。
Docker還是不解其中之意,於是又在Linux帝國到處打聽什麼是namespace。
經過一陣琢磨,Docker總算是明白了,原來這個namespace是帝國提供的一種機制,透過它可以劃定一個個的名稱空間,然後把程序劃分到這些名稱空間中。
而每個名稱空間都是獨立存在的,命名空間裡面的程序都無法看到空間之外的程序、使用者、網路等等資訊。
這不正是Docker想要的嗎?真是踏破鐵鞋無覓處,得來全不費功夫!
Docker趕緊加班加點,用上了這個namespace,將程序的“視野”鎖定在容器規定的範圍內,如此一來,容器內的程序彷佛被施上了障眼法,再也看不到外面的世界。
錦囊3:CGroup檔案系統和程序隔離的問題都解決了,Docker心裡的石頭總算是放下了。心裡著急著想測試自己的容器,可又好奇這最後一個錦囊寫的是什麼,於是打開了第三個錦囊,只見上面寫著:CGroup。
這又是什麼東西?Docker仍然看不懂,不過這一次管不了那麼許多了,先執行起來再說。
試著運行了一段時間,一切都在Docker的計劃之中,容器中的程序都能正常的執行,都被他構建的虛擬檔案系統和隔離出來的系統環境給欺騙了,Docker高興壞了!
然而,鮮花與掌聲的背後,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沒想到的是,新的挑戰還在後面。