前言微服務(wù)架構(gòu)背景下,,隨著服務(wù)和服務(wù)實(shí)例的數(shù)量不斷增加,,如果依然用傳統(tǒng)的方式部署、配置和管理這些服務(wù)進(jìn)程,,就會(huì)發(fā)現(xiàn),,越來(lái)越多的時(shí)間花在了管理部署和解決部署過(guò)程中出現(xiàn)的問(wèn)題上了。比如,,需要新增服務(wù)實(shí)例進(jìn)行擴(kuò)容,,服務(wù)器環(huán)境搭建就挺費(fèi)時(shí)間的。另外,,很多人肯定會(huì)經(jīng)歷過(guò),,同一份代碼的程序在測(cè)試環(huán)境跑得好好的,但到了生產(chǎn)環(huán)境就出錯(cuò)了,。部署上線的時(shí)候,,大部分問(wèn)題其實(shí)都是運(yùn)行環(huán)境和配置問(wèn)題,開(kāi)發(fā)和運(yùn)維就為了解決這些問(wèn)題花費(fèi)了很多時(shí)間,。 容器化就能很好地解決上面所說(shuō)的問(wèn)題,。其實(shí),虛擬機(jī)也是一種解決方案,,但虛擬機(jī)相對(duì)來(lái)說(shuō)太重了,。容器則很輕量級(jí),占用的資源也很少,,啟動(dòng)又快,。所以,無(wú)疑容器是解決微服務(wù)應(yīng)用部署問(wèn)題的更優(yōu)選擇,。確切地說(shuō),,虛擬機(jī)是為了實(shí)現(xiàn)在單個(gè)物理機(jī)上安裝不同的操作系統(tǒng),目的是操作系統(tǒng)級(jí)別的隔離,;而容器則是為了實(shí)現(xiàn)在同一個(gè)操作系統(tǒng)中將不同的應(yīng)用隔離開(kāi),,目的是應(yīng)用級(jí)別的隔離。 那說(shuō)到容器化技術(shù),,Docker 和 Kubernetes(簡(jiǎn)稱 K8S) 是最具代表性的兩套工具,。不過(guò),,容器技術(shù)其實(shí)遠(yuǎn)不只是這兩套工具。下面,,我們就來(lái)細(xì)聊這一塊,。 容器說(shuō)到容器,很多人就想到了 Docker,,甚至認(rèn)為容器=Docker,,這無(wú)疑是錯(cuò)誤的認(rèn)識(shí)。其實(shí),,Docker 是一套容器引擎,,也叫容器運(yùn)行時(shí),且容器引擎不只有 Docker 一家,,還有 rkt,、containerd、pouch,、cri-o 等,。容器的創(chuàng)建和管理都是由容器引擎實(shí)現(xiàn)的。 要直觀地理解容器,,其實(shí)和虛擬機(jī)對(duì)比一下就明白了,請(qǐng)看下圖: 從圖中也很明顯看出,,之所以容器比 VM 要輕量得多,,主要就因?yàn)樯倭艘粋€(gè) Guest OS。另外,,圖中也看到了,,容器的下層就是容器引擎。 一個(gè)容器本質(zhì)上也是一個(gè)進(jìn)程,,多個(gè)容器就是運(yùn)行在同個(gè) OS 中的多個(gè)相互隔離的進(jìn)程,。實(shí)現(xiàn)容器間的隔離,其底層主要使用了 Linux 內(nèi)核的 Namespaces 和 CGroups 來(lái)分隔進(jìn)程,,以便各應(yīng)用進(jìn)程能夠相互獨(dú)立運(yùn)行,。Namespace 又稱為命名空間,主要對(duì)系統(tǒng)資源做訪問(wèn)隔離,。其原理是針對(duì)一類資源進(jìn)行抽象,,并將其封裝在一起提供給一個(gè)容器使用,對(duì)于這類資源,,因?yàn)槊總€(gè)容器都有自己的抽象,,而他們彼此之間是不可見(jiàn)的,所以就可以做到訪問(wèn)隔離,。主要有六類 Namesapce:
CGroups 是 Control Groups 的簡(jiǎn)稱,,也叫控制組,,主要做資源限制。原理是將一組進(jìn)程放在一個(gè)控制組里,,通過(guò)給這個(gè)控制組分配指定的可用資源,,達(dá)到控制這一組進(jìn)程可用資源的目的。比如可以限制 CPU 的使用率,、內(nèi)存的使用上限等,。 最早的容器引擎應(yīng)該算是 LXC 了,全稱為 Linux Container,,誕生于 2008 年,,主要使用命令行創(chuàng)建和管理容器。不過(guò),,LXC 創(chuàng)建的容器無(wú)法有效跨機(jī)器進(jìn)行遷移,,這是最大的缺陷。但 LXC 也是現(xiàn)代容器技術(shù)的實(shí)現(xiàn)基礎(chǔ),,包括 Docker,,最初都是在 LXC 的基礎(chǔ)上提供了更強(qiáng)大的功能。 DockerDocker 發(fā)布于 2013年,,在這之前,,容器技術(shù)一直不溫不火,是 Docker 讓容器技術(shù)迎來(lái)了騰飛,。主要就是因?yàn)?Docker 突破性的解決了容器標(biāo)準(zhǔn)化與可移植性的問(wèn)題,。Docker 的宣傳口號(hào)是 “Build,Ship and Run Any App,,Anywhere”,。標(biāo)準(zhǔn)化了才可以 Run Any App,具備可移植性才能做到 Run Anywhere,。而做到這兩點(diǎn)的核心就是容器鏡像(container image),,一種新型的應(yīng)用打包、分發(fā)和運(yùn)行機(jī)制,。容器鏡像將應(yīng)用運(yùn)行環(huán)境,,包括代碼、依賴庫(kù),、工具,、資源文件和元信息等,打包成一種操作系統(tǒng)發(fā)行版無(wú)關(guān)的不可變更軟件包。 容器鏡像打包了整個(gè)容器運(yùn)行依賴的環(huán)境,,以避免依賴底層的操作系統(tǒng),,從而實(shí)現(xiàn) “build once,run anywhere”,。也同樣有賴于容器鏡像,,用戶可以打包任何應(yīng)用所依賴的環(huán)境,而不用改造應(yīng)用來(lái)適配運(yùn)行環(huán)境,,所以就可以 “run any app”,。 容器鏡像是基于聯(lián)合文件系統(tǒng)(UnionFS) 的,具有分層結(jié)構(gòu),,即一個(gè)鏡像是由若干層級(jí)的不同鏡像疊加組成的,,且每一層都是只讀的。容器鏡像只是一個(gè)靜態(tài)文件,,在鏡像的最上層再增加一層可寫(xiě)層(也稱為容器層),,就變成了 Docker 容器,即 Docker 容器 = 鏡像 + 容器層,。 另外,,容器也是有生命周期的,主要有 5 種狀態(tài):Created,、Running,、Paused、Stopped,、Deleted,。各狀態(tài)的流轉(zhuǎn)如下圖: 既然容器可以被刪除,那容器中的程序產(chǎn)生的數(shù)據(jù)需要持久化又怎么辦呢,?為了解決此問(wèn)題,,Docker 引入了 Volume 機(jī)制,,Volume 以獨(dú)立于 Docker 文件系統(tǒng)的形式存在于宿主機(jī)中,,不會(huì)隨著容器的刪除而刪除。Volume 由 Docker 管理,,包括創(chuàng)建,、刪除等。默認(rèn)情況下,,Volume 的存儲(chǔ)空間來(lái)自于宿主機(jī)文件系統(tǒng)中的某個(gè)目錄,,如 /var/lib/docker/volumes/,Docker 系統(tǒng)外的程序不應(yīng)該修改其中的數(shù)據(jù),。不過(guò),,每個(gè)容器只能掛載一個(gè) Volume。雖然也有其他的持久化方案,但 Volume 是官方推薦的持久化方案,。 再來(lái)看看 Docker 的整體架構(gòu),,如下圖: Docker 采用的是 C/S 架構(gòu),Client 是提供給用戶操作容器和鏡像的工具集,,主要是通過(guò)發(fā)送 docker 命令到 Docker daemon 實(shí)現(xiàn)的,。docker 命令與 Docker daemon 通信實(shí)際上是調(diào)用了 Docker API,且一個(gè) Client 是可以與多個(gè) Docker daemon 通信的,。Docker daemon 會(huì)監(jiān)聽(tīng) Docker API 的請(qǐng)求,,并管理 Docker 各種對(duì)象,包括鏡像,、容器,、網(wǎng)絡(luò)和磁盤等。Docker daemon 和容器,,以及本地鏡像都在同一個(gè) Docker Host 上,,即 Docker 主機(jī)。Client 和 Docker Host 可以部署在同一臺(tái)宿主機(jī)上,,也可以分開(kāi)部署,。但一般都是分開(kāi)部署,一個(gè) Client 連接多個(gè) Docker Host,。 啟動(dòng)運(yùn)行容器時(shí),,Docker daemon 從本地獲取鏡像,如本地沒(méi)有,,則從 Registry 獲取鏡像并緩存到本地,。Registry 是存放鏡像的倉(cāng)庫(kù),有公共倉(cāng)庫(kù),,也可以搭建私有倉(cāng)庫(kù),。Docker 官方運(yùn)營(yíng)著一個(gè)公共的 Registry 叫 Docker Hub,用戶可以在 Docker Hub 注冊(cè)賬號(hào),,分享并保存自己的鏡像,。 KubernetesKubernetes,簡(jiǎn)稱 K8S,,是用來(lái)做容器編排的,,是用于自動(dòng)部署、擴(kuò)展和管理容器化應(yīng)用程序的開(kāi)源系統(tǒng),。因?yàn)槿萜髦饕€是應(yīng)用在分布式架構(gòu)的系統(tǒng)中,,擁有大量服務(wù),而這些服務(wù)又要封裝到容器中,,那就存在大量容器需要進(jìn)行創(chuàng)建,、編排等工作。如果一個(gè)個(gè)容器還需要人工去編排管理,那工作量無(wú)疑是巨大的,,所以才需要像 K8S 這樣的自動(dòng)化容器編排系統(tǒng),。 K8S 是在 2014 年 Google 基于內(nèi)部使用的 Borg 系統(tǒng)所創(chuàng)建的開(kāi)源項(xiàng)目,用于解決大規(guī)模集群的容器部署,、運(yùn)行,、管理等問(wèn)題。K8S 在容器的基礎(chǔ)上增加了一層的新的管理抽象 Pod,,以便更好地利用容器進(jìn)行應(yīng)用的功能模塊切分,。得益于 Google 在大規(guī)模集群基礎(chǔ)設(shè)施建設(shè)的強(qiáng)大積累,脫胎于 Borg 的 K8S 很快成為了行業(yè)的標(biāo)準(zhǔn)應(yīng)用,,堪稱容器編排的必備工具,。 K8S 的架構(gòu)圖如下: K8S 采用了主從分布式架構(gòu),主要由一個(gè) Master 和多個(gè) Worker Node 組成,,以及包括客戶端命令行工具 kubectl 和其它附加項(xiàng),。主要包含了以下核心組件:
Container Runtime 即容器運(yùn)行時(shí),其實(shí)也可以理解為就是像 Docker 這樣的容器引擎,,后面我們會(huì)再細(xì)說(shuō)這個(gè)概念,。在 K8S 中,,主要就是 kubelet 組件通過(guò)一個(gè)叫 CRI 的接口服務(wù)與 Container Runtime 進(jìn)行通信的,。 K8S 能夠創(chuàng)建和部署的最小單元是 Pod,一個(gè) Pod 可以包含一個(gè)或多個(gè)容器,,還包括了存儲(chǔ),、網(wǎng)絡(luò)等各個(gè)容器共享的資源。通常一個(gè) Pod 運(yùn)行一個(gè)容器,不同 Pod 之間則是相互隔離的,。另外,,Pod 所支持的容器不只是 Docker,也支持很多其他容器,。 Pod 和 Docker 一樣也存在數(shù)據(jù)持久化的問(wèn)題,,解決方案也采用了 Volume 機(jī)制,但與 Docker Volume 有些不同,。最大的不同就是 K8S 可以支持許多類型的 Volume,,Pod 也能同時(shí)使用任意數(shù)量的 Volume。 容器規(guī)范前面我們說(shuō)過(guò),,容器引擎不只有 Docker,,還有 rkt、containerd,、pouch,、cri-o 等。而容器編排工具也不只有 Kubernetes,,還有 Docker Swarm,、Apache Mesos 等。各大派系相互競(jìng)爭(zhēng),,在競(jìng)爭(zhēng)合作之間尋找平衡從而導(dǎo)致了標(biāo)準(zhǔn)規(guī)范的誕生,。 2015 年 6 月,Docker 帶頭成立 OCI(Open Container Initiative),,旨在“制定并維護(hù)容器鏡像格式和容器運(yùn)行時(shí)的正式規(guī)范(OCI Specifications)”,其核心產(chǎn)出是 OCI Runtime Spec(容器運(yùn)行時(shí)規(guī)范),、OCI Image Spec(鏡像格式規(guī)范)、OCI Distribution Spec(鏡像分發(fā)規(guī)范),。所以 OCI 組織解決的是容器的構(gòu)建,、分發(fā)和運(yùn)行問(wèn)題。 一個(gè)月之后,,Google 帶頭成立了 CNCF(Cloud Native Computing Foundation),,旨在“構(gòu)建云原生計(jì)算 —— 一種圍繞著微服務(wù)、容器和應(yīng)用動(dòng)態(tài)調(diào)度的,、以基礎(chǔ)設(shè)施為中心的架構(gòu),,并促進(jìn)其廣泛使用”。所以 CNCF 組織解決的是應(yīng)用管理及容器編排問(wèn)題,。 這兩個(gè)組織不再是競(jìng)爭(zhēng)關(guān)系,,而是相輔相成,,共同制定了一系列行業(yè)事實(shí)標(biāo)準(zhǔn)。其中,,與容器相關(guān)的最為重要的幾個(gè)規(guī)范包括:OCI Distribution Spec,、OCI Image Spec、OCI Runtime Spec,、CRI,、CNI、CSI 和 Shimv2,。
其中,,CRI,、CNI、CSI 都是 K8S 系統(tǒng)里原本所定義的幾個(gè)接口,。 這些規(guī)范確立之后,基于這些標(biāo)準(zhǔn)規(guī)范的具體實(shí)現(xiàn)不斷涌現(xiàn),,呈現(xiàn)出一片百花齊放的景象,。Docker 也為了適應(yīng) OCI 標(biāo)準(zhǔn)規(guī)范而剝離出來(lái)了兩個(gè)標(biāo)準(zhǔn)化的組件,一個(gè)叫 runc,,一個(gè)叫 containerd,。下面再來(lái)了解下這兩個(gè)組件。 容器運(yùn)行時(shí)講具體的組件之前,,我想先聊聊另一個(gè)概念,,叫 Container Runtime(容器運(yùn)行時(shí))。lxc,、docker,、rkt、cri-o,、containerd,、runc 等其實(shí)都屬于 Container Runtime。但其實(shí),,Container Runtime 還可以再分為兩大類:High-Level Container Runtime 和 Low-Level Container Runtime,。它們的關(guān)系如下圖: 要理解這兩者,我們可以從運(yùn)行容器的步驟說(shuō)起,。一般來(lái)說(shuō),,運(yùn)行一個(gè)容器的過(guò)程可分為三步:
只專注于解決第三步的運(yùn)行時(shí),即負(fù)責(zé)底層運(yùn)行容器的 Runtime,,就屬于 Low-Level 容器運(yùn)行時(shí),。lxc、runc 都?xì)w于這一類,。對(duì)應(yīng)地,,High-Level 容器運(yùn)行時(shí)位于 Low-Level 容器運(yùn)行時(shí)的上層,則負(fù)責(zé)更為高級(jí)的容器功能,,包括鏡像的傳輸和管理,鏡像的解壓,,并傳遞給 Low-Level 容器運(yùn)行時(shí)來(lái)運(yùn)行容器,。這一類的 Runtime 主要有 docker、containerd,、cri-o 等。 runc 應(yīng)該算是應(yīng)用最廣泛的 Low-Level Container Runtime,,是 Docker 為了適應(yīng) OCI Runtime Spec 而貢獻(xiàn)給 OCI 組織的,而它的前身其實(shí)是 Docker 內(nèi)部的一個(gè) lib 庫(kù)叫 libcontainer,。runc 其實(shí)也是一個(gè) CLI 工具,,實(shí)際上,runc 也是通過(guò)調(diào)用 libcontainer 提供的接口來(lái)管理容器的,。 其實(shí),,Docker 剛發(fā)布的時(shí)候,是基于 LXC 的,。Docker 把 LXC 復(fù)雜的容器創(chuàng)建與使用方式簡(jiǎn)化為了自己的一套命令體系,。但隨著 Docker 的不斷發(fā)展,LXC 已不能滿足 Docker 的需求(比如跨平臺(tái)),,于是 Docker 公司把底層實(shí)現(xiàn)都抽象化,,將底層容器的實(shí)現(xiàn)方式變成了一種可變的方案,從而誕生了 libcontainer,。libcontainer 是一個(gè)用于容器管理的 lib 庫(kù),,基于 Go 語(yǔ)言實(shí)現(xiàn),通過(guò)管理 containerd 則是應(yīng)用廣泛的 High-Level Container Runtime,也是從 Docker 中剝離出來(lái)的,,但 containerd 不是貢獻(xiàn)給了 OCI 組織,,而是捐給了 CNCF 組織,成為了 CRI 標(biāo)準(zhǔn)的一個(gè)實(shí)現(xiàn),。獨(dú)立后的 containerd 的架構(gòu)如下圖: containerd 采用了 C/S 架構(gòu),,并不是直接面向最終用戶的,主要用于集成到更上層的系統(tǒng)里,,比如 K8S,、 Swarm、Mesos 等容器編排系統(tǒng),。另外,,其 CRI 實(shí)現(xiàn)是通過(guò)插件化的方式實(shí)現(xiàn)的。而底層的 Low-Level Container Runtime 則默認(rèn)使用 runc,,當(dāng)然,,實(shí)際上只要是符合 OCI 規(guī)范的 Runtime 都可以支持。 containerd 啟動(dòng)時(shí)主要也是以守護(hù)進(jìn)程的方式運(yùn)行的,,可以管理一臺(tái)主機(jī)上的所有容器,。而運(yùn)行其上的每個(gè)容器,則會(huì)啟動(dòng)每個(gè)單獨(dú)的 containerd-shim 子進(jìn)程并結(jié)合 runc 或其他 Runtime 進(jìn)行管理,。 其實(shí),,從符合哪個(gè)標(biāo)準(zhǔn)規(guī)范的維度來(lái)劃分的話,High-Level 容器運(yùn)行時(shí)一般也稱為 CRI Runtime,,而 Low-Level 容器運(yùn)行時(shí)則稱為 OCI Runtime,。而說(shuō)到這,不得不提一下一件事,,2020 年底的時(shí)候,,Kubernetes 官方發(fā)布公告,宣布自 v1.20 起放棄對(duì) Docker 的支持,,屆時(shí)用戶將收到 Docker 棄用警告,,并需要改用其他容器運(yùn)行時(shí),。這是因?yàn)?Docker 并不支持 CRI,而 Kubernetes 對(duì) Docker 的支持主要是通過(guò)一個(gè)叫 dockershim 的橋接服務(wù),,能夠?qū)?Docker API 轉(zhuǎn)換為 CRI,。但在后續(xù)版本當(dāng)中,Kubernetes 將不再提供這項(xiàng)橋接服務(wù),。因此,,對(duì)于已經(jīng)在 Kubernetes 中使用了 Docker 的系統(tǒng),建議可以從 Docker 遷移到 containerd,,畢竟 containerd 就是從 Docker 剝離出來(lái)的,,遷移的成本最低。 容器網(wǎng)絡(luò)容器網(wǎng)絡(luò)也是容器化平臺(tái)中很核心的一個(gè)基礎(chǔ)模塊,,主要就是解決容器之間互相通信的問(wèn)題,,包括同一主機(jī)上的容器,也包括不同主機(jī)的容器,。另外,,對(duì)于容器編排系統(tǒng)來(lái)說(shuō),容器還要能和集群中所有的節(jié)點(diǎn)直接通信,。 早期的容器網(wǎng)絡(luò)設(shè)計(jì)把重點(diǎn)放在了如何連接同一主機(jī)上的容器,,讓它們可以和外界進(jìn)行交互。 Docker 的容器網(wǎng)絡(luò)一開(kāi)始采用的是 host 模式,,運(yùn)行在同一主機(jī)上的容器直接使用宿主機(jī)的 network namespace,,和宿主機(jī)同一個(gè) IP,而容器會(huì)占用宿主機(jī)上的一個(gè)端口,,通過(guò)這個(gè)端口和外界通信,。這樣,就需要手動(dòng)維護(hù)端口的分配,,不同的容器服務(wù)需要使用不同的端口,。這種模式另一個(gè)明顯的劣勢(shì)就是容器不再擁有隔離、獨(dú)立的網(wǎng)絡(luò)棧,。 Docker 后來(lái)升級(jí)為 bridge 模式,,這種模式下,首先會(huì)在宿主機(jī)創(chuàng)建一個(gè)網(wǎng)橋叫 docker0,,當(dāng)創(chuàng)建一個(gè)新的容器時(shí),,容器通過(guò) DHCP 獲取一個(gè)與 docker0 同網(wǎng)段的虛擬 IP 地址,并默認(rèn)連接到 docker0,,以此實(shí)現(xiàn)容器與宿主機(jī)的網(wǎng)絡(luò)互通,。同時(shí),docker 會(huì)為容器創(chuàng)建獨(dú)立的網(wǎng)絡(luò)棧,實(shí)現(xiàn)容器之間,、容器與宿主機(jī)之間的網(wǎng)絡(luò)隔離,。其網(wǎng)絡(luò)模型如下圖: 不過(guò),如果容器想要和外界通信的話,,還是需要使用 host 的 IP 地址,。這時(shí)候需要用到 NAT 將 host-ip:port 轉(zhuǎn)換成 private-ip:port。 而不管是 host 模式還是 bridge 模式,,主要都是為了解決同一主機(jī)內(nèi)的容器網(wǎng)絡(luò)通信問(wèn)題,,而不是為了跨主機(jī)通信而設(shè)計(jì)的,因此并不能優(yōu)雅地解決跨主機(jī)容器通信的問(wèn)題,。 而隨著容器技術(shù)的快速發(fā)展,,容器跨主機(jī)通信的需求越來(lái)越迫切。后來(lái),,Docker 公司和 CoreOS 公司相繼提出了各自的容器網(wǎng)絡(luò)標(biāo)準(zhǔn) CNM(Container Network Model) 和 CNI(Container Network Interface),。 Docker 還將網(wǎng)絡(luò)部分的代碼從 Docker 核心代碼中剝離出來(lái),,形成了單獨(dú)的項(xiàng)目 libnetwork,,這也成為了實(shí)現(xiàn) CNM 的第一個(gè)項(xiàng)目,而且被作為 Docker 容器內(nèi)置的網(wǎng)絡(luò)插件,。 而 CNI 相比 CNM 更加通用和簡(jiǎn)單,,也因此,當(dāng) K8S 社區(qū)決定從 CNM 和 CNI 中選擇一個(gè)作為 K8S 的容器網(wǎng)絡(luò)標(biāo)準(zhǔn)時(shí),,最終選擇了 CNI,。也因?yàn)?K8S 的影響力,后來(lái)的很多項(xiàng)目也都選擇了 CNI,,因此,,CNI 更有望成為未來(lái)容器網(wǎng)絡(luò)的標(biāo)準(zhǔn)。 CNI 的基本思想為:Container Runtime 在創(chuàng)建容器時(shí),,先創(chuàng)建好 network namespace,,然后調(diào)用 CNI 插件為這個(gè) netns 配置網(wǎng)絡(luò),其后再啟動(dòng)容器內(nèi)的進(jìn)程,。 支持 CNI 的網(wǎng)絡(luò)方案被稱為 CNI 插件,。CNI 插件包括兩部分:
常見(jiàn)的 CNI 插件包括 IPvlan、MACvlan,、Bridge,、Calico、Flannel、Weave,、Open vSwitch,、Contiv、CNI-Genie 等,。 而這么多網(wǎng)絡(luò)插件,,其實(shí)可以根據(jù)實(shí)現(xiàn)模式分為三類:Underlay、Overlay,、Routing,。 Underlay 模式中容器和宿主機(jī)位于同一層網(wǎng)絡(luò),依賴于底層網(wǎng)絡(luò)的能力來(lái)打通容器之間的網(wǎng)絡(luò),,以 IPvlan,、MACvlan 為代表。 Overlay 模式的典型特征是容器獨(dú)立于主機(jī)的 IP 段,,這個(gè) IP 段進(jìn)行跨主機(jī)網(wǎng)絡(luò)通信時(shí)是通過(guò)在主機(jī)之間創(chuàng)建隧道的方式,,將整個(gè)容器網(wǎng)段的包全都封裝成底層的物理網(wǎng)絡(luò)中主機(jī)之間的包。該方式不依賴于底層網(wǎng)絡(luò),,實(shí)現(xiàn)方案以 Flannel,、Weave 為代表。 Routing 模式中主機(jī)和容器也分屬不同的網(wǎng)段,,與 Overlay 模式的主要區(qū)別在于它的跨主機(jī)通信是通過(guò)路由打通,,無(wú)需在不同主機(jī)之間做一個(gè)隧道封包。但路由打通就需要部分依賴于底層網(wǎng)絡(luò),,比如說(shuō)要求底層網(wǎng)絡(luò)有二層可達(dá)的一個(gè)能力,。該模式的典型方案為 Calico。 Flannel 和 Calico 是兩款流行的插件,,有必要再多了解一下,。 Flannel 通過(guò)給每臺(tái)宿主機(jī)分配一個(gè)子網(wǎng)的方式為容器提供虛擬網(wǎng)絡(luò),它基于 Linux TUN/TAP,,使用 UDP 封裝 IP 包來(lái)創(chuàng)建 Overlay 網(wǎng)絡(luò),,并借助 etcd 維護(hù)網(wǎng)絡(luò)的分配情況。其原理如下圖所示: 目前已支持 udp,、vxlan,、host-gw、aws-vpc,、gce,、ali-vpc 等數(shù)據(jù)轉(zhuǎn)發(fā)方式,其中以 vxlan 技術(shù)最為流行,,因?yàn)?vxlan 性能更良好并且需要的手動(dòng)干預(yù)更少,。 與其他方案相比,,F(xiàn)lannel 的優(yōu)點(diǎn)就是相對(duì)容易安裝和配置。一般來(lái)說(shuō),,在初期使用 Flannel 是一個(gè)穩(wěn)妥安全的選擇,,直到你開(kāi)始需要一些它無(wú)法提供的東西。 Calico 目前的流行程度還比不上 Flannel,,但其受眾正在快速增長(zhǎng),。雖然 Flannel 被公認(rèn)為是最簡(jiǎn)單的選擇,但Calico 以其性能,、靈活性而聞名,。Calico 的功能也更為全面,不僅提供主機(jī)和 Pod 之間的網(wǎng)絡(luò)連接,,還涉及網(wǎng)絡(luò)安全和管理,,支持網(wǎng)絡(luò)策略就是其最受追捧的功能之一。此外,,Calico 還可以與服務(wù)網(wǎng)格 Istio 集成,,以便在服務(wù)網(wǎng)格層和網(wǎng)絡(luò)基礎(chǔ)架構(gòu)層中解釋和實(shí)施集群內(nèi)工作負(fù)載的策略。 總地來(lái)說(shuō),,F(xiàn)lannel 可以算是入門級(jí)插件,,Calico 則是進(jìn)階級(jí)的。 容器化落地前面講了那么多,,最后,,我們就來(lái)看看如何將容器化技術(shù)落地到我們的項(xiàng)目中,。 首先,,從選型上來(lái)說(shuō),上了規(guī)模的微服務(wù)架構(gòu)系統(tǒng)是需要使用容器編排系統(tǒng)的,,而這塊的競(jìng)爭(zhēng)者雖然有 Kubernetes,、Swarm 和 Mesos 等,但實(shí)際應(yīng)用中,,Kubernetes 可以說(shuō)是一支獨(dú)大,,大廠中廠都已經(jīng)選擇了它,那我們其實(shí)也沒(méi)必要再花費(fèi)時(shí)間和精力去對(duì)比,,選它就對(duì)了,。 其次,需要選擇使用哪個(gè)容器運(yùn)行時(shí),。原本,,使用最廣泛的運(yùn)行時(shí)當(dāng)屬 Docker,但前面我們說(shuō)過(guò),,Kubernetes 已經(jīng)宣布了不再提供 Docker 的專屬橋接服務(wù),。而且 Docker 由于剝離出了兩個(gè)獨(dú)立的運(yùn)行時(shí) runc 和 containerd,所以,作為運(yùn)行時(shí)的 Docker 其實(shí)也已經(jīng)不具備太大優(yōu)勢(shì),,即是說(shuō),,作為容器運(yùn)行時(shí)的 Docker,已經(jīng)不再是最佳選擇,,containerd + runc 很可能會(huì)成為替代 Docker 的最佳選擇,。 然后,還需要選擇 CNI 插件,??稍?Flannel 和 Calico 兩者之中選一個(gè),我比較傾向于選擇 Calico,,雖然 Flannel 更容易安裝和配置,,但 Calico 的部署也不難,而且后續(xù)需要用到高級(jí)特性時(shí)也不需要更換網(wǎng)絡(luò)方案,。 接著,,還要考慮整個(gè)系統(tǒng)中哪些需要容器化,哪些不需要容器化,?我們知道,,應(yīng)用其實(shí)可以分為有狀態(tài)和無(wú)狀態(tài)兩種,像網(wǎng)關(guān),、業(yè)務(wù)邏輯層,、數(shù)據(jù)訪問(wèn)層的服務(wù)實(shí)例大部分都可以做成無(wú)狀態(tài)的,而像數(shù)據(jù)庫(kù),、緩存,、MQ 等保存數(shù)據(jù)的應(yīng)用則是有狀態(tài)的。雖然從技術(shù)上來(lái)說(shuō),,不管是無(wú)狀態(tài)還是有狀態(tài)的應(yīng)用,,都可以容器化運(yùn)行,但無(wú)狀態(tài)應(yīng)用更適合用容器化運(yùn)行,,可以實(shí)現(xiàn)服務(wù)的水平伸縮,,通過(guò)容器編排避免單點(diǎn)故障的問(wèn)題。但數(shù)據(jù)庫(kù),、MQ 等需要持久化數(shù)據(jù)的服務(wù)容器化的效用則不大,。Redis 如果只是用作緩存,不需要保證該數(shù)據(jù)持久化,,那么數(shù)據(jù)沒(méi)有丟失的風(fēng)險(xiǎn),,這時(shí)候用容器化也沒(méi)有問(wèn)題。 簡(jiǎn)而言之,,我們主要采用 Kubernetes + containerd + runc + Calico 來(lái)搭建我們的容器化平臺(tái),,從網(wǎng)關(guān)層,,到業(yè)務(wù)邏輯層,再到數(shù)據(jù)訪問(wèn)層的所有微服務(wù),,都可以進(jìn)行容器化運(yùn)行,,而數(shù)據(jù)庫(kù)、MQ 則無(wú)需容器化,。 總結(jié)容器化解決的不是應(yīng)用架構(gòu)的問(wèn)題,,而是運(yùn)維部署的問(wèn)題。容器技術(shù)生態(tài)發(fā)展迅速,,涉及到的概念和技術(shù)也比較多,,所以搞清楚各種概念和技術(shù)很重要。本文聊了容器,、Docker,、Kubernets、容器規(guī)范,、容器運(yùn)行時(shí),、容器網(wǎng)絡(luò)等各種概念和技術(shù),并最后簡(jiǎn)單聊了下容器化落地的一點(diǎn)思路,,希望能給到還不太了解容器技術(shù)生態(tài)的小伙伴一些認(rèn)識(shí),。 |
|