再見 Docker,8 款容器替代方案

Docker 誕生於 2013 年,並普及了容器的概念,以至於大多數人仍然將容器的概念等同於 “Docker 容器”。

作爲第一個喫螃蟹的人,Docker 設置了新加入者必須遵守的標準。例如,Docker 有一個大型系統鏡像庫。所有的替代方案都必須使用相同的鏡像格式,同時試圖改變 Docker 所基於的整個堆棧的一個或多個部分。

在此期間,出現了新的容器標準,容器生態系統朝着不同方向發展。現在除了 Docker 之外,還有很多方法可以使用容器。

在本文中,我們將介紹以下內容:

容器的軟件堆棧

像 Chroot 調用、 cgroups 和命名空間等 Linux 特性幫助容器在與所有其他進程隔離的情況下運行,從而保證運行時的安全性。

Chroot

所有類似 Docker 的技術都起源於類似 Unix 操作系統(OS)的根目錄。在根目錄上方是根文件系統和其他目錄。

從長遠來看,這是很危險的,因爲根目錄中任何不需要的刪除都會影響整個操作系統。這就是爲什麼存在一個系統調用 chroot()。它創建了額外的根目錄,例如一個用於運行遺留軟件,另一個用於包含數據庫等等。

對於所有這些環境,chroot 似乎是一個真正的根目錄,而是實際上,它只是將路徑名添加到任何以 / 開頭的名字上。真正的根目錄仍然存在,並且任何進程都可以引用指定根目錄以外的任何位置。

Linux cgroups

自 2008 年 2.6.24 版本以來,Control groups (cgroups) 一直是 Linux 內核的一項功能。Cgroup 將同時限制、隔離和測量多個進程的系統資源(內存、CPU、網絡和 I/O)使用情況。

假設我們想阻止用戶從服務器發送大量電子郵件。我們創建了一個內存限制爲 1GB、CPU 佔用率爲 50% 的 cgroup,並將應用程序的 processid 添加到該組中。當達到這些限制時,系統將限制電子郵件發送過程。它甚至可能終止進程,這取決於託管策略。

Namespaces

Linux 命名空間是另一個有用的抽象層。命名空間允許我們擁有許多進程層次,每個層次都有自己的嵌套 “子樹(subtree)”。命名空間可以使用全局資源,並將其呈現給其成員,就像它是自己的資源一樣。

具體來看,Linux 系統開始時的進程標識符(PID)爲 1,並且所有其他進程將包含在其樹中。PID 命名空間允許我們跨越一棵新樹,它擁有自己的 PID 1 進程。現在有兩個值爲 1 的 PID,每個命名空間可以產生自己的命名空間,並且相同的過程可以附加了幾個 PID。

子命名空間中的一個進程將不知道父級的進程存在,而父命名空間將可以訪問整個子命名空間。

有七種類型的名稱空間:cgroup、IPC、網絡、mount、PID、用戶和 UTS。

Network Namespace

一些資源是稀缺的。按照慣例,有些端口具有預定義的角色,不應用於其他任何用途:端口 80 僅服務於 HTTP 調用,端口 443 僅服務於 HTTPS 調用等等。在共享主機環境中,兩個或多個站點可以監聽來自端口 80 的 HTTP 請求。第一個獲得該端口的站點不允許任何其他應用程序訪問該端口上的數據。第一個應用程序在互聯網上是可見的,而其他所有應用程序將不可見。

解決方案是使用網絡命名空間,通過網絡命名空間,內部進程將看到不同的網絡接口。

在一個網絡命名空間中,同一端口可以是開放的,而在另一個網絡命名空間中,可以關閉該端口。爲此,我們必須採用額外的 “虛擬” 網絡接口,這些接口同時屬於多個命名空間。中間還必須有一個路由器進程,將到達物理設備的請求連接到相應的名稱空間和其中的進程。

複雜嗎?這就是爲什麼 Docker 和類似工具如此受歡迎。現在讓我們來介紹一下 Docker,以及它的替代方案。

Docker: 人人可用的容器

在容器統治雲計算世界之前,虛擬機非常流行。如果你有一臺 Windows 機器,但想爲 iOS 開發移動應用程序,你可以購買一臺新的 Mac,或者將其虛擬機安裝到 Windows 硬件上。虛擬機也可能是笨重的,它們經常吞噬不需要的資源,而且啓動速度通常很慢(長達一分鐘)。

容器是標準軟件單元,具有運行程序所需的一切:操作系統、數據庫、鏡像、圖標,軟件庫、代碼和所需的其他組件。容器的運行也與所有其他容器,甚至與操作系統本身隔離。與虛擬機相比,容器是輕量級的,所以它們可以快速啓動,並且容易被替換。

要運行隔離和保護,容器需要基於 Chroot、cgroups 和命名空間。

容器的鏡像是在實際機器上形成應用程序的模板,能夠根據單個鏡像創建儘可能多的容器,一個名爲 Dockerfile 的文本文件包含了組裝鏡像所需的所有信息。

Docker 帶來的真正革命是創建了 Docker 鏡像倉庫和開發了 Docker 引擎,這些鏡像以相同的方式在各地運行,作爲第一個被廣泛採用的容器鏡像,形成了一個不成文的世界標準,所有後來的入局者都必須關注它。

CRI and OCI

圖片

OCI 全稱爲 Open Container Initiative,它發佈鏡像和容器的規範。它於 2015 年由 Docker 發起,並被微軟、Facebook、英特爾、VMWare、甲骨文和許多其他行業巨頭接受。

OCI 還提供了規範的一個實現,被稱爲 runc ,它可以直接使用容器,創建並運行它們等。

容器運行時接口(Container Runtime Interface,簡稱 CRI)是一個 Kubernetes API,它定義了 Kubernetes 如何與容器運行時交互。它也是標準化的,所以我們可以選擇採用哪個 CRI 實現。

用於 CRI 和 OCI 的容器的軟件堆棧

Linux 是運行容器的軟件堆棧中最基本的部分:

圖片

請注意,Containerd 和 CRI-O 都堅持 CRI 和 OCI 規範。對於 Kubernetes 而言,這意味着它可以使用 Containerd 或 CRI-O,而用戶不會注意到其中的區別。它還可以使用我們現在要提到的任何其他替代方案——這正是創建和採用了 OCI 和 CRI 等軟件標準的目標。

Docker 軟件堆棧

Docker 的軟件堆棧包括:

Kubernetes 的軟件堆棧幾乎是相同的;Kubernetes 使用 CRI-O,而不是 Containerd,這是由 Red Hat / IBM 和其他人創建的 CRI 實現。

containerd

圖片

containerd 作爲一個守護程序在 Linux 和 Windows 上運行。它加載鏡像,將其作爲容器執行,監督底層存儲,並負責整個容器的運行時間和生命週期。

Containerd 誕生於 2014 年,一開始作爲 Docker 的一部分,2017 年成爲雲原生計算基金會(CNCF)中的一個項目,並於 2019 年年初畢業。如果你想了解一些 Containerd 的使用技巧,歡迎查看下方的文章:

配置 containerd 鏡像倉庫完全攻略

runc

runc 是 OCI 規範的參考實現。它創建並運行容器以及其中的進程。它使用較低級別的 Linux 特性,比如 cgroup 和命名空間。

runc 的替代方案包括 Kata-Runtime、GVisor 和 CRI-O。

Kata-Runtime 使用硬件虛擬化作爲單獨的輕量級 VM 實現 OCI 規範。它的運行時與 OCI、CRI-O 和 Containerd 兼容,因此它可以與 Docker 和 Kubernetes 無縫工作。

圖片

Google 的 gVisor 創建包含自己內核的容器。它通過名爲 runsc 的項目實現 OCI,該項目與 Docker 和 Kubernetes 集成。有自己內核的容器比沒有內核的容器更安全,但它不是萬能的,而且這種方法在資源使用上要付出代價。

圖片

CRI-O 是一個純粹爲 Kubernetes 設計的容器堆棧,是 CRI 標準的第一個實現。它從任何容器鏡像倉庫中 提取鏡像,可以作爲使用 Docker 的輕量級替代方案。

圖片

今天它支持 runc 和 Kata Containers 作爲容器運行時,但也可以插入任何其他 OC 兼容的運行時(至少在理論上)。

它是一個 CNCF 孵化項目。

Podman

圖片

Podman 是一個沒有守護進程的 Docker 替代品。它的命令有意與 Docker 儘可能兼容,以至於您可以在 CLI 界面中創建一個別名並開始使用單詞 “Docker” 而不是 “podman”。

Podman 的目標是取代 Docker,因此堅持使用相同的命令集是有意義的。Podman 試圖改進 Docker 中的兩個問題。

首先,Docker 總是使用內部守護進程執行。守護進程是在後臺運行的單進程。如果它失敗了,整個系統就會失敗。

第二,Docker 作爲後臺進程運行,具有 root 權限,所以當你給一個新的用戶訪問權時,你實際上是給了整個服務器的訪問權。

Podman 是一個遠程 Linux 客戶端,可直接從操作系統運行容器。你也可以以 rootless 模式運行它們。它從 DockerHub 下載鏡像,並以與 Docker 完全相同的方式運行它們,具有完全相同的命令。

Podman 以 root 以外的用戶身份運行命令和鏡像,所以它比 Docker 更安全。另一方面,有許多爲 Docker 開發的工具在 Podman 上是不可用的,如 Portainer 和 Watchtower。擺脫 Docker 意味着放棄你之前建立的工作流程。

Podman 的目錄結構與 buildah、skopeo 和 CRI-I 類似。它的 Pod 也非常類似於 KubernetesPod。

Linux 容器:LXC 和 LXD

LXC(LinuX Containers)於 2008 年推出,是 Linux 上第一個上游內核的容器。Docker 的第一個版本使用了 LXC,但在後來的發展中,由於已經實現了 runc,所以 LXC 被移除了。

LXC 的目標是使用一個 Linux 內核在一個控制主機上運行多個隔離的 Linux 虛擬環境。爲此,它使用了 cgroups 功能,而不需要啓動任何虛擬機;它還使用命名空間,將應用程序與底層系統完全隔離。

LXC 旨在創建系統容器,幾乎就像你在虛擬機中一樣——但硬件開銷很小,因爲這些硬件是被虛擬化的。

LXC 不模擬硬件和軟件包,只包含需要的應用程序,所以它幾乎以裸機速度執行。相反,虛擬機包含整個操作系統,然後模擬硬件,如硬盤、虛擬處理器和網絡接口。

所以,LXC 是小而快的,而虛擬機是大而慢的。另一方面,虛擬環境不能被打包成現成的、可快速部署的機器,而且很難通過 GUI 管理控制檯進行管理。LXC 要求技術人員有很高的技術水平,並且優化後的機器可能與其他環境不兼容。

LXC VS Docker

LXC 就像 Linux 上的一個增壓 chroot,它產生的 “小” 服務器啓動更快,需要更少的 RAM。然而,Docker 提供了更多特性:

LXC 面向系統管理員,而 Docker 更面向開發人員。這就是 Docker 更受歡迎的原因所在。

LXD

LXD 有一個特權守護進程,它通過本地 UNIX socket 和網絡(如果啓用)公開 REST API。您可以通過命令行工具訪問它,但它總是使用 REST API 調用進行通信。無論客戶端是在本地機器上還是在遠程服務器上,它的功能都是一樣的。

LXD 可以從一臺本地機器擴展到幾千臺遠程機器。與 Docker 類似,它是基於鏡像的,所有更流行的 Linux 發行版都可以使用鏡像。Ubuntu 的公司 Canonical 正在資助 LXD 的開發,因此它將始終運行在 Ubuntu 以及其他類似 Linux 操作系統的最新版本上。LXD 可以與 OpenNebula 和 OpenStack 標準無縫集成。

從技術上講,LXD 是站在 LXC 的肩膀上(兩者都使用相同的 liblxc 庫和 Go 語言創建容器),但 LXD 的目標是改善用戶體驗。

Docker 會永遠存在嗎?

Docker 擁有 1100 萬開發者、700 萬個應用程序和每月 130 億次的鏡像下載。如果僅僅說 Docker 仍然是領導,那就太輕描淡寫了。然而,在這篇文章中,我們已經看到,現在已經有許多產品可以取代 Docker 軟件棧的一個或多個部分,並且通常情況下沒有兼容性問題。而且與 Docker 提供的服務相比,其他軟件的主要目標是安全性。

文章來源:RancherLabs / 可點擊查看原文

原文鏈接:

https://community.suse.com/posts/beyond-docker-a-look-at-alternatives-to-container-management-14411837


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/3S3xXLvmFACtoXn1Ccai2w