在聊容器之前,我們先聊聊以前的服務部署。我們部署服務都是直接部署在硬件服務器上,擴容就需要購買服務器,然後進行應用部署,以及各種環境和服務配置。這些流程相當繁瑣,並且都是人工操作,不僅浪費時間還很費程序“猿”,因此服務部署以及遷移效率都極其低下。
在早期,用戶數以及業務體量還不是很大,人工操作還能夠應付得過來。而隨着業務規模的不斷髮展、用戶數的爆炸式增長,這樣的軟件服務生產方式已經無法滿足業務高速發展的需求。它主要有以下三個問題:
服務互干擾
一臺服務器一般不會只部署一個服務應用,大多部署了多個服務應用。但是由於這些服務都是公用服務器中的 CPU、內存、硬盤以及網絡 IO 等服務器資源,必定會存在資源互相爭用、服務互相影響的情況。
資源利用低
業務是存在高峯期和低谷期的。就電商平臺來說,一般深夜屬於業務低谷期,服務器的資源利用率相比業務高峯期的時候要低很多。因此在業務低谷期,實際服務器的資源利用率比較低,不能物盡其用。
遷移擴展難
原有的服務器數量不足以應對高速發展的業務時,就需要不斷的進行服務器實例擴充,但是由於服務直接部署在服務器中,在進行服務遷移擴展的時候,需要各種依賴庫、環境配置以及網絡配置等,步驟複雜,擴展困難。
什麼是容器
容器(Container)是一種更輕量級,更靈活的虛擬化處理方式,它將一個應用程序所需的一切打包在一起。容器包括所有代碼,各種依賴甚至操作系統,這讓應用程序幾乎在任何地方都可以運行。因此它的誕生,解決了一個重要問題:如何確保應用程序從一個環境移動到另一個環境的正確運行。它只是虛擬了操作系統,而不像虛擬機一樣去虛擬底層計算機。下面我們來詳細瞭解下容器技術的原理。
隔離與共享
在一個多員共用的開發環境或者一臺服務器運行多個邏輯隔離的服務器進程。誰的運行環境也不希望影響到另一個誰。也就是一個物理機器需要虛擬化出多個環境或者容器。通過提供一種創建和進入容器的方式,操作系統讓應用程序就像在獨立的機器上運行一樣,但又能共享很多底層的資源。
虛擬化 VS 容器
傳統的虛擬化技術是通過硬件模擬或者操作系統軟件實現,而容器技術可以比傳統虛擬化更輕量級。
容器在提供隔離的同時,還通過共享這些資源節省開銷,這意味着容器比真正的虛擬化的開銷要小得多。例如,可以有效地共享公共文件(比如 glibc)的頁緩存,因爲所有容器都使用相同的內核,而且所有容器還常常共享相同的 libc 庫(取決於容器配置)。這種共享常常可以擴展到目錄中其他不需要寫入內容的文件。
和傳統虛擬化相比,容器啓動很快。由於共享系統資源,一臺主機可以運行上千個容器,並且容器鏡像用類似 git 分發思想,用戶更容易創建,分發,更新存儲這些鏡像。
容器的前世今生
容器的今生是 docker 大流行的時代,而它的前世是早於 1982 年的 chroot 工具,以及後面經過改進並且現在還在使用的 lxc 技術。早期 docker 的代碼實現基於 LXC(0.9之前)。
Linux 容器功能是基於 cgroups 和 Namespace 來實現的,所以要了解 Linux 容器必須先了解 cgroup 和 Namespace。
Namespace
Namespace 是 Linux 用來隔離內核資源的方式。通過 namespace 可以讓一些進程只看到與自己相關的資源,而另外一些進程也只能看到與它們自己相關的資源,這兩撥進程感覺不到對方的存在。具體的實現方式是把一個或多個進程的相關資源指定在同一個 namespace 中。
Linux namespaces 是對全局系統資源的一種封裝隔離,使得處於不同 namespace 的進程擁有獨立的全局系統資源,改變一個 namespace 中的系統資源只會影響當前 namespace 裏的進程,對其他 namespace 中的進程沒有影響。
可能絕大多數的使用者和我一樣,是在使用 docker 後纔開始瞭解 linux 的 namespace 技術的。Linux 內核實現 namespace 的其中一個目的,就是爲了實現輕量級虛擬化(容器)服務。在同一個 namespace 下的進程可以感知彼此變化,而對外界進程一無所知。這樣就可以讓容器中的進程產生錯覺,認爲自己置身於一個獨立系統中,從而達到隔離的目的。可以說,Linux 內核提供的 namespace 技術爲 docker 等容器技術的出現和發展提供了基礎條件。
如何從 docker 實現者的角度出發,去實現一個資源隔離的容器呢?
- IPC:隔離 System V IPC 和 POSIX 消息隊列
- Network:隔離網絡資源。
- Mount:隔離文件系統掛載點。
- PID:隔離進程ID。
- UTS:隔離主機名和域名。
- User:隔離用戶ID和組ID。
以上這六種隔離能力是實現一個容器的基礎,而 linux 內核的 namespace 特性也爲我們提供了 IPC、Network、Mount、PID、User、UTS、Cgroup 等隔離能力。下面重點來聊聊 Cgroups。
Cgroups
Cgroups(Control Groups) 是 linux 內核提供的一種機制,這種機制可以根據需求,把一系列系統任務及其子任務整合(或分隔)到按資源劃分等級的不同組內,從而爲系統資源管理提供一個統一的框架。簡單來說,cgroups 可以限制、記錄任務組所使用的物理資源。本質上來說,cgroups 是內核附加在程序上的一系列鉤子(hook),通過程序運行時對資源的調度,觸發相應的鉤子以達到資源追蹤和限制的目的。
爲什麼要使用 Cgroups?
其可以做到對 cpu、內存等資源實現精細化的控制,目前越來越火的輕量級容器 Docker 及 k8s 中的 pod 就使用了 cgroups 提供的資源限制能力來完成 cpu、內存等部分的資源控制。
舉個例子,在一個既部署了前端 web 服務,也部署了後端計算模塊的八核服務器上,可以使用 cgroups 限制 web server 僅可以使用其中的六個核,把剩下的兩個核留給後端計算模塊。
Cgroups 的主要作用
實現 cgroups 的主要目的,是爲不同用戶層面的資源管理提供一個統一化的接口。從單個任務的資源控制到操作系統層面的虛擬化,cgroups 提供了四大功能:
- 資源限制:cgroups 可以對任務的資源總額進行限制。比如設定任務運行時使用的內存上限,一旦超出就發 OOM。
- 優先級分配:通過分配的 CPU 時間片數量和磁盤 IO 帶寬,實際上就等同於控制了任務運行的優先級。
- 資源統計:cgoups 可以統計系統的資源使用量,比如 CPU 使用時長、內存用量等。這個功能非常適合當前雲端產品按使用量計費的方式。
- 任務控制:cgroups 可以對任務執行掛起、恢復等操作。
Cgroups相關概念及其關係
相關概念
- 任務(task):在cgroups中,任務就是系統的一個進程。
- 控制族羣(control group):控制族羣就是一組按照某種標準劃分的進程。Cgroups中的資源控制都是以控制族羣爲單位實現。一個進程可以加入到某個控制族羣,也從一個進程組遷移到另一個控制族羣。一個進程組的進程可以使用 cgroups 以控制族羣爲單位分配的資源,同時受到 cgroups 以控制族羣爲單位設定的限制。
- 層級(hierarchy):控制族羣可以組織成 hierarchical 的形式,既一顆控制族羣樹。控制族羣樹上的子節點控制族羣是父節點控制族羣的孩子,繼承父控制族羣的特定的屬性。
- 子系統(subsytem):一個子系統就是一個資源控制器,比如 cpu 子系統就是控制 cpu 時間分配的一個控制器。子系統必須附加(attach)到一個層級上才能起作用,一個子系統附加到某個層級以後,這個層級上的所有控制族羣都受到這個子系統的控制。
相互關係
- 每次在系統中創建新層級時,該系統中的所有任務都是那個層級的默認 cgroup(我們稱之爲 root cgroup,此 cgroup 在創建層級時自動創建,後面在該層級中創建的cgroup都是此cgroup的後代)的初始成員。
- 一個子系統最多隻能附加到一個層級。
- 一個層級可以附加多個子系統
- 一個任務可以是多個 cgroup 的成員,但是這些 cgroup 必須在不同的層級。
- 系統中的進程(任務)創建子進程(任務)時,該子任務自動成爲其父進程所在 cgroup 的成員。然後可根據需要將該子任務移動到不同的 cgroup 中,但開始時它總是繼承其父任務的 cgroup。
容器的應用場景
容器技術的誕生其實主要解決了 PAAS 層的技術實現,像 OpenStack、Cloudstack 這樣的技術是解決 IAAS 層的問題。那麼容器技術主要應用在哪些場景呢?目前主流的有以下幾種:
- 容器化傳統應用
容器不僅能提高現有應用的安全性和可移植性,還能節約成本。每個企業的環境中都有一套較舊的應用來服務於客戶或自動執行業務流程。即使是大規模的單體應用,通過容器隔離的增強安全性、以及可移植性特點,也能從 Docker 中獲益,從而降低成本。一旦容器化之後,這些應用可以擴展額外的服務或者轉變到微服務架構之上。
- 持續集成和持續部署 (CI/CD)
通過 Docker 加速應用管道自動化和應用部署,交付速度提高至少 13 倍。現代化開發流程快速、持續且具備自動執行能力,最終目標是開發出更加可靠的軟件。通過持續集成 (CI) 和持續部署 (CD),每次開發人員簽入代碼並順利測試之後,IT 團隊都能夠集成新代碼。作爲開發運維方法的基礎,CI/CD 創造了一種實時反饋迴路機制,持續地傳輸小型迭代更改,從而加速更改,提高質量。CI 環境通常是完全自動化的,通過 git 推送命令觸發測試,測試成功時自動構建新鏡像,然後推送到 Docker 鏡像庫。通過後續的自動化和腳本,可以將新鏡像的容器部署到預演環境,從而進行進一步測試。
- 微服務
應用架構正在從採用瀑布模型開發法的單體代碼庫轉變爲獨立開發和部署的松耦合服務。成千上萬個這樣的服務相互連接就形成了應用。Docker 允許開發人員選擇最適合於每種服務的工具或技術棧,隔離服務以消除任何潛在的衝突,從而避免“地獄式的矩陣依賴”。這些容器可以獨立於應用的其他服務組件,輕鬆地共享、部署、更新和瞬間擴展。Docker 的端到端安全功能讓團隊能夠構建和運行最低權限的微服務模型,服務所需的資源(其他應用、涉密信息、計算資源等)會適時被創建並被訪問。
- IT 基礎設施優化
Docker 和容器有助於優化 IT 基礎設施的利用率和成本。優化不僅僅是指削減成本,還能確保在適當的時間有效地使用適當的資源。容器是一種輕量級的打包和隔離應用工作負載的方法,所以 Docker 允許在同一物理或虛擬服務器上毫不衝突地運行多項工作負載。企業可以整合數據中心,將併購而來的IT資源進行整合,從而獲得向雲端的可遷移性,同時減少操作系統和服務器的維護工作。
作爲雲原生髮展的基石,容器技術的新趨勢和新挑戰備受關注,以容器爲代表的雲原生技術正在成爲釋放雲價值的最短路徑。