從零開始入門 K8s| 詳解 Pod 及容器設計模式

  • 2019 年 10 月 3 日
  • 筆記

作者|張磊 阿里雲容器平台高級技術專家,CNCF 官方大使

一、為什麼需要 Pod

容器的基本概念

我們知道 Pod 是 Kubernetes 項目裡面一個非常重要的概念,也是非常重要的一個原子調度單位,但是為什麼我們會需要這樣一個概念呢?在使用容器 Docker 的時候,也沒有這個說法。其實,如果想要理解 Pod,首先要理解容器,所以來回顧一下容器的概念:

容器的本質實際上是一個進程,是一個視圖被隔離,資源受限的進程。

容器裡面 PID=1 的進程就是應用本身,這意味著管理虛擬機等於管理基礎設施,因為我們是在管理機器,但管理容器卻等於直接管理應用本身。這也是之前說過的不可變基礎設施的一個最佳體現,這個時候,你的應用就等於你的基礎設施,它一定是不可變的。

在以上面的例子為前提的情況下,Kubernetes 又是什麼呢?很多人都說 Kubernetes 是雲時代的作業系統,這個非常有意思,因為如果以此類推,容器鏡像就是這個作業系統的軟體安裝包,它們之間是這樣的一個類比關係。
file

真實作業系統里的例子

如果說 Kubernetes 就是作業系統的話,那麼不妨看一下真實的作業系統的例子。

例子裡面有一個程式叫做 Helloworld,這個 Helloworld 程式實際上是由一組進程組成的,需要注意一下,這裡說的進程實際上等同於 Linux 中的執行緒。

因為 Linux 中的執行緒是輕量級進程,所以如果從 Linux 系統中去查看 Helloworld 中的 pstree,將會看到這個 Helloworld 實際上是由四個執行緒組成的,分別是 {api、main、log、compute}。也就是說,四個這樣的執行緒共同協作,共享 Helloworld 程式的資源,組成了 Helloworld 程式的真實工作情況。

這是作業系統裡面進程組或者執行緒組中一個非常真實的例子,以上就是進程組的一個概念。

file

那麼大家不妨思考一下,在真實的作業系統裡面,一個程式往往是根據進程組來進行管理的。Kubernetes 把它類比為一個作業系統,比如說 Linux。針對於容器我們前面提到可以類比為進程,就是前面的 Linux 執行緒。那麼 Pod 又是什麼呢?實際上 Pod 就是我們剛剛提到的進程組,也就是 Linux 里的執行緒組。

進程組概念

說到進程組,首先建議大家至少有個概念上的理解,然後我們再詳細的解釋一下。

還是前面那個例子:Helloworld 程式由四個進程組成,這些進程之間會共享一些資源和文件。那麼現在有一個問題:假如說現在把 Helloworld 程式用容器跑起來,你會怎麼去做?

當然,最自然的一個解法就是,我現在就啟動一個 Docker 容器,裡面運行四個進程。可是這樣會有一個問題,這種情況下容器裡面 PID=1 的進程該是誰? 比如說,它應該是我的 main 進程,那麼問題來了,「誰」又負責去管理剩餘的 3 個進程呢?

這個核心問題在於,容器的設計本身是一種「單進程」模型,不是說容器里只能起一個進程,由於容器的應用等於進程,所以只能去管理 PID=1 的這個進程,其他再起來的進程其實是一個託管狀態。 所以說服務應用進程本身就具有「進程管理」的能力。

比如說 Helloworld 的程式有 system 的能力,或者直接把容器里 PID=1 的進程直接改成 systemd,否則這個應用,或者是容器是沒有辦法去管理很多個進程的。因為 PID=1 進程是應用本身,如果現在把這個 PID=1 的進程給 kill 了,或者它自己運行過程中死掉了,那麼剩下三個進程的資源就沒有人回收了,這個是非常嚴重的一個問題。

反過來,如果真的把這個應用本身改成了 systemd,或者在容器裡面運行了一個 systemd,將會導致另外一個問題:使得管理容器不再是管理應用本身了,而等於是管理 systemd,這裡的問題就非常明顯了。比如說我這個容器裡面 run 的程式或者進程是 systemd,那麼接下來,這個應用是不是退出了?是不是 fail 了?是不是出現異常失敗了?實際上是沒辦法直接知道的,因為容器管理的是 systemd。這就是為什麼在容器裡面運行一個複雜程式往往比較困難的一個原因。

這裡再幫大家梳理一下:由於容器實際上是一個「單進程」模型,所以如果你在容器里啟動多個進程,只有一個可以作為 PID=1 的進程,而這時候,如果這個 PID=1 的進程掛了,或者說失敗退出了,那麼其他三個進程就會自然而然的成為孤兒,沒有人能夠管理它們,沒有人能夠回收它們的資源,這是一個非常不好的情況。

注意:Linux 容器的「單進程」模型,指的是容器的生命周期等同於 PID=1 的進程(容器應用進程)的生命周期,而不是說容器里不能創建多進程。當然,一般情況下,容器應用進程並不具備進程管理能力,所以你通過 exec 或者 ssh 在容器里創建的其他進程,一旦異常退出(比如 ssh 終止)是很容易變成孤兒進程的。

反過來,其實可以在容器裡面 run 一個 systemd,用它來管理其他所有的進程。這樣會產生第二個問題:實際上沒辦法直接管理我的應用了,因為我的應用被 systemd 給接管了,那麼這個時候應用狀態的生命周期就不等於容器生命周期。這個管理模型實際上是非常非常複雜的。

file

Pod = 「進程組」

在 Kubernetes 裡面,Pod 實際上正是 Kubernetes 項目為你抽象出來的一個可以類比為進程組的概念。

前面提到的,由四個進程共同組成的一個應用 Helloworld,在 Kubernetes 裡面,實際上會被定義為一個擁有四個容器的 Pod,這個概念大家一定要非常仔細的理解。

就是說現在有四個職責不同、相互協作的進程,需要放在容器里去運行,在 Kubernetes 裡面並不會把它們放到一個容器里,因為這裡會遇到兩個問題。那麼在 Kubernetes 里會怎麼去做呢?它會把四個獨立的進程分別用四個獨立的容器啟動起來,然後把它們定義在一個 Pod 裡面。

所以當 Kubernetes 把 Helloworld 給拉起來的時候,你實際上會看到四個容器,它們共享了某些資源,這些資源都屬於 Pod,所以我們說 Pod 在 Kubernetes 裡面只有一個邏輯單位,沒有一個真實的東西對應說這個就是 Pod,不會有的。真正起來在物理上存在的東西,就是四個容器,這四個容器,或者說是多個容器的組合就叫做 Pod。並且還有一個概念一定要非常明確,Pod 是 Kubernetes 分配資源的一個單位,因為裡面的容器要共享某些資源,所以 Pod 也是 Kubernetes 的原子調度單位。
file

上面提到的 Pod 設計,也不是 Kubernetes 項目自己想出來的, 而是早在 Google 研發 Borg 的時候,就已經發現了這樣一個問題。這個在 Borg paper 裡面有非常非常明確的描述。簡單來說 Google 工程師發現在 Borg 下面部署應用時,很多場景下都存在著類似於「進程與進程組」的關係。更具體的是,這些應用之前往往有著密切的協作關係,使得它們必須部署在同一台機器上並且共享某些資訊。

以上就是進程組的概念,也是 Pod 的用法。

為什麼 Pod 必須是原子調度單位?

可能到這裡大家會有一些問題:雖然了解這個東西是一個進程組,但是為什麼要把 Pod 本身作為一個概念抽象出來呢?或者說能不能通過調度把 Pod 這個事情給解決掉呢?為什麼 Pod 必須是 Kubernetes 裡面的原子調度單位?

下面我們通過一個例子來解釋。

假如現在有兩個容器,它們是緊密協作的,所以它們應該被部署在一個 Pod 裡面。具體來說,第一個容器叫做 App,就是業務容器,它會寫日誌文件;第二個容器叫做 LogCollector,它會把剛剛 App 容器寫的日誌文件轉發到後端的 ElasticSearch 中。

兩個容器的資源需求是這樣的:App 容器需要 1G 記憶體,LogCollector 需要 0.5G 記憶體,而當前集群環境的可用記憶體是這樣一個情況:Node_A:1.25G 記憶體,Node_B:2G 記憶體。

假如說現在沒有 Pod 概念,就只有兩個容器,這兩個容器要緊密協作、運行在一台機器上。可是,如果調度器先把 App 調度到了 Node_A 上面,接下來會怎麼樣呢?這時你會發現:LogCollector 實際上是沒辦法調度到 Node_A 上的,因為資源不夠。其實此時整個應用本身就已經出問題了,調度已經失敗了,必須去重新調度。

file

以上就是一個非常典型的成組調度失敗的例子。英文叫做:Task co-scheduling 問題,這個問題不是說不能解,在很多項目裡面,這樣的問題都有解法。

比如說在 Mesos 裡面,它會做一個事情,叫做資源囤積(resource hoarding):即當所有設置了 Affinity 約束的任務都達到時,才開始統一調度,這是一個非常典型的成組調度的解法。

所以上面提到的「App」和「LogCollector」這兩個容器,在 Mesos 裡面,他們不會說立刻調度,而是等兩個容器都提交完成,才開始統一調度。這樣也會帶來新的問題,首先調度效率會損失,因為需要等待。由於需要等,還會有外一個情況會出現,就是產生死鎖,即互相等待的一個情況。這些機制在 Mesos 里都是需要解決的,也帶來了額外的複雜度。

另一種解法是 Google 的解法。它在 Omega 系統(就是 Borg 下一代)裡面,做了一個非常複雜且非常厲害的解法,叫做樂觀調度。比如說:不管這些衝突的異常情況,先調度,同時設置一個非常精妙的回滾機制,這樣經過衝突後,通過回滾來解決問題。這個方式相對來說要更加優雅,也更加高效,但是它的實現機制是非常複雜的。這個有很多人也能理解,就是悲觀鎖的設置一定比樂觀鎖要簡單。

而像這樣的一個 Task co-scheduling 問題,在 Kubernetes 里,就直接通過 Pod 這樣一個概念去解決了。因為在 Kubernetes 里,這樣的一個 App 容器和 LogCollector 容器一定是屬於一個 Pod 的,它們在調度時必然是以一個 Pod 為單位進行調度,所以這個問題是根本不存在的。

再次理解 Pod

在講了前面這些知識點之後,我們來再次理解一下 Pod,首先 Pod 裡面的容器是「超親密關係」。

這裡有個「超」字需要大家理解,正常來說,有一種關係叫做親密關係,這個親密關係是一定可以通過調度來解決的。

file

比如說現在有兩個 Pod,它們需要運行在同一台宿主機上,那這樣就屬於親密關係,調度器一定是可以幫助去做的。但是對於超親密關係來說,有一個問題,即它必須通過 Pod 來解決。因為如果超親密關係賦予不了,那麼整個 Pod 或者說是整個應用都無法啟動。

什麼叫做超親密關係呢?大概分為以下幾類:

  • 比如說兩個進程之間會發生文件交換,前面提到的例子就是這樣,一個寫日誌,一個讀日誌;
  • 兩個進程之間需要通過 localhost 或者說是本地的 Socket 去進行通訊,這種本地通訊也是超親密關係;
  • 這兩個容器或者是微服務之間,需要發生非常頻繁的 RPC 調用,出於性能的考慮,也希望它們是超親密關係;
  • 兩個容器或者是應用,它們需要共享某些 Linux Namespace。最簡單常見的一個例子,就是我有一個容器需要加入另一個容器的 Network Namespace。這樣我就能看到另一個容器的網路設備,和它的網路資訊。

像以上幾種關係都屬於超親密關係,它們都是在 Kubernetes 中會通過 Pod 的概念去解決的。

現在我們理解了 Pod 這樣的概念設計,理解了為什麼需要 Pod。它解決了兩個問題:

  1. 我們怎麼去描述超親密關係;
  2. 我們怎麼去對超親密關係的容器或者說是業務去做統一調度,這是 Pod 最主要的一個訴求。

二、Pod 的實現機制

Pod 要解決的問題

像 Pod 這樣一個東西,本身是一個邏輯概念。那在機器上,它究竟是怎麼實現的呢?這就是我們要解釋的第二個問題。

既然說 Pod 要解決這個問題,核心就在於如何讓一個 Pod 里的多個容器之間最高效的共享某些資源和數據。

因為容器之間原本是被 Linux Namespace 和 cgroups 隔開的,所以現在實際要解決的是怎麼去打破這個隔離,然後共享某些事情和某些資訊。這就是 Pod 的設計要解決的核心問題所在。

所以說具體的解法分為兩個部分:網路和存儲。

1.共享網路

第一個問題是 Pod 里的多個容器怎麼去共享網路?下面是個例子:

比如說現在有一個 Pod,其中包含了一個容器 A 和一個容器 B,它們兩個就要共享 Network Namespace。在 Kubernetes 里的解法是這樣的:它會在每個 Pod 里,額外起一個 Infra container 小容器來共享整個 Pod 的  Network Namespace。

Infra container 是一個非常小的鏡像,大概 100~200KB 左右,是一個彙編語言寫的、永遠處於「暫停」狀態的容器。由於有了這樣一個 Infra container 之後,其他所有容器都會通過 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中。

所以說一個 Pod 裡面的所有容器,它們看到的網路視圖是完全一樣的。即:它們看到的網路設備、IP地址、Mac地址等等,跟網路相關的資訊,其實全是一份,這一份都來自於 Pod 第一次創建的這個 Infra container。這就是 Pod 解決網路共享的一個解法。

在 Pod 裡面,一定有一個 IP 地址,是這個 Pod 的 Network Namespace 對應的地址,也是這個 Infra container 的 IP 地址。所以大家看到的都是一份,而其他所有網路資源,都是一個 Pod 一份,並且被 Pod 中的所有容器共享。這就是 Pod 的網路實現方式。

由於需要有一個相當於說中間的容器存在,所以整個 Pod 裡面,必然是 Infra container 第一個啟動。並且整個 Pod 的生命周期是等同於 Infra container 的生命周期的,與容器 A 和 B 是無關的。這也是為什麼在 Kubernetes 裡面,它是允許去單獨更新 Pod 里的某一個鏡像的,即:做這個操作,整個 Pod 不會重建,也不會重啟,這是非常重要的一個設計。

file

2.共享存儲

第二問題:Pod 怎麼去共享存儲?Pod 共享存儲就相對比較簡單。

比如說現在有兩個容器,一個是 Nginx,另外一個是非常普通的容器,在 Nginx 里放一些文件,讓我能通過 Nginx 訪問到。所以它需要去 share 這個目錄。我 share 文件或者是 share 目錄在 Pod 裡面是非常簡單的,實際上就是把 volume 變成了 Pod level。然後所有容器,就是所有同屬於一個 Pod 的容器,他們共享所有的 volume。

file

比如說上圖的例子,這個 volume 叫做 shared-data,它是屬於 Pod level 的,所以在每一個容器里可以直接聲明:要掛載 shared-data 這個 volume,只要你聲明了你掛載這個 volume,你在容器里去看這個目錄,實際上大家看到的就是同一份。這個就是 Kubernetes 通過 Pod 來給容器共享存儲的一個做法。

所以在之前的例子中,應用容器 App 寫了日誌,只要這個日誌是寫在一個 volume 中,只要聲明掛載了同樣的 volume,這個 volume 就可以立刻被另外一個 LogCollector 容器給看到。以上就是 Pod 實現存儲的方式。

三、詳解容器設計模式

現在我們知道了為什麼需要 Pod,也了解了 Pod 這個東西到底是怎麼實現的。最後,以此為基礎,詳細介紹一下 Kubernetes 非常提倡的一個概念,叫做容器設計模式。

舉例

接下來將會用一個例子來給大家進行講解。

比如我現在有一個非常常見的一個訴求:我現在要發布一個應用,這個應用是 JAVA 寫的,有一個 WAR 包需要把它放到 Tomcat 的 web APP 目錄下面,這樣就可以把它啟動起來了。可是像這樣一個 WAR 包或 Tomcat 這樣一個容器的話,怎麼去做,怎麼去發布?這裡面有幾種做法。

file

  • 第一種方式:可以把 WAR 包和 Tomcat 打包放進一個鏡像裡面。但是這樣帶來一個問題,就是現在這個鏡像實際上揉進了兩個東西。那麼接下來,無論是我要更新 WAR 包還是說我要更新 Tomcat,都要重新做一個新的鏡像,這是比較麻煩的;

  • 第二種方式:就是鏡像裡面只打包 Tomcat。它就是一個 Tomcat,但是需要使用數據卷的方式,比如說 hostPath,從宿主機上把 WAR 包掛載進我們 Tomcat 容器中,掛到我的 web APP 目錄下面,這樣把這個容器啟用起來之後,裡面就能用了。

但是這時會發現一個問題:這種做法一定需要維護一套分散式存儲系統。因為這個容器可能第一次啟動是在宿主機 A 上面,第二次重新啟動就可能跑到 B 上去了,容器它是一個可遷移的東西,它的狀態是不保持的。所以必須維護一套分散式存儲系統,使容器不管是在 A 還是在 B 上,都可以找到這個 WAR 包,找到這個數據。

注意,即使有了分散式存儲系統做 Volume,你還需要負責維護 Volume 里的 WAR 包。比如:你需要單獨寫一套 Kubernetes Volume 插件,用來在每次 Pod 啟動之前,把應用啟動所需的 WAR 包下載到這個 Volume 里,然後才能被應用掛載使用到。

這樣操作帶來的複雜程度還是比較高的,且這個容器本身必須依賴於一套持久化的存儲插件(用來管理 Volume 里的 WAR 包內容)。

InitContainer

所以大家有沒有考慮過,像這樣的組合方式,有沒有更加通用的方法?哪怕在本地 Kubernetes 上,沒有分散式存儲的情況下也能用、能玩、能發布。

實際上方法是有的,在 Kubernetes 裡面,像這樣的組合方式,叫做 Init Container。

file

還是同樣一個例子:在上圖的 yaml 里,首先定義一個 Init Container,它只做一件事情,就是把 WAR 包從鏡像里拷貝到一個 Volume 裡面,它做完這個操作就退出了,所以 Init Container 會比用戶容器先啟動,並且嚴格按照定義順序來依次執行。

然後,這個關鍵在於剛剛拷貝到的這樣一個目的目錄:APP 目錄,實際上是一個 Volume。而我們前面提到,一個 Pod 裡面的多個容器,它們是可以共享 Volume 的,所以現在這個 Tomcat 容器,只是打包了一個 Tomcat 鏡像。但在啟動的時候,要聲明使用 APP 目錄作為我的 Volume,並且要把它們掛載在 Web APP 目錄下面。

而這個時候,由於前面運行過了一個 Init Container,已經執行完拷貝操作了,所以這個 Volume 裡面已經存在了應用的 WAR 包:就是 sample.war,絕對已經存在這個 Volume 裡面了。等到第二步執行啟動這個 Tomcat 容器的時候,去掛這個 Volume,一定能在裡面找到前面拷貝來的 sample.war。

所以可以這樣去描述:這個 Pod 就是一個自包含的,可以把這一個 Pod 在全世界任何一個 Kubernetes 上面都順利啟用起來。不用擔心沒有分散式存儲、Volume 不是持久化的,它一定是可以公布的。

所以這是一個通過組合兩個不同角色的容器,並且按照一些像 Init Container 的編排方式,統一去打包這樣一個應用,把它用 Pod 來去做的非常典型的一個例子。像這樣的一個概念,在 Kubernetes 裡面就是一個非常經典的容器設計模式,叫做:「Sidecar」。

容器設計模式:Sidecar

什麼是 Sidecar?就是說其實在 Pod 裡面,可以定義一些專門的容器,來執行主業務容器所需要的一些輔助工作,比如我們前面舉的例子,其實就幹了一個事兒,這個 Init Container,它就是一個 Sidecar,它只負責把鏡像里的 WAR 包拷貝到共享目錄裡面,以便被 Tomcat 能夠用起來。

其它有哪些操作呢?比如說:

  • 原本需要在容器裡面執行 SSH 需要乾的一些事情,可以寫腳本、一些前置的條件,其實都可以通過像 Init Container 或者另外像 Sidecar 的方式去解決;

  • 當然還有一個典型例子就是我的日誌收集,日誌收集本身是一個進程,是一個小容器,那麼就可以把它打包進 Pod 裡面去做這個收集工作;

  • 還有一個非常重要的東西就是 Debug 應用,實際上現在 Debug 整個應用都可以在應用 Pod 裡面再次定義一個額外的小的 Container,它可以去 exec 應用 pod 的 namespace;

  • 查看其他容器的工作狀態,這也是它可以做的事情。不再需要去 SSH 登陸到容器里去看,只要把監控組件裝到額外的小容器裡面就可以了,然後把它作為一個 Sidecar 啟動起來,跟主業務容器進行協作,所以同樣業務監控也都可以通過 Sidecar 方式來去做。

這種做法一個非常明顯的優勢就是在於其實將輔助功能從我的業務容器解耦了,所以我就能夠獨立發布 Sidecar 容器,並且更重要的是這個能力是可以重用的,即同樣的一個監控 Sidecar 或者日誌 Sidecar,可以被全公司的人共用的。這就是設計模式的一個威力。

file

Sidecar:應用與日誌收集

接下來,我們再詳細細化一下 Sidecar 這樣一個模式,它還有一些其他的場景。

比如說前面提到的應用日誌收集,業務容器將日誌寫在一個 Volume 裡面,而由於 Volume 在 Pod 裡面是被共享的,所以日誌容器 —— 即 Sidecar 容器一定可以通過共享該 Volume,直接把日誌文件讀出來,然後存到遠程存儲裡面,或者轉發到另外一個例子。現在業界常用的 Fluentd 日誌進程或日誌組件,基本上都是這樣的工作方式。

file

Sidecar:代理容器

Sidecar 的第二個用法,可以稱作為代理容器 Proxy。什麼叫做代理容器呢?

假如現在有個 Pod 需要訪問一個外部系統,或者一些外部服務,但是這些外部系統是一個集群,那麼這個時候如何通過一個統一的、簡單的方式,用一個 IP 地址,就把這些集群都訪問到?有一種方法就是:修改程式碼。因為程式碼里記錄了這些集群的地址;另外還有一種解耦的方法,即通過 Sidecar 代理容器。

簡單說,單獨寫一個這麼小的 Proxy,用來處理對接外部的服務集群,它對外暴露出來只有一個 IP 地址就可以了。所以接下來,業務容器主要訪問 Proxy,然後由 Proxy 去連接這些服務集群,這裡的關鍵在於 Pod 裡面多個容器是通過 localhost 直接通訊的,因為它們同屬於一個 network Namespace,網路視圖都一樣,所以它們倆通訊 localhost,並沒有性能損耗。

所以說代理容器除了做了解耦之外,並不會降低性能,更重要的是,像這樣一個代理容器的程式碼就又可以被全公司重用了。

file

Sidecar:適配器容器

Sidecar 的第三個設計模式 —— 適配器容器 Adapter,什麼叫 Adapter 呢?

現在業務暴露出來的 API,比如說有個 API 的一個格式是 A,但是現在有一個外部系統要去訪問我的業務容器,它只知道的一種格式是 API B ,所以要做一個工作,就是把業務容器怎麼想辦法改掉,要去改業務程式碼。但實際上,你可以通過一個 Adapter 幫你來做這層轉換。

file

有個例子:現在業務容器暴露出來的監控介面是 /metrics,訪問這個容器的 metrics 的 URL 就可以拿到了。可是現在,這個監控系統升級了,它訪問的 URL 是 /health,我只認得暴露出 health 健康檢查的 URL,才能去做監控,metrics 不認識。那這個怎麼辦?那就需要改程式碼了,但可以不去改程式碼,額外寫一個 Adapter,用來把所有對 health 的這個請求轉發給 metrics 就可以了,所以這個 Adapter 對外暴露的是 health 這樣一個監控的 URL,這就可以了,你的業務就又可以工作了。

這樣的關鍵,還在於 Pod 之中的容器是通過 localhost 直接通訊的,所以沒有性能損耗,並且這樣一個 Adapter 容器可以被全公司重用起來,這些都是設計模式給我們帶來的好處。

本文總結

  • Pod 是 Kubernetes 項目里實現「容器設計模式」的核心機制;
  • 「容器設計模式」是 Google Borg 的大規模容器集群管理最佳實踐之一,也是 Kubernetes 進行複雜應用編排的基礎依賴之一;
  • 所有「設計模式」的本質都是:解耦和重用。

最後

Pod 與容器設計模式是 Kubernetes 體系裡面最重要的一個基礎知識點,希望讀者能夠仔細揣摩和掌握。在這裡,我建議你去重新審視一下之前自己公司或者團隊里使用 Pod 方式,是不是或多或少採用了所謂「富容器」這種設計呢?這種設計,只是一種過渡形態,會培養出很多非常不好的運維習慣。我強烈建議你逐漸採用容器設計模式的思想,對富容器進行解耦,將它們拆分成多個容器組成一個 Pod。這也正是當前阿里巴巴「全面上雲」戰役中正在全力推進的一項重要的工作內容。

「 阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。」