容器技術的起源
假設你們公司正在祕密研發下一個“今日頭條”APP,我們姑且稱為明日頭條,程式設計師自己從頭到尾搭建了一套環境開始寫程式碼,寫完程式碼後程式設計師要把程式碼交給測試同學測試,這時測試同學開始從頭到尾搭建這套環境,測試過程中出現問題程式設計師也不用擔心,大可以一臉無辜的撒嬌,“明明在人家的環境上可以執行的”。
測試同學測完後終於可以上線了,這時運維同學又要重新從頭到尾搭建這套環境,費了九牛二虎之力搭建好環境開始上線,糟糕,上線系統就崩潰了,這時心理素質好的程式設計師又可以施展演技了,“明明在人家的環境上可以執行的”。
從整個過程可以看到,不但我們重複搭建了三套環境還要迫使程式設計師轉行演員浪費表演才華,典型的浪費時間和效率,聰明的程式設計師是永遠不會滿足現狀的,因此又到了程式設計師改變世界的時候了,容器技術應運而生。
有的同學可能會說:“等等,先別改變世界,我們有虛擬機器啊,VMware好用的飛起,先搭好一套虛擬機器環境然後給測試和運維clone出來不就可以了嗎?”
在沒有容器技術之前,這確實是一個好辦法,只不過這個辦法還沒有那麼好。
先科普一下,現在雲端計算其底層的基石就是虛擬機器技術,雲端計算廠商買回來一堆硬體搭建好資料中心後使用虛擬機器技術就可以將硬體資源進行切分了,比如可以切分出100臺虛擬機器,這樣就可以賣給很多使用者了。
你可能會想這個辦法為什麼不好呢?
容器技術 vs 虛擬機器
我們知道和一個單純的應用程式相比,作業系統是一個很重而且很笨的程式,簡稱笨重,有多笨重呢?
我們知道作業系統執行起來是需要佔用很多資源的,大家對此肯定深有體會,剛裝好的系統還什麼都沒有部署,單純的作業系統其磁碟佔用至少幾十G起步,記憶體要幾個G起步。
假設我有一臺機器,16G記憶體,需要部署三個應用,那麼使用虛擬機器技術可以這樣劃分:
在這臺機器上開啟三個虛擬機器,每個虛擬機器上部署一個應用,其中VM1佔用2G記憶體,VM2佔用1G記憶體,VM3佔用了4G記憶體。
我們可以看到虛擬本身就佔據了總共7G記憶體,因此我們沒有辦法劃分出更多虛擬機器從而部署更多的應用程式,可是我們部署的是應用程式,要用的也是應用程式而不是作業系統。
如果有一種技術可以讓我們避免把記憶體浪費在“無用”的作業系統上豈不是太香?這是問題一,主要原因在於作業系統太重了。
還有另一個問題,那就是啟動時間問題,我們知道作業系統重啟是非常慢的,因為作業系統要從頭到尾把該檢測的都檢測了該載入的都載入上,這個過程非常緩慢,動輒數分鐘,因此作業系統還是太笨了。
那麼有沒有一種技術可以讓我們獲得虛擬機器的好處又能克服這些缺點從而一舉實現魚和熊掌的兼得呢?
答案是肯定的,這就是容器技術。
什麼是容器
容器一詞的英文是container,其實container還有集裝箱的意思,集裝箱絕對是商業史上了不起的一項發明,大大降低了海洋貿易運輸成本。讓我們來看看集裝箱的好處:
-
集裝箱之間相互隔離
-
長期反覆使用
-
快速裝載和解除安裝
-
規格標準,在港口和船上都可以擺放
回到軟體中的容器,其實容器和集裝箱在概念上是很相似的。
現代軟體開發的一大目的就是隔離,應用程式在執行時相互獨立互不干擾,這種隔離實現起來是很不容易的,其中一種解決方案就是上面提到的虛擬機器技術,通過將應用程式部署在不同的虛擬機器中從而實現隔離。
但是虛擬機器技術有上述提到的各種缺點,那麼容器技術又怎麼樣呢?
與虛擬機器通過作業系統實現隔離不同,容器技術只隔離應用程式的執行時環境但容器之間可以共享同一個作業系統,這裡的執行時環境指的是程式執行依賴的各種庫以及配置。
從圖中我們可以看到容器更加的輕量級且佔用的資源更少,與作業系統動輒幾G的記憶體佔用相比,容器技術只需數M空間,因此我們可以在同樣規格的硬體上大量部署容器,這是虛擬機器所不能比擬的,而且不同於作業系統數分鐘的啟動時間容器幾乎瞬時啟動,容器技術為打包服務棧提供了一種更加高效的方式,So cool。
那麼我們該怎麼使用容器呢?這就要講到docker了。
注意,容器是一種通用技術,docker只是其中的一種實現。
什麼是docker
docker是一個用Go語言實現的開源專案,可以讓我們方便的建立和使用容器,docker將程式以及程式所有的依賴都打包到docker container,這樣你的程式可以在任何環境都會有一致的表現,這裡程式執行的依賴也就是容器就好比集裝箱,容器所處的作業系統環境就好比貨船或港口,程式的表現只和集裝箱有關係(容器),和集裝箱放在哪個貨船或者哪個港口(作業系統)沒有關係。
因此我們可以看到docker可以遮蔽環境差異,也就是說,只要你的程式打包到了docker中,那麼無論執行在什麼環境下程式的行為都是一致的,程式設計師再也無法施展表演才華了,不會再有“在我的環境上可以執行”,真正實現“build once, run everywhere”。
此外docker的另一個好處就是快速部署,這是當前網際網路公司最常見的一個應用場景,一個原因在於容器啟動速度非常快,另一個原因在於只要確保一個容器中的程式正確執行,那麼你就能確信無論在生產環境部署多少都能正確執行。
如何使用docker
docker中有這樣幾個概念:
-
dockerfile
-
image
-
container
實際上你可以簡單的把image理解為可執行程式,container就是執行起來的程式。
那麼寫程式需要原始碼,那麼“寫”image就需要dockerfile,dockerfile就是image的原始碼,docker就是"編譯器"。
因此我們只需要在dockerfile中指定需要哪些程式、依賴什麼樣的配置,之後把dockerfile交給“編譯器”docker進行“編譯”,也就是docker build命令,生成的可執行程式就是image,之後就可以執行這個image了,這就是docker run命令,image執行起來後就是docker container。
具體的使用方法就不再這裡贅述了,大家可以參考docker的官方文件,那裡有詳細的講解。
docker是如何工作的
實際上docker使用了常見的CS架構,也就是client-server模式,docker client負責處理使用者輸入的各種命令,比如docker build、docker run,真正工作的其實是server,也就是docker demon,值得注意的是,docker client和docker demon可以執行在同一臺機器上。
接下來我們用幾個命令來講解一下docker的工作流程:
-
docker build
當我們寫完dockerfile交給docker“編譯”時使用這個命令,那麼client在接收到請求後轉發給docker daemon,接著docker daemon根據dockerfile建立出“可執行程式”image。
-
docker run
有了 “可執行程式” image 後就可以執行程式了,接下來使用命令docker run
,docker daemon 接收到該命令後找到具體的image,然後載入到記憶體開始執行,image 執行起來就是所謂的 container。
-
docker pull
其實docker build
和docker run
是兩個最核心的命令,會用這兩個命令基本上 docker 就可以用起來了,剩下的就是一些補充。那麼docker pull是什麼意思呢?
我們之前說過,docker中image的概念就類似於“可執行程式”,我們可以從哪裡下載到別人寫好的應用程式呢?很簡單,那就是APP Store,即應用商店。與之類似,既然image也是一種“可執行程式”,那麼有沒有"Docker Image Store"呢?答案是肯定的,這就是 Docker Hub,docker官方的“應用商店”,你可以在這裡下載到別人編寫好的image,這樣你就不用自己編寫dockerfile了。
docker registry 可以用來存放各種image,公共的可以供任何人下載image的倉庫就是 docker Hub。那麼該怎麼從 Docker Hub 中下載image呢,就是這裡的 docker pull命令了。
因此,這個命令的實現也很簡單,那就是使用者通過docker client傳送命令,docker daemon 接收到命令後向 docker registry 傳送 image下載請求,下載後存放在本地,這樣我們就可以使用image了。
最後,讓我們來看一下docker的底層實現。
docker的底層實現
docker 基於 Linux核心 提供這樣幾項功能實現的:
-
NameSpace
我們知道 Linux 中的 PID、IPC、網路等資源是全域性的,而 NameSpace 機制是一種資源隔離方案,在該機制下這些資源就不再是全域性的了,而是屬於某個特定的 NameSpace,各個 NameSpace 下的資源互不干擾,這就使得每個 NameSpace 看上去就像一個獨立的作業系統一樣,但是隻有NameSpace是不夠。
-
Control groups
雖然有了 NameSpace 技術可以實現資源隔離,但程式還是可以不受控的訪問系統資源,比如 CPU、記憶體、磁碟、網路等,為了控制容器中程式對資源的訪問,Docker 採用 control groups技術(也就是cgroup),有了 cgroup 就可以控制容器中程式對系統資源的消耗了,比如你可以限制某個容器使用記憶體的上限、可以在哪些CPU上執行等等。
總結
docker是目前非常流行的技術,很多公司都在生產環境中使用,但是docker依賴的底層技術實際上很早就已經出現了,現在以docker的形式重新煥發活力,並且能很好的解決面臨的問題,希望本文能對大家理解docker有所幫助。