2014 年發布的 Kubernetes 在今天儼然已成為容器編排領域的事實標準,相信談到 Kubernetes 的開發者都會一再復述上述現象。如下圖所示,今天的大多數個人或者團隊都會選擇 Kubernetes 管理容器,而也有 75% 的人會在生產環境中使用 Kubernetes。
圖 1 - Kubernetes 容器編排[^1]
在這種全民學習和使用 Kubernetes 的大背景下,我們也應該非常清晰地知道 Kubernetes 有哪些局限性。雖然 Kubernetes 能夠解決容器編排領域的大多數問題,但是仍然有一些場景是它很難處理、甚至無法處理的,只有對這些潛在的風險有清晰的認識,才能更好地駕馭這項技術,這篇文章將從集群管理和應用場景兩個部分談談 Kubernetes 社區目前的發展和一些局限性。
集群管理
集群是一組能夠在一起協同工作的計算機,我們可以將集群中的所有計算機看成一個整體,所有資源調度系統都是以集群為維度進行管理的,集群中的所有機器構成了資源池,這個巨大的資源池會為待運行的容器提供資源執行計算任務,這里簡單談一談 Kubernetes 集群管理面對的幾個復雜問題。
水平擴展性
集群大小是我們在評估資源管理系統時需要關注的重要指標之一,然而 Kubernetes 能夠管理的集群規模遠遠小于業界的其他資源管理系統。集群大小為什么重要呢,我們先來看另一個同樣重要的指標 — 資源利用率,很多工程師可能沒有在公有云平臺上申請過資源,這些資源都相當昂貴,在 AWS 上申請一個與主機差不多配置的虛擬機實例(8 CPU、16 GB)每個月大概需要 150 美金,約為 1000 人民幣[^2]。
圖 2 - AWS EC2 價格
大多數的集群都會使用 48 CPU 或者 64 CPU 的物理機或者虛擬機作為集群中的節點,如果我們的集群中需要包含 5,000 個節點,那么這些節點每個月大概要 8,000,000 美元,約為 50,000,000 人民幣,在這樣的集群中提升 1% 的資源利用率就相當于每個月節省了 500,000 的成本。
多數在線任務的資源利用率都很低,更大的集群意味著能夠運行更多的工作負載,而多種高峰和低谷期不同的負載部署在一起可以實現超售,這樣能夠顯著地提高集群的資源利用率,如果單個集群的節點數足夠多,我們在部署不同類型的任務時會有更合理的組合,可以完美錯開不同服務的高峰期。
Kubernetes 社區對外宣傳的是單個集群最多支持 5,000 節點,Pod 總數不超過 150,000,容器總數不超過 300,000 以及單節點 Pod 數量不超過 100 個[^3],與幾萬節點的 Apache Mesos 集群、50,000 節點的微軟 YARN 集群[^4]相比,Kubernetes 的集群規模整整差了一個數量級。雖然阿里云的工程師也通過優化 Kubernetes 的各個組件實現了 5 位數的集群規模,但是與其他的資源管理方式相比卻有比較大的差距[^5]。
圖 3 - Apache Mesos 與 Hadoop YARN
需要注意的是 Kubernetes 社區雖然對外宣稱單集群可以支持 5,000 節點,同時社區也有各種各樣的集成測試保證每個改動都不會影響它的伸縮性[^6],但是 Kubernetes 真的非常復雜,我們沒有辦法保證你使用的每個功能在擴容的過程中都不出問題。而在生產環境中,我們甚至可能在集群擴容到 1000 ~ 1500 節點時遇到瓶頸。
每個稍具規模的大公司都想要實現更大規模的 Kubernetes 集群,但是這不是一個改幾行代碼就能解決的簡單問題,它可能需要我們限制 Kubernetes 中一些功能的使用,在擴容的過程中,etcd、API 服務器、調度器以及控制器都有可能出現問題。社區中已經有一些開發者注意到了其中的一些問題,例如在節點上增加緩存降低 API 服務器的負載[^7],但是要推動類似的改變還是很困難的,有志之士可以嘗試在社區推動類似的項目。
多集群管理
單個集群的容量再大也無法解決企業面對的問題,哪怕有一天 Kubernetes 集群可以達到 50,000 節點的規模,我們仍然需要管理多個集群,多集群管理也是 Kubernetes 社區目前正在探索的方向,社區中的多集群興趣小組(SIG Multi-Cluster)目前就在完成相關的工作[^8]。在作者看來,Kubernetes 的多集群會帶來資源不平衡、跨集群訪問困難以及提高運維和管理成本三大問題,我們在這里談一談目前在開源社區和業界幾種可供參考和選擇的解決方案。
kubefed
首先要介紹的是 kubefed,該項目是 Kubernetes 社區給出的解決方案,它同時提供了跨集群的資源和網絡管理的功能,社區的多集群興趣小組(SIG Multi-Cluster)負責了該項目的開發工作:
圖 4 - Kubernetes 聯邦
kubefed 通過一個中心化的聯邦控制面板管理多集群中的元數據,上層的控制面板會為管理器群中的資源創建對應的聯邦對象,例如:FederatedDeployment:
- kind: FederatedDeployment
- ...
- spec:
- ...
- overrides:
- # Apply overrides to cluster1
- - clusterName: cluster1
- clusterOverrides:
- # Set the replicas field to 5
- - path: "/spec/replicas"
- value: 5
- # Set the image of the first container
- - path: "/spec/template/spec/containers/0/image"
- value: "nginx:1.17.0-alpine"
- # Ensure the annotation "foo: bar" exists
- - path: "/metadata/annotations"
- op: "add"
- value:
- foo: bar
- # Ensure an annotation with key "foo" does not exist
- - path: "/metadata/annotations/foo"
- op: "remove"
- # Adds an argument `-q` at index 0 of the args list
- # this will obviously shift the existing arguments, if any
- - path: "/spec/template/spec/containers/0/args/0"
- op: "add"
- value: "-q"
上層的控制面板會根據聯邦對象 FederatedDeployment 的規格文件生成對應的 Deployment 并推送到下層的集群,下層集群可以正常根據 Deployment 中的定義創建特定數量的副本。
圖 5 - 從聯邦對象到普通對象
FederatedDeployment 只是一種最簡單的分發策略,在生產環境中我們希望通過聯邦的集群實現容災等復雜功能,這時可以利用 ReplicaSchedulingPreference 在不同集群中實現更加智能的分發策略:
- apiVersion: scheduling.kubefed.io/v1alpha1
- kind: ReplicaSchedulingPreference
- metadata:
- name: test-deployment
- namespace: test-ns
- spec:
- targetKind: FederatedDeployment
- totalReplicas: 9
- clusters:
- A:
- minReplicas: 4
- maxReplicas: 6
- weight: 1
- B:
- minReplicas: 4
- maxReplicas: 8
- weight: 2
上述調度的策略可以實現工作負載在不同集群之間的權重,在集群資源不足甚至出現問題時將實例遷移到其他集群,這樣既能夠提高服務部署的靈活性和可用性,基礎架構工程師也可以更好地平衡多個集群的負載。
我們可以認為 kubefed 的主要作用是將多個松散的集群組成強耦合的聯邦集群,并提供更加高級的網絡和部署功能,這樣我們可以更容易地解決集群之間資源不平衡和連通性的一些問題,然而該項目的關注點不包含集群生命周期的管理,
集群接口
Cluster API 也是 Kubernetes 社區中與多集群管理相關的項目,該項目由集群生命周期小組(SIG Cluster-Lifecycle)負責開發,其主要目標是通過聲明式的 API 簡化多集群的準備、更新和運維工作,你在該項目的 設計提案 中能夠找到它的職責范圍[^9]。
圖 6 - Cluster API 概念
在該項目中最重要的資源就是 Machine,它表示一個 Kubernetes 集群中的節點。當該資源被創建時,特定提供商的控制器會根據機器的定義初始化并將新的節點注冊到集群中,在該資源被更新或者刪除時,也會執行操作達到用戶的狀態。
這種策略與阿里的多集群管理的方式有一些相似,它們都使用聲明式的 API 定義機器和集群的狀態,然后使用 Kubernetes 原生的 Operator 模型在更高一層的集群中管理下層集群,這能夠極大降低集群的運維成本并提高集群的運行效率[^10],不過類似的項目都沒有考慮跨集群的資源管理和網絡管理。
應用場景
我們在這一節將談談 Kubernetes 中一些有趣的應用場景,其中包括應用分發方式的現狀、批處理調度任務以及硬多租戶在集群中的支持,這些是社區中比較關注的問題,也是 Kubernetes 目前的盲點。
應用分發
Kubernetes 主項目提供了幾種部署應用的最基本方式,分別是 Deployment、StatefulSet 和 DaemonSet,這些資源分別適用于無狀態服務、有狀態服務和節點上的守護進程,這些資源能夠提供最基本的策略,但是它們無法處理更加復雜的應用。
圖 7 - Kubernetes 應用管理
隨著 CRD 的引入,目前社區的應用管理小組(SIG Apps)基本不會向 Kubernetes 主倉庫引入較大的改動,大多數的改動都是在現有資源上進行的修補,很多常見的場景,例如只運行一次的 DaemonSet[^11] 以及金絲雀和藍綠部署等功能,現在的資源也存在很多問題,例如 StatefulSet 在初始化容器中卡住無法回滾和更新[^12]。
我們可以理解社區不想在 Kubernetes 中維護更多的基本資源,通過幾個基本的資源可以覆蓋 90% 的場景,剩下的各種復雜場景可以讓其他社區通過 CRD 的方式實現。不過作者認為如果社區能夠在上游實現更多高質量的組件,這對于整個生態都是很有價值并且很重要的工作,需要注意的是假如各位讀者想要在 Kubernetes 項目中成為貢獻者,SIG Apps 可能不是一個很好的選擇。
批處理調度
機器學習、批處理任務和流式任務等工作負載的運行從 Kubernetes 誕生第一天起到今天都不是它的強項,大多數的公司都會使用 Kubernetes 運行在線服務處理用戶請求,用 Yarn 管理的集群運行批處理的負載。
hadoop-yarn
圖 8 - Hadoop Yarn
在線任務和離線任務往往是兩種截然不同的作業,大多數的在線任務都是無狀態的服務,它們可以在不同機器上進行遷移,彼此很難有極強的依賴關系;但是很多離線任務的拓撲結構都很復雜,有些任務需要多個作業一同執行,而有些任務需要按照依賴關系先后執行,這種復雜的調度場景在 Kubernetes 中比較難以處理。
在 Kubernetes 調度器引入調度框架之前,所有的 Pod 在調度器看來是沒有任何關聯的,不過有了調度框架,我們可以在調度系統中實現更加復雜的調度策略,例如保證一組 Pod 同時調度的 PodGroup[^13],這對于 Spark 和 TensorFlow 任務非常有用。
- # PodGroup CRD spec
- apiVersion: scheduling.sigs.k8s.io/v1alpha1
- kind: PodGroup
- metadata:
- name: nginx
- spec:
- scheduleTimeoutSeconds: 10
- minMember: 3
- ---
- # Add a label `pod-group.scheduling.sigs.k8s.io` to mark the pod belongs to a group
- labels:
- pod-group.scheduling.sigs.k8s.io: nginx
Volcano 也是在 Kubernetes 上構建的批處理任務管理系統[^14],它能夠處理機器學習、深度學習以及其他大數據應用,可以支持包括 TensorFlow、Spark、PyTorch 和 MPI 在內的多個框架。
圖 9 - Volcano
雖然 Kubernetes 能夠運行一些批處理任務,但是距離在這個領域上取代 Yarn 等老牌資源管理系統上還有非常大的差距,相信在較長的一段時間內,大多數公司都會同時維護 Kubernetes 和 Yarn 兩種技術棧,分別管理和運行不同類型的工作負載。
硬多租戶
多租戶是指同一個軟件實例可以為不同的用戶組提供服務,Kubernetes 的多租戶是指多個用戶或者用戶組使用同一個 Kubernetes 集群,今天的 Kubernetes 還很難做到硬多租戶支持,也就是同一個集群的多個租戶不會相互影響,也感知不到彼此的存在。
硬多租戶在 Kubernetes 中是一個很重要、也很困難的課題,合租公寓就是一個典型的多租戶場景,多個租客共享房屋內的基礎設施,硬多租戶要求多個訪客之間不會相互影響,你可以想象這有多么困難,Kubernetes 社區甚至有一個工作小組專門討論和研究相關的問題[^15],然而雖然感興趣的工程師很多,但是成果卻非常有限。
圖 10 - 多租戶
盡管 Kubernetes 使用命名空間來劃分虛擬機群,然而這也很難實現真正的多租戶。多租戶的支持到底有哪些作用呢,這里簡單列幾個多租戶帶來的好處:
Kubernetes 帶來的額外部署成本對于小集群來說非常高昂,穩定的 Kubernetes 集群一般都需要至少三個運行 etcd 的主節點,如果大多數的集群都是小集群,這些額外的機器會帶來很高的額外開銷;
Kubernetes 中運行的容器可能需要共享物理機和虛擬機,一些開發者可能在公司內部遇到過自己的服務被其他業務影響,因為主機上容器可能隔離了 CPU 和內存資源,但是沒有隔離 I/O、網絡 和 CPU 緩存等資源,這些資源的隔離是相對困難的;
如果 Kubernetes 能夠實現硬多租戶,這不僅對云服務商和小集群的使用者來說都是個福音,它還能夠隔離不同容器之間的影響并防止潛在安全問題的發生,不過這在現階段還是比較難實現的。
總結
每個技術都有自己的生命周期,越底層的技術生命周期會越長,而越上層的技術生命周期也就越短,雖然 Kubernetes 是當今容器界的扛把子,但是未來的事情沒有人可以說的準。我們要時刻清楚手中工具的優點和缺點,花一些時間學習 Kubernetes 中設計的精髓,不過如果在未來的某一天 Kubernetes 也成為了過去,我們也應該感到喜悅,因為會有更好的工具取代它。
[^1]: Kubernetes and Container Security and Adoption Trends https://www.stackrox.com/kubernetes-adoption-security-and-market-share-for-containers/
[^2]: AWS Pricing Calculator https://calculator.aws/#/createCalculator/EC2
[^3]: Considerations for large clusters https://kubernetes.io/docs/setup/best-practices/cluster-large/
[^4]: How Microsoft drives exabyte analytics on the world’s largest YARN cluster https://azure.microsoft.com/en-us/blog/how-microsoft-drives-exabyte-analytics-on-the-world-s-largest-yarn-cluster/
[^5]: 備戰雙 11!螞蟻金服萬級規模 K8s 集群管理系統如何設計?https://www.sofastack.tech/blog/ant-financial-managing-large-scale-kubernetes-clusters/
[^6]: sig-scalability-kubemark dashboard https://testgrid.k8s.io/sig-scalability-kubemark#kubemark-5000
[^7]: Node-local API cache #84248 https://github.com/kubernetes/kubernetes/issues/84248
[^8]: Multicluster Special Interest Group https://github.com/kubernetes/community/tree/master/sig-multicluster
[^9]: Cluster API Scope and Objectives https://github.com/kubernetes-sigs/cluster-api/blob/master/docs/scope-and-objectives.md
[^10]: Demystifying Kubernetes as a service – How Alibaba cloud manages 10,000s of Kubernetes clusters https://www.cncf.io/blog/2019/12/12/demystifying-kubernetes-as-a-service-how-does-alibaba-cloud-manage-10000s-of-kubernetes-clusters/
[^11]: Run job on each node once to help with setup #64623 https://github.com/kubernetes/kubernetes/issues/64623
[^12]: StatefulSet does not upgrade to a newer version of manifests #78007 https://github.com/kubernetes/kubernetes/issues/78007
[^13]: Coscheduling based on PodGroup CRD https://github.com/kubernetes-sigs/scheduler-plugins/tree/master/kep/42-podgroup-coscheduling
[^14]: Volcano · A Kubernetes Native Batch System https://github.com/volcano-sh/volcano
[^15]: Kubernetes Working Group for Multi-Tenancy https://github.com/kubernetes-sigs/multi-tenancy
原文地址:https://mp.weixin.qq.com/s/ULfmxZh2PBYK-298Xskf2Q