今天Docker容器技術已經很是普及了,其中容器是一種基礎工具,泛指任何能夠用於容納其它物品的工具,能夠部分或徹底封閉,被用於容納、存儲、運輸物品;物體能夠被放置在容器中,而容器則能夠保護內容物,人類使用容器的歷史至少有十萬年,甚至可能有數百萬年的歷史。
(1)虛擬化技術類型
咱們在虛擬化的技術當中,目前虛擬化的常見形式有兩種。第一種咱們稱之爲主機級虛擬化,虛擬的是整個完整的硬件平臺,例如咱們經常使用的VMware Workstation就可讓咱們自由的在平臺上安裝操做系統,安裝的操做系統甚至和咱們底層的宿主機能夠是不一樣的操做系統。其中主機級虛擬化有兩種實現形式,Type-I型的虛擬化技術是直接在硬件平臺上裝一個Hyper Banner,在硬件之上不用再安裝宿主機操做系統,而在Hyper Banner之上直接安裝虛擬機,也就意味着沒有操做系統直接跑在硬件之上,全部操做系統都是在虛擬機內部;針對Type-II型的虛擬化首先咱們會有宿主機,在宿主機設備上會安裝主機操做系統,在宿主機之上會安裝VMM即虛擬機管理器,在軟件之上會建立一個個的虛擬機。
對於主機級虛擬化,咱們發現若是一個進程須要調度,首先它須要虛擬機之上的內核進行調度、磁盤IO管理等,虛擬機自己也是被宿主機內核管理的抽象層而已,所以咱們運行的進程還會被宿主機的Hyper Banner管理一次,這中間資源的額外開銷也就不言而喻了,所以傳統的主機虛擬化技術的確可以讓一組硬件環境在跨系統環境的資源隔離、調試等能夠高效應用,可是對咱們資源的消耗也是不容忽視的。
第二種咱們稱之爲容器級虛擬化,首先咱們有一個硬件平臺,在硬件平臺之上咱們有一層虛擬的隔離環境管理器,在上面建立一個用戶空間的隔離環境,而咱們指望將用戶空間隔離成多組互相不干擾,且一個用戶空間內只運行一個或部分進程的狀態。通常來講第一個用戶空間是有特權的能夠經過它來管理其餘的用戶空間。雖然在衆多的用戶空間都是公用底層同一個內核,可是在本身運行時所可以看到的邊界只是本身所屬用戶空間的邊界,這樣彼此間也就實現了隔離,可是你們須要明白這樣的隔離遠沒有主機級虛擬化那樣隔離的完全。咱們發現隔離出來的用戶空間拿來放進程,給進程提供運行環境,而且還可以保護內部的進程不受其餘進程的干擾,這就是咱們所熟知的容器。
(2)chroot
容器技術並非新概念,最先是出如今FreeBSD系統中,當年在系統中名爲jail(監獄),做用是不受其餘進程的干擾,而且能夠提供一個沙箱環境,讓進程在其中運行,就算進程出現Bug或故障,也不會影響到本身所屬容器外圍的進程,這樣能夠給咱們帶來一個安全的運行環境。後來人們把這樣的技術復刻到Linux平臺上,這個產品名爲vserver,能夠實現和jail一樣的效果,而實現vserver功能的核心技術就是咱們熟知的chroot。
(3)namespaces
對於容器級虛擬化技術,表面上看是使用了chroot,但背後是一堆技術的支撐,一個單獨的用戶空間,它的主要目標是進行用戶隔離環境的,然後任何進程運行在用戶空間當中會覺得本身是惟一運行在當前內核之上用戶空間中的進程,並且本身所能看到的進程也都是當前系統之上的全部進程,一個用戶空間應該包含如下組件:主機名和域名,根文件系統,每一個用戶空間本身獨有的IPC等,各個用戶空間進程數本身的PID號,被隔離的用戶和組,以及每一個用戶空間本身的Network網絡。到今天爲止Linux內核級已經對這6種須要被隔離的資源已經經過名稱空間namespaces的機制原生支持。因此到今天爲止Linux領域的容器化技術就是靠6個內核級的namespaces和chroot來實現的。
(4)Control Groups(cgroups)
名稱空間是工做在同一組內核之上的,若是裏面有的進程出現了異常而致使內存泄露,不斷吞噬內存,最終內存所有被吃掉;一樣CPU資源也由於這個異常進程而致使其餘進程沒法獲得CPU資源,CPU屬於可壓縮型資源,若是其餘進程沒法獲得資源那麼就會一直掛在那裏等待,可是內存屬於非可壓縮型資源,申請就必須得有,沒有就會出現OOM內存溢出的異常。因此內核級必須實現功能來限制每個用戶空間的進程全部可用資源總量,第一種方式例如咱們能夠按CPU來進行分配,一共有3個用戶空間,咱們指定CPU的比例是1:2:1,這樣分配後,若是2和3號不用,那麼1號若是須要大量計算能夠吃掉整個CPU的計算量,若是2和3號都會使用,那麼它們就會按照比例分配,確保CPU按照25%,50%,25%的百分比分配資源;第二種方式是能夠限制一個用戶空間的進程在整個系統資源如32核CPU中,最多使用2核CPU。這種功能必需要在內核上對每一個名稱空間來實現,而這個功能在內核級靠的是Control Groups即cgroups的機制來實現的。
對cgroups來講就是把系統資源分紅多個組,把每一個組內的資源量指派到特定的用戶空間的進程上去(圖1-4)。容器級的虛擬化因爲使用的是同一個內核,在內核級強行設置了邊界,而主機級虛擬化自己使用的就不是同一個內核,內核就是自然隔離的平臺,因此容器級的虛擬化的隔離性遠不如主機級虛擬化隔離性那麼好,所以爲了增強隔離性防止用戶空間的進程繞過漏洞去劫持其餘用戶空間中的資源,全部後來經過SELinux等安全機制來增強系統的安全性,因此咱們爲了可以支撐容器技術更加完善,因此咱們在使用容器技術的時候一樣要啓用SELinux功能
(5)LXC
爲了使容器技術更加易用,把使用容器技術的功能作成一組工具能夠極大的簡化用戶的使用難度,因此就有了LXC的解決方案,LXC即LinuX Container。LXC是最先使用一組簡易使用的工具和模板來極大的簡化容器技術使用的方案,咱們可使用lxc-create來快速建立用戶空間,建立完用戶空間後還須要裝上基本的應用程序,此時須要基於template模板腳本,指向一個安裝過程,這個安裝過程包含了你所打算建立的系統發行版所屬的倉庫,從倉庫中把各個程序包下載下來並安裝,生成這個名稱空間,這個名稱空間的使用效果就相似於虛擬機或者KVM同樣。雖然LXC極大的簡化了容器技術的使用,使得系統的資源開銷極大的下降,可是在容器分發、遷移、快速建立等大規模使用的場景中和傳統的虛擬機相比,複雜程度並無下降,且隔離用戶空間的安全性也並非那麼完善。
(6)Docker
因而在這樣的背景下就出現了docker,它是LXC的加強版,是容器技術的前端易用工具,容器是Linux內核當中的技術,而docker則是將容器技術得以普及的一個工具。Docker在早期使用的是LXC做爲容器管理引擎,可是在建立用戶空間時不是用template來現場安裝,而是使用了鏡像技術,相似於把一個操做系統打包成一個鏡像,而後把這個鏡像文件下載下來,建立成一個虛擬機,而後基於這個虛擬機來啓動,Docker就是使用相似這樣的方式來操做。在互聯網中有一個專門的倉庫,倉庫中有已經打包好的最小化的CentOS操做系統,最小化的CentOS+Nginx的鏡像等,後續使用docker啓動容器,運行容器時,它會自動連到服務器上下載一個匹配你所要建立的容器的鏡像,把鏡像拖到本地,並基於鏡像啓動容器。因此docker極大的簡化了容器的使用難度,你所用到的大多數的鏡像均可以在docker倉庫中找到。
爲了使容器更加易於管理,docker規定在一個用戶空間中只運行一個進程,即nginx在nginx的容器中,Tomcat在Tomcat的容器中,兩者使用容器間的通訊邏輯進行通訊。如此一來使用的調試工具等須要在每一個容器中都存放一份,好處是若是刪除了容器自身中的文件並不會影響其餘容器的,壞處是所須要使用的空間更大了,每一個容器中所使用的調試工具都須要準備一份,且使用進程查看命令如ps、top等時須要突破各個容器的邊界才能夠查看。
docker在鏡像的構建底層使用的是所謂分層構建,聯合掛載的機制來實現的。咱們首先建立一個純淨版的CentOS的鏡像,隨後基於這個CentOS鏡像之上構建一個nginx鏡像,且這個鏡像只包含nginx鏡像自己,一個功能只在一層上構建並實現,而後把它們疊在一塊兒造成一個統一的視圖,這樣的好處是之後咱們的鏡像分發沒有那麼龐大了。好比咱們在一個系統上須要運行3個容器:nginx、tomcat、MySQL都是基於底層CentOS構建的,當咱們須要運行nginx鏡像時,咱們把nginx和CentOS進行聯合掛載,同時每一層鏡像都是隻讀的,當咱們須要運行2個nginx服務的時候,使用同一個CentOS鏡像和同一個nginx鏡像,而後都經過聯合掛載的方式建立2個容器,並在每一層聯合掛載的鏡像棧的最頂層額外添加一個新層,這個層可讀可寫,且是容器自身專有的層,這樣就實現了容器運行的環境。可是若是咱們但願將容器遷移到其餘宿主機的環境中去,在可讀可寫層是寫有數據的,所以如今生產環境真正使用容器時並不會在容器本地保存有效數據,咱們會在文件系統的外部掛載一個共享的持久存儲,如iSCSI,Ceph等,這樣若是出現MySQL容器運行故障或者出現宕機也沒有關係,咱們在一個新的主機上從新啓動一個MySQL容器,而後把持久存儲的數據掛載過來,繼續使用就能夠了(圖1-6)。這樣一來,咱們就能夠把一個容器當作一個進程來使用,啓動一個容器就是爲了運行一個進程,進程一終止,把對應的容器刪除便可,這樣容器就像進程同樣有了生命週期,並且容器運行的環境和咱們的宿主機也沒有密切關聯了,能夠運行在任意一臺宿主機上。
(7)容器編排工具
當咱們有多個容器須要運行的時候,咱們須要一個在docker基礎之上可以把這種應用程序之間的依賴關係,從屬關係、反映在啓動關閉時的次序和管理邏輯之中,這種功能就是容器編排。Docker出現以後迅速出現了不少的容器編排工具,docker公司本身的machine+swarm+compose的工具組合,其中compose是單機編排,swarm是將多個主機做爲一個總體進行編排;另外一個是ASF的,ASF有一個著名的數據中心操做系統mesos,這不是專門編排容器的,它是實現統一資源調度和分配的,若是咱們想實現統一編排容器還須要加一箇中間層marathon;第三個就是谷歌公司推廣的kubernetes(k8s),k8s是由谷歌公司本身公司運行了十幾年的博格系統經驗改編而來,谷歌公司主導成立了CNCF基金會,這個基金會是有不少組織和公司共同組成的公共組織,是由微軟、谷歌、IBM、Redhat等公司組成的容器標準委員會,使得kubernetes已經成爲了事實上的容器編排工具的主流。
Docker公司的容器引擎經歷了由最初的LXC再到libcontainer引擎的過程,可是CNCF基金會要求Docker公司建立一個容器引擎的標準,並把它開源出來,因此目前最新的容器引擎名爲runC,這也是目前容器運行時的環境標準。前端