容器技術的發展歷程悠久,從早期的作業系統層級隔離機制演變而來,如今已成為雲原生應用佈署的根本。容器的輕量級特性及與微服務架構的契合度,使其成為現代軟體開發不可或缺的技術。尤其在 Kubernetes 的普及下,容器協調更簡化了複雜應用程式的佈署和管理。不同容器引擎的選擇,例如 Docker 和 Podman,也影響著開發流程和系統架構。理解容器技術的演進和不同引擎的特性,有助於開發者選擇最適合自身需求的解決方案,並有效提升應用程式開發和佈署效率。

為什麼需要容器?

容器作為一種智慧且易用的應用程式封裝解決方案,能夠滿足開發者建立自洽的套件的需求,將所有必要的二進位檔案和組態封裝在一起,以確保工作負載能夠無縫執行。作為一種自洽的隔離行程和保證名稱空間及資源使用分離的方法,容器受到維運團隊的青睞,因為他們不再需要維護複雜的依賴關係約束,也不需要將每個應用程式隔離在虛擬機器中。

從這個角度來看,容器可以被視為DevOps最佳實踐的促進者,開發者和維運人員可以更密切地合作,以佈署和管理應用程式,而不需要僵化的分離。

容器與DevOps

開發者如果想要建立自己的容器映像檔,需要更加了解映像檔中內建的作業系統層,並與維運團隊密切合作,以定義建置範本和自動化流程。

雲端就緒

容器是為雲端而設計的,採用不可變性的思維方式。不可變性模式明確規定,對基礎設施(無論是單個容器還是複雜叢集)的更改必須透過重新佈署修改版本來實作,而不是修補當前版本。這有助於提高系統的可預測性和可靠性。

雲端佈署流程

當需要推出新的應用程式版本時,會將其建置到新的映像檔中,並佈署新的容器以取代先前的版本。可以實施建置流程管線來管理複雜的工作流程,從應用程式建置、映像檔建立、映像檔登入推播和標記,直到佈署到目標主機。這種方法大大縮短了資源組態時間,同時減少了不一致性。

未來的章節將介紹專門的容器協調解決方案,如Kubernetes,它們也提供了自動化大量主機排程模式的方法,使容器化的工作負載易於佈署、監控和擴充套件。

基礎設施最佳化

與虛擬機器相比,容器的輕量級足跡大大提高了計算和記憶體資源的使用效率。透過簡化工 作負載執行的途徑,採用容器技術能夠帶來巨大的成本文省。

資源最佳化實踐

透過減少應用程式的計算成本,可以實作IT資源的最佳化;如果原本執行在虛擬機器上的應用程式伺服器可以被容器化,並與其他容器一起在主機上執行(具有專門的資源限制和請求),則可以節省和重複使用計算資源。

整個基礎設施都可以根據這一新正規化進行重新調整;之前組態為虛擬機器管理程式的裸機可以重新分配為容器協調系統的工作節點,只需執行更細粒度的容器化應用程式即可。

微服務架構

微服務架構將應用程式拆分為多個服務,每個服務執行細粒度的功能,並且是應用程式整體的一部分。

微服務與容器

傳統應用程式採用單體式方法,所有功能都是同一個例項的一部分。微服務的目的在於將單體式應用程式分解為更小的部分,這些部分可以獨立互動。

單體式應用程式可以很好地適應容器,但微服務應用程式與容器的匹配更為理想。

為每個微服務提供一個容器有助於實作重要的好處,例如:

  • 微服務的獨立擴充套件性
  • 開發團隊雲端存取計畫的更明確責任劃分
  • 不同微服務可能採用不同的技術堆積疊
  • 對安全性方面有更強的控制力(例如公開面對的暴露服務、mTLS連線等)

然而,在處理大型且複雜的架構時,協調微服務可能是一項艱鉅的任務。採用Kubernetes等協調平台、Istio或Linkerd等服務網格解決方案,以及Jaeger和Kiali等追蹤工具,對於控制複雜性至關重要。

容器的由來

容器技術並不是電腦行業中的新話題,其根源於作業系統歷史。我們將回顧Unix到GNU/Linux機器的作業系統歷史中最重要的里程碑,以瞭解其底層思想如何隨著時間演變。

chroot與Unix V7

我們的容器歷史之旅的第一站是1979年,當時Unix V7引入了一個重要的系統呼叫——chroot系統呼叫。

chroot的作用

這個系統呼叫允許應用程式更改其自身和子行程的根目錄,移除執行中的軟體逃離該「監獄」的任何能力。這一功能使得禁止執行中的應用程式存取給定子樹以外的任何檔案或目錄成為可能,這在當時是一個重大的突破。

儘管chroot是在1979年引入的,但它並不是為了安全性而設計的。隨著時間的推移,作業系統檔案和安全文獻強烈建議不要將chroot jail作為實作隔離的安全機制。

FreeBSD jail

在我們的歷史之旅中,下一個重要的里程碑是2000年,當時FreeBSD作業系統批准並發布了一個新的概念——FreeBSD jail,它擴充套件了舊有的chroot系統呼叫的功能。

FreeBSD jail的特點

FreeBSD jail的主要特點包括:

  • 目錄子樹:這與chroot jail類別似,執行中的行程被限制在該子樹中,無法逃脫。
  • IP位址:可以為jail定義獨立的IP位址,使其與主機系統隔離。
  • 主機名稱:在jail內部使用,與主機系統不同。
  • 命令:要在jail內部執行的命令,具有相對路徑,該路徑是jail內部的自包含路徑。

每個FreeBSD jail例項都有自己的使用者和root帳戶,且對其他jail或底層主機系統沒有任何許可權或許可許可權。

Solaris Containers(又稱Solaris Zones)

我們的時間機器再向前推進幾年,到2004年,我們遇到了第一個可識別的名稱——Solaris Containers。

Solaris Containers簡介

Solaris是一個由Sun Microsystems開發的專有Unix作業系統,誕生於1993年,原本根據SunOS。

此圖示說明瞭容器技術從chroot到現代容器技術的發展過程。

內容解密:

此圖表展示了容器技術的發展歷程,從早期的chroot系統呼叫,到後來的FreeBSD jail,再到Solaris Containers,最終演變為現代的容器技術。每一步都代表著對前一步的改進和擴充套件,使容器技術變得越來越成熟和完善。

容器技術的演進與發展

容器技術的概念最早源自於 Solaris Zones,一種內建於 Solaris 作業系統的虛擬化技術。這項技術透過特殊的檔案系統 ZFS 實作儲存快照和克隆的功能。Solaris Zones 提供了一個虛擬化的應用環境,能夠與主機系統和其他區域中的應用程式完全隔離。其中一個重要的創新是「品牌區域」(branded zone)的概念,允許在與底層作業系統不同的環境中執行不同的二進位檔案、工具包,甚至是不同的作業系統。

Solaris Zones 的特性

  • 虛擬化的應用環境
  • 與主機系統和其他區域完全隔離
  • 支援品牌區域,提供不同的執行環境
  • 可自定義網路、使用者和時區

Linux 容器(LXC)的崛起

2008 年,Linux 容器(LXC)問世,成為 Linux 平台上第一個完整的容器管理解決方案。LXC 的開發者不僅實作了容器管理功能,還為 Linux 核心貢獻了許多關鍵特性,這些特性後來被其他容器執行環境廣泛採用。LXC 利用 Linux 核心的多項功能來實作與虛擬機器(VM)相似的隔離效果,但避免了模擬硬體和執行全新核心例項所帶來的開銷。

LXC 的核心功能

  • 名稱空間(Namespaces):隔離行程對系統資源的存取。
  • 強制存取控制(Mandatory Access Control, MAC):如 SELinux,提供根據角色的存取控制和多層次安全機制。
  • 控制群組(Control Groups, cgroups):用於組織和限制行程資源的使用。

LXC 的一大創新是支援無特權容器(unprivileged containers),透過名稱空間、MAC 和 cgroups 的結合,實作了 UID 和 GID 的對映,確保容器內的許可權與主機系統隔離。

Docker 的出現與影響

2013 年,Docker 進入容器領域,並迅速獲得廣泛關注。Docker 最初使用 LXC 作為其容器引擎,但很快開發了自己的 libcontainer,並替換了 LXC。Docker 繼承了 LXC 的核心概念,並引入了容器映像檔和容器登入機制,極大地促進了容器技術的普及。

Docker 的關鍵特性

  • OverlayFS:一種聯合檔案系統,能夠將多個檔案系統合併為一個。
  • 容器映像檔和登入機制:允許開發者和系統管理員共用和重用容器映像檔。
  • Dockerfile:自動化構建容器映像檔的工具。

rkt 與 OCI 規範的誕生

2014 年至 2015 年間,CoreOS 公司推出了 rkt,一種無守護程式(daemon-less)的容器引擎。rkt 的設計理念對後來的容器技術產生了重要影響。與此同時,Docker 將其核心執行環境 containerd 捐贈給了雲原生計算基金會(CNCF),推動了容器技術社群的發展。

2015 年,多家公司共同發起開放容器倡議(OCI),旨在制定容器執行環境和映像檔的標準規範。OCI 釋出了 runc,一種符合 OCI 規範的容器執行環境。

OCI 規範的重要性

  • 標準化容器技術:為容器引擎的開發提供了統一的標準。
  • 促進容器生態系統的發展:使得 Kubernetes 等容器協調工具得以更好地整合和發展。

為何需要容器?

開放容器倡議(OCI)不僅定義了執行獨立容器的規範,還為將Kubernetes層與底層容器引擎更輕鬆地連線提供了基礎。同時,Kubernetes社群發布了容器執行時介面(CRI),這是一個外掛介面,用於支援採用多種容器執行時。

CRI-O正是在此背景下誕生的。2017年,Red Hat將CRI-O作為開源專案發布,它是Kubernetes容器執行時介面的首批實作之一,支援使用符合OCI規範的執行時。CRI-O代表了一種輕量級的替代方案,用於取代Docker、rkt或其他引擎作為Kubernetes的執行時。

隨著生態系統的不斷發展,標準和規範得到了越來越廣泛的採用,從而推動了容器生態系統的擴充套件。先前提到的OCI規範對於runc容器執行時的發展至關重要,而runc被Podman專案所採用。

Podman

我們終於來到了時間旅行的盡頭;在前一段中,我們抵達了2017年,而同年,Podman專案在GitHub上進行了首次提交。

該專案的名稱揭示了它的用途——PODMAN = POD管理器。現在,我們準備好來看看容器世界中Pod的基本定義。

Pod是Kubernetes可以處理的最小可佈署計算單元;它可以由一個或多個容器組成。在同一Pod中包含多個容器的情況下,它們會在共用的上下文中被排程和執行。

Podman的功能

Podman管理容器和容器的映像、它們的儲存卷,以及由一個或多個容器組成的Pod,並且從一開始就被設計為遵循OCI標準。

與其前身rkt一樣,Podman沒有中央守護程式來管理容器,而是將它們作為標準系統程式啟動。它還定義了與Docker相容的CLI介面,以簡化從Docker的過渡。

Podman引入的最重要的功能之一是無根容器。通常,當我們想到Linux容器時,我們會立即想到需要系統管理員在作業系統層級進行一些準備,以建立讓我們的容器得以執行和執行的環境。

無根容器可以輕鬆地以普通使用者身份執行,而無需root許可權。使用非特權使用者執行Podman將啟動受限的容器,而不會擁有任何特權,就像執行它的使用者一樣。

毫無疑問,Podman引入了更大的靈活性,是一個非常活躍的專案,其採用率不斷增長。每個主要版本都會帶來許多新功能;例如,3.0版本引入了對Docker Compose的支援,這是一個備受期待的功能。這也反映了社群支援的良好健康指標。

容器的應用場景

本章最後將對最常見的容器採用案例進行綜述。

這是一個開放性的章節,旨在闡述在生產環境中,容器目前的使用情況。本章還將介紹容器協調的概念,以及Kubernetes——目前最被廣泛使用的開源協調解決方案,已被全球數千家公司採用。容器的採用正在各行各業的企業中迅速普及。

如果我們深入研究已經使用容器或Kubernetes發行版的公司的成功案例,我們會發現,容器化和容器協調正在加速專案開發和交付的速度,並加快在各類別行業(從汽車到醫療保健)中建立新的應用場景。無論從經濟角度還是技術角度來看,這對電腦技術的發展都產生了巨大的影響。

公司正在將新的應用程式從舊有的虛擬機器佈署模型轉向容器模型。正如我們在前面的段落中簡要介紹的那樣,容器可以輕鬆地被視為封裝應用程式的新方式。

回顧虛擬機器的歷史,它們的主要目的是什麼?它們是為了為目標應用程式創造一個隔離的環境,並為其保留一定的資源。

隨著容器的出現,企業意識到,透過引入某種創新,他們可以更好地最佳化基礎設施,加快新服務的開發和佈署。

回顧容器的採用歷史和它們的使用方式,我們可以看到,在剛開始時,它們被用作封裝傳統單體應用程式執行時的方法。但是,隨著雲原生浪潮的興起,以及諸如微服務等概念的流行,容器成為了封裝下一代雲原生應用程式的事實上的標準。

重要筆記

雲原生運算是一種軟體開發實踐,用於在公有、私有或混合雲中構建和佈署可擴充套件的應用程式。

微服務架構是一種建立根據鬆散耦合、細粒度服務的應用程式的做法,使用輕量級協定。

根據我們與採用容器的客戶合作的日常經驗,我們可以確認,客戶最初只將標準應用程式封裝到容器中,並使用容器協調器(如Kubernetes)進行協調。但是,一旦新的開發模型到來,開發人員團隊開始使用容器及其協調器來管理這種新型服務,並且這種趨勢越來越明顯。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 容器技術綜觀與PodmanDocker比較

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

此圖示展示了從傳統虛擬機器到容器化,再到微服務架構,最終由Kubernetes進行協調的演變過程。

內容解密:

此Plantuml圖表描述了技術發展的流程。首先,從傳統虛擬機器開始,接著轉變為更現代化的容器化技術。隨後,這些容器進一步發展成支援微服務架構的形式。最後,這些根據微服務的容器由Kubernetes進行高效協調和管理。這種演變體現了軟體開發和佈署技術的不斷進步和最佳化。

容器技術簡介與Podman和Docker的比較

容器技術的背景與優勢

在微服務架構的背景下,容器技術提供了一種輕量級、隔離的應用程式執行環境。透過容器,每個微服務可以擁有自己的基礎映像檔(base image),包含所需的執行環境,從而實作開發與佈署的獨立性。此外,容器技術也促進了持續整合與持續交付/佈署(CI/CD)的實踐,自動化了應用程式的開發、測試和佈署流程。

容器技術的演進使得原本孤立的開發(Dev)和維運(Ops)團隊能夠更緊密地協作,推動了DevOps實踐的採用。容器不僅適用於微服務架構,也能夠支援傳統的單體式應用程式。隨著容器技術的發展,基礎映像檔的大小和內容不斷最佳化,以適應複雜應用程式的需求。

容器技術的歷史與現狀

容器技術並非新興概念,其根源可追溯至1979年。經過多年的發展,容器技術已成為現代軟體開發和佈署的重要組成部分。企業公司中,容器技術被廣泛採用,不僅用於微服務架構,也用於傳統的單體式應用程式。

Podman與Docker的比較

在容器引擎領域,Docker曾經獨領風騷。然而,隨著Podman的出現,開發者有了新的選擇。Podman是一種無守護程式(daemon-less)的容器引擎,其架構與Docker有所不同。本章將探討Docker和Podman的主要差異,包括其架構、使用者經驗等方面。

Docker容器守護程式架構

Docker容器引擎在2013年出現後迅速流行起來。Docker使用守護程式來管理容器的生命週期,並依賴於底層的容器執行時(container runtime)來執行容器。在早期的版本中,Docker使用LXC作為容器執行時,後來則被替換為自己的實作——libcontainer。

Podman無守護程式架構

與Docker不同,Podman採用無守護程式架構,這意味著它不需要一個常駐的守護程式來管理容器的執行。這種設計使得Podman在安全性和資源利用率方面具有一定的優勢。

主要差異與技術需求

本章將探討Docker和Podman的主要差異,包括其架構設計、使用者經驗等方面。讀者可以根據自己的需求選擇合適的容器引擎,無需擔心技術門檻。本章不要求讀者具備特定的技術背景,但若希望實踐本章中的範例,則需要安裝和組態Podman和Docker。

程式碼解析:

# 檢視目前系統中的容器映像檔
podman images

內容解密:

此指令用於列出目前系統中已下載或建立的容器映像檔。透過podman images,使用者可以檢視映像檔的ID、倉函式庫名稱、標籤和大小等資訊。

# 從Docker Hub下載Ubuntu映像檔
podman pull ubuntu:latest

內容解密:

此指令從Docker Hub下載最新的Ubuntu映像檔至本地系統。podman pull指令用於取得遠端倉函式庫中的映像檔,並將其儲存在本地。

進一步閱讀

若希望深入瞭解本章所涉及的主題,可以參考以下資源: