阿里微服務架構師隨手筆記:教你如何手寫Docker

模擬Docker實現一個簡單的容器,不到 200行代碼(包括空行、註釋、異常處理),這並不是吹牛B。容器技術幾乎是Linux kernel內置的模塊,我們簡單調用一下API就能搞定很多事情。當然你要考慮各種商業因素、政治因素那就會成長為Docker這種量級的代碼量了。

盜用一下朋友圈裡的段子:小公司與大公司的區別就是,以殺豬為例,小公司是找到豬直接亂刀砍死。大公司要先做一套籠具抓豬,再做一套流程磨刀,再發明一套刀法(工程師通常會就刀法爭論很久)殺豬。抓豬的籠具除了能抓豬還能抓跳騷,磨刀的工具除了能磨柴刀,還能磨指甲刀。殺豬的流程除了能殺豬,也能殺雞。做完了之後你只敲一個殺豬的命令就行。你不知道豬在哪裡,因為這是另一個人負責的,代碼放在你不知道的某個目錄下;你也不知道刀在哪裡,因為目錄不可見,格式不可讀。刀法是啥你也不知道。這套系統理論上威力無比,一群人費了老大勁做出來,除了用柴刀殺豬沒幹過別的,殺雞從來沒測試過,殺跳騷代碼都不完整。但是公司裡的所有人都覺得,殺豬就應該這樣。所以大家每天忙忙碌碌,豬快活的過了一年又一年。

所以這系列文章我主要介紹如何找到豬、怎麼持刀不傷到自己,如何發力能夠更兇狠;然後現場表演一下把一頭活蹦亂跳的豬捅死。

涉及到的技術

寫一個容器只需要兩個技術——Namespace和CGroup,而這兩個東西都是Linux kernel提供的,我們要做的就是——調用一下。無恥的盜用一下Brendan Gregg大神的圖。

阿里微服務架構師隨手筆記:教你如何手寫Docker

這張圖中蘊含了一個經常被忽視的細節——容器是共享內核的,它們屬於多個進程同時運行在一個內核上,只不過是利用Namespace把它們隔離開,用CGroup限制可用資源。而虛擬機是共享“硬件”的,每個虛擬機都有自己獨立的操作系統。所以,虛擬機是可引導的、絕對安全的隔離技術;而容器是非常脆弱的,不安全的隔離技術。

Namespace是Linux內核提供的一種隔離技術,它提供了六種隔離空間:

阿里微服務架構師隨手筆記:教你如何手寫Docker

看的一臉懵逼對不對?沒關係,簡單的解釋一下。

學過操作系統原理的同學都知道(沒學過?你還敢在這個行業混?),在一個內核所有進程都共享操作系統定義的資源——主機名、域名、ARP表、路由表、NAT表;文件系統、用戶和組、進程編號。以主機名為例,它是由操作系統定義在一塊內存空間中的,所以進程A能看到,進程B也能看到(如果有權限甚至可以修改)。Namespace提供了一種隔離技術,可以讓每個進程都定義“自己的主機名”。你可以理解為內核為每個進程都提供了一份當前主機名的備份,進程當然可以修改這份數據,但是這個修改只能作用於自己,其他進程感知不到——因為它不再是“全局”的。

經常有人問是不是所有應用都可以做容器化?理解Namespace就很容易回答這個問題。容器技術本質上還是共享內核,所以任何需要修改內核的應用都不可以被容器化。比如LVS、OpenvSwtich這些需要加載內核模塊的應用都沒有辦法做成容器。

如果你也想在IT行業拿高薪,可以參加我們的訓練營課程,選擇最適合自己的課程學習,技術大牛親授,7個月後,進入名企拿高薪。我們的課程內容有:Java工程化、高性能及分佈式、高性能、深入淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點。如果你想拿高薪的,想學習的,想就業前景好的,想跟別人競爭能取得優勢的,想進阿里面試但擔心面試不過的,你都可以來,群號為: 454377428


注:加群要求

1、具有1-5工作經驗的,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加。

2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的可以加。

3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,常用設計思想,常用java開發框架掌握熟練的,可以加。

4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加。

5.阿里Java高級大牛直播講解知識點,分享知識,多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!

6.小號或者小白之類加群一律不給過,謝謝。

目標已經有了,下面就看行動了!記住:學習永遠是自己的事情,你不學時間也不會多,你學了有時候卻能夠使用自己學到的知識換得更多自由自在的美好時光!時間是生命的基本組成部分,也是萬物存在的根本尺度,我們的時間在那裡我們的生活就在那裡!我們價值也將在那裡提升或消弭!Java程序員,加油吧

Hello world

調用Namespace非常簡單,只需要一個API(沒錯,一個,只要一個)——clone。

阿里微服務架構師隨手筆記:教你如何手寫Docker

它會創建一個新的線程(內核不會太區分線程和進程),第一個參數指定了線程的代碼入口,第二個參數是線程棧,第三個參數是標誌位,第四個參數是代碼入口的參數指針。

我們上面所羅列的Namespace參數就是通過第三個參數——標誌位傳遞的。

阿里微服務架構師隨手筆記:教你如何手寫Docker

我們先測試一下UTS(主機名)是否能正常工作,因為子進程不涉及到遞歸調用所以定義1024字節的stack大小應該足夠了。main方法裡的os.waitpid(pid, 0)是必須的,否則子進程會因為父進程終止而提前退出。

child_func是子進程的入口,這段代碼裡我們調用sethostname修改主機然後再執行hostname驗證修改是否生效了。

libc是我封裝好的系統調用,非常簡單。

阿里微服務架構師隨手筆記:教你如何手寫Docker

小試牛刀一下:

阿里微服務架構師隨手筆記:教你如何手寫Docker

首先在父進程中輸出自己的進程編號和子進程的編號,然後在子進程中輸出自己的進程編號和父進程的編號。在子進程中我們調用sethostname修改了主機名並且通過hostname驗證了調用結果。但是這個修改並沒有波及到內核,最後我們在shell中調用hostname驗證了這一結果。

要有Shell

上面只是執行一次修改hostname的動作,動作有點小,不夠過癮。我們希望能夠在獨立的Namespace中拿到一個shell。

阿里微服務架構師隨手筆記:教你如何手寫Docker

只需要更改兩行代碼。父進程裡面增加NEW_PID、NEW_IPC的標誌位,子進程裡調用execle執行bash,通過最後一個參數指定了環境變量PS1,這個表示提示符。

阿里微服務架構師隨手筆記:教你如何手寫Docker

再次執行,我們發現shell已經變化了。通過hostname驗證我們已經“在容器裡面”了。鍵入exit,退出容器。

是不是已經無法掩蓋自己內心的興奮了。別急,還有更興奮的,我們進行第三步——分離文件系統。

推薦一個交流學習群:478030634 裡面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多:

徹底分離

如果你在上一部的shell中輸入一些top、ps、ls命令會發現幾乎和“Host”環境中一摸一樣。這是因為我們還沒有做最重要的一部——分離文件系統。

Docker提供的有Ubuntu、CentOS的鏡像,其實這些並不是嚴格意義上的鏡像,它們準確的叫法應該是——根文件系統(root filesystem)。

容器是共享內核的,所以無論是Ubuntu、CentOS它們裡面都使用Host的內核,如果你在Docker中通過uname查看會發現無論什麼鏡像它們的內核版本都和Host一摸一樣。所以,不同“操作系統”Docker鏡像其實就是不同的根文件系統。

很多人用BusyBox的rootfs做演示,作為一個風騷的男人怎麼怎麼可能如此俗套。所以我用CentOS 7作為演示。

真正的原因切換容器中的根目錄,後續的代碼執行會使用新的根文件系統,而後續的代碼是依賴Python運行環境的。所以我們需要一個帶Python的rootfs,CentOS 7剛好滿足這個。如果我們用C或者Golang就不會有這個限制了。

你可以通過CentOS提供的Dockerfile找到相關的rootfs的下載,比如:https://github.com/CentOS/sig- ... ocker

阿里微服務架構師隨手筆記:教你如何手寫Docker

把下載到的文件解壓到/tmp目錄下。

阿里微服務架構師隨手筆記:教你如何手寫Docker

分離文件系統分為三個步驟,首先我們建立容器裡面的/proc文件系統,很多Linux命令都是讀取這個文件系統下的內容(比如top中顯示的進程列表);其次我們要把現在的用戶和容器裡面的用戶做映射,否則會提示權限不足;最後我們要通過pivot_root 函數把“切換”根文件系統。

阿里微服務架構師隨手筆記:教你如何手寫Docker

不要忘記修改main方法,為標誌位增加三個參數,映射用戶。

阿里微服務架構師隨手筆記:教你如何手寫Docker

再次執行。

阿里微服務架構師隨手筆記:教你如何手寫Docker

和CentOS 7一摸一樣,你甚至可以用yum命令,當然由於我們現在還沒有實現網絡功能所以yum會告訴你無法訪問網絡。

再多執行幾個添加文件、刪除文件看看?你會發現無論做什麼動作最終的數據都會被牢牢地固定在/tmp/rootfs下,也就是說——在容器裡面我們是沒有辦法訪問host的文件的。

完整代碼:https://github.com/fireflyc/mini-docker。

如果想學習Java性能優化,工程化、高性能及分佈式、深入淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友可以加下454377428群裡有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給大家。


分享到:


相關文章: