Kubernetes 雖然簡化了分散式應用的佈署和維運,但對於開發者來說,它引入的新概念和工件也增加了一層複雜性。因此,建構更高層級的抽象層,提供更友好的開發者原語,並標準化應用程式的組態和佈署方式,變得至關重要。開發高階抽象層的兩種主要方法,一是將 Kubernetes 封裝起來,讓開發者不必直接與 Kubernetes 互動;二是利用 Kubernetes 的擴充套件能力,直接擴充其功能。選擇哪種方法取決於抽象層的目標和應用場景。對於機器學習Pipeline等特定領域,第一種方法更適合;而對於通用的應用程式佈署,擴充套件 Kubernetes 更具優勢,因為它能保持與 Kubernetes 生態系統的相容性,並更容易找到具備相關經驗的開發人員。
在 Kubernetes 上建構更高層級的應用模式
Kubernetes 是一個複雜的系統,儘管它簡化了分散式應用的佈署和維運,但對於開發人員來說,它並沒有使開發變得更容易。事實上,當新增新的概念和工件供開發人員互動時,它在簡化維運的同時,也增加了一層複雜性。因此,在許多環境中,開發更高層級的抽象以提供更友好的開發人員原語是有意義的。此外,在許多大公司中,標準化應用程式的組態和佈署方式以使所有人遵循相同的維運最佳實踐也是有意義的。這可以透過開發更高層級的抽象來實作,使開發人員自動遵循這些原則。
開發更高層級抽象的方法
在考慮如何在 Kubernetes 上開發更高層級的原語時,有兩種基本方法。第一種是將 Kubernetes 作為實作細節進行封裝。透過這種方法,消費您的平台的開發人員應該基本上不知道他們是在 Kubernetes 上執行;相反,他們應該認為自己是您提供的平台的消費者,因此 Kubernetes 只是一個實作細節。
Kubeflow:Kubernetes 的機器學習工具包
Kubeflow 是 Kubernetes 的機器學習工具包,它原生於 Kubernetes,並提供了多種必要的工具來完成機器學習工作流程。像 Jupyter Notebooks、pipelines 和 Kubernetes 原生控制器等工具,使資料科學家能夠簡單、輕鬆地充分利用 Kubernetes 作為機器學習平台。
Kubeflow 的主要功能
- Jupyter Notebooks:提供互動式的開發環境,方便資料科學家進行資料探索、模型開發和測試。
- Pipelines:實作機器學習工作流程的自動化和可重複性。
- Kubernetes 原生控制器:確保機器學習工作流程的高用性和可擴充套件性。
Polyaxon:管理機器學習工作流程的工具
Polyaxon 是一個用於管理機器學習工作流程的工具,支援多種流行的函式庫,並可在任何 Kubernetes 叢集上執行。Polyaxon 提供了商業和開源版本。
Polyaxon 的主要功能
- 支援多種機器學習函式庫,如 TensorFlow、PyTorch 等。
- 提供工作流程管理、模型訓練和佈署等功能。
- 可與 Kubernetes 無縫整合,實作機器學習工作流程的自動化和可擴充套件性。
Pachyderm:企業級的資料科學平台
Pachyderm 是一個企業級的資料科學平台,提供了一套豐富的工具,用於資料集準備、生命週期管理和版本控制,以及構建機器學習管道。Pachyderm 提供了商業版本,可佈署到任何 Kubernetes 叢集。
Pachyderm 的主要功能
- 資料集準備和版本控制:確保資料的一致性和可重複性。
- 機器學習管道構建:實作機器學習工作流程的自動化和可擴充套件性。
- 與 Kubernetes 無縫整合:提供高用性和可擴充套件性的機器學習平台。
在 Kubernetes 上執行機器學習的最佳實踐
要在 Kubernetes 上實作最佳的機器學習效能,請考慮以下最佳實踐:
- 智慧排程和自動擴充套件:利用 Cluster Autoscaler 實作叢集的自動擴充套件,根據工作負載的需求動態調整資源。
- GPU 資源管理:使用 taints 和 tolerations 或 time-specific Cluster Autoscaler 來管理和最佳化 GPU 資源的使用。
- 監控和最佳化:持續監控 GPU、CPU、網路和儲存資源的使用情況,找出瓶頸並進行最佳化。
- 混合工作負載叢集:使用獨立的節點池來執行機器學習工作負載,避免影響其他業務服務。
- 分散式訓練:使用 Horovod 等開源工具來改善分散式訓練框架,實作更好的模型擴充套件性。
在Kubernetes上建立更高層級的應用模式
在為開發者建立更高層級的抽象層時,開發人員有兩種主要選擇。第一種是完全在Kubernetes之上建立一個抽象層,使開發者完全不必直接與Kubernetes互動。第二種則是利用Kubernetes本身的擴充套件能力,直接擴充套件Kubernetes的功能。
選擇合適的方法
選擇哪種方法取決於你所建立的抽象層的目標。如果你的目標是建立一個完全隔離、整合的環境,使用者不需要“破壞玻璃”並逃離這個環境,而且使用方便性是重要的特性,那麼第一種選擇是很好的。例如,建立一個機器學習Pipeline就是一個很好的例子。這個領域相對較為成熟,使用者可能是資料科學家,他們可能不熟悉Kubernetes。讓這些資料科學家快速完成工作並專注於他們的領域,而不是分散式系統,是主要目標。因此,在Kubernetes之上建立一個完整的抽象層是最合理的選擇。
另一方面,當建立一個更高層級的開發者抽象層時,例如一個簡單佈署Java應用程式的方法,擴充套件Kubernetes比包裝它更好,有兩個原因。首先,應用程式開發的領域非常廣泛,很難預測開發者的所有需求和使用案例,特別是當應用程式和業務隨著時間的推移而迭代和變化時。其次,確保你可以繼續利用Kubernetes的工具生態系統。現在有無數的雲原生工具用於監控、持續交付等。擴充套件而不是替換Kubernetes API,可以確保你可以繼續使用這些工具和未來開發的新工具。此外,當你選擇擴充套件而不是模糊Kubernetes API時,很容易找到具有Kubernetes行業經驗的人才。在一個只存在於你環境中的定製應用平台上建立應用程式的經驗是非常罕見的。
擴充套件Kubernetes
由於在Kubernetes上建立的每一層都是獨特的,因此在本文中描述如何建立這樣一層以擴充套件Kubernetes超出了範圍。但是,用於擴充套件Kubernetes的工具和技術對於你在Kubernetes上進行的任何構建都是通用的,因此我們將花時間介紹它們。
擴充套件Kubernetes叢集
擴充套件Kubernetes叢集涉及瞭解Kubernetes中資源的接觸點。有三個相關的技術解決方案。第一個是sidecar。Sidecar容器(如圖15-1所示)在服務網格的背景下已經變得流行。這些容器與主應用程式容器一起執行,提供與主應用程式解耦的額外功能,通常由不同的團隊維護。例如,在服務網格中,sidecar可能會為容器化應用程式提供透明的相互傳輸層安全性(mTLS)身份驗證。你可以使用sidecars為使用者定義的應用程式新增功能。
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 擴充套件Kubernetes叢集
rectangle "一起執行" as node1
rectangle "提供額外功能" as node2
node1 --> node2
@enduml此圖示展示了sidecar設計的概念,其中sidecar容器與主應用程式容器一起執行,提供額外的功能。
內容解密:
圖15-1展示了sidecar設計的概念。sidecar容器與主應用程式容器一起執行,提供額外的功能,如mTLS身份驗證。這種設計模式在服務網格中非常流行,並且被許多專案用來為開發者的容器提供服務。
在業界,sidecar方法已經變得越來越流行,許多專案使用它來提供與開發者容器平行的服務。一個很好的例子是Dapr(分散式應用程式執行環境)專案。Dapr是一個在CNCF內的開源專案,它為應用程式實作了一個sidecar,提供了許多功能,如加密、金鑰/值儲存、發布/訂閱佇列等,具有非常簡單、一致的API。像Dapr這樣的sidecars可以被用作你在Kubernetes上開發的平台的模組化構建塊。
然而,如果我們要求開發者學習和使用sidecars,我們實際上使問題變得更糟。幸運的是,用於擴充套件Kubernetes的其他工具簡化了事情。特別是,Kubernetes具有準入控制器。准入控制器是在API請求被儲存(或“准入”)到叢集的後端儲存之前讀取它們的攔截器。你可以使用這些准入控制器來驗證或修改API物件。在sidecars的背景下,你可以使用它們自動將sidecars新增到叢集中建立的所有pod中,以便開發者不需要了解sidecars就可以獲得其好處。圖15-2展示了准入控制器如何與Kubernetes API互動。
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 內容解密:
rectangle "請求" as node1
rectangle "驗證或修改" as node2
rectangle "儲存" as node3
node1 --> node2
node2 --> node3
@enduml此圖示展示了准入控制器與Kubernetes API互動的方式。
內容解密:
圖15-2展示了准入控制器如何與Kubernetes API互動。准入控制器攔截API請求,在它們被儲存到叢集的後端儲存之前,對其進行驗證或修改。這使得你可以自動將sidecars新增到叢集中的所有pod中,而不需要開發者瞭解sidecars。
擴充套件 Kubernetes 的功能與使用者經驗
Kubernetes 的准入控制器(Admission Controllers)不僅可用於新增 sidecar,還能驗證開發人員提交給 Kubernetes 的物件。例如,實作一個 Kubernetes linter,確保開發人員提交的 Pod 和其他資源遵循使用 Kubernetes 的最佳實踐。常見的錯誤是開發人員未為其應用程式保留資源,此時根據准入控制器的 linter 可以攔截這些請求並拒絕它們。當然,也應該提供逃脫出口(escape hatch),讓進階使用者可以適時選擇離開 lint 規則。
自訂資源定義(CRDs)
CRDs 允許動態地向現有的 Kubernetes 叢集新增新資源。例如,可以新增一個新的 ReplicatedService 資源,當開發人員建立 ReplicatedService 例項時,它會在 Kubernetes 中建立對應的 Deployment 和 Service 資源。因此,ReplicatedService 是開發人員對常見模式的一種方便抽象。CRDs 通常由佈署在叢集中的控制迴圈(control loop)實作,用於管理這些新的資源型別。
CRDs 的實作與應用
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: replicatedservices.mycompany.com
spec:
group: mycompany.com
versions:
v1:
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
image:
type: string
scope: Namespaced
names:
plural: replicatedservices
singular: replicatedservice
kind: ReplicatedService
shortNames:
- rs
內容解密:
apiVersion和kind定義了 CRD 的基本資訊。metadata.name指定了 CRD 的名稱。spec.group和spec.versions定義了 CRD 的 API 群組和版本。spec.scope和spec.names設定了 CRD 的作用域和名稱。
擴充套件 Kubernetes 使用者經驗
新增資源到叢集中是一個很好的方法,但要真正利用它們,擴充套件 Kubernetes 的使用者經驗(UX)也是非常有用的。預設情況下,Kubernetes 工具不知道自訂資源和其他擴充套件,因此以非常通用和不友好的方式對待它們。擴充套件 Kubernetes 命令列可以提供更好的使用者經驗。
kubectl 外掛
kubectl 外掛是名稱為 kubectl-foo 的二進位檔案,當執行 kubectl foo 時,呼叫會被路由到外掛二進位檔案。使用 kubectl 外掛,可以定義新的體驗,讓開發人員更深入地瞭解新增的資源。
簡化容器化開發
在將應用程式佈署到 Kubernetes 之前,開發人員必須先容器化該應用程式。對於熟悉雲原生生態系統的人來說,構建容器是第二天性,但對於許多人來說,這是一項令人望而生畏的任務。
自動化工具
工具如 Draft 和 Skaffold 可以自動為特定的語言或開發環境生成 Dockerfile。
開發「Push-to-Deploy」體驗
許多 PaaS 產品最受歡迎的功能之一是「push to deploy」,即單次推播程式碼到 Git 儲存函式庫即可將應用程式佈署到雲端環境。現在,使用 CI/CD 解決方案如 GitHub Actions、Azure DevOps 等,可以輕鬆開發類別似的體驗。
自動化佈署流程
name: Build and Deploy
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push image
run: |
docker build -t myimage .
docker tag myimage ${{ secrets.DOCKER_USERNAME }}/myimage:latest
docker push ${{ secrets.DOCKER_USERNAME }}/myimage:latest
- name: Deploy to Kubernetes
uses: kubernetes/deploy-action@v1
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
command: |
kubectl apply -f deployment.yaml
內容解密:
name和on定義了 GitHub Actions 工作流程的名稱和觸發條件。jobs定義了工作流程中的任務。steps定義了任務中的步驟,包括簽出程式碼、登入 DockerHub、構建和推播映像,以及佈署到 Kubernetes。- 使用
${{ secrets.xxx }}存取儲存的機密資訊。
在 Kubernetes 上建構更高層級的應用程式平台的最佳實踐
結合 GitHub Actions 和 GitOps 可以使開發人員實作快速佈署,同時保持與雲原生生態系統和基礎設施即程式碼(IaC)等理念的一致性。
建構平台時的設計考量
無數的平台被建立以提高開發人員的生產力。透過觀察這些平台成功和失敗的經驗,可以總結出一套共同的模式和考量。遵循這些設計準則有助於確保所建構的平台是成功的,而不是最終需要擺脫的「遺留」僵局。
支援匯出到容器映像檔
許多平台設計透過允許使用者提供程式碼(如函式即服務(FaaS)中的函式)或原生套件(如 Java 中的 JAR 檔案),而不是完整的容器映像檔來提供簡便性。這種方法具有很大的吸引力,因為它讓使用者能夠保持在其熟悉的工具和開發經驗範圍內。平台會為他們處理應用程式的容器化。
然而,這種方法的問題在於,當開發人員遇到所提供的程式設計環境的限制時。可能是因為他們需要特定版本的語言執行環境來解決錯誤,或者需要封裝額外的資源或可執行檔,而這些並不是自動容器化應用程式的一部分。
無論原因為何,遇到這種情況對開發人員來說是一個糟糕的時刻,因為他們突然需要學習更多關於如何封裝應用程式的知識,而他們真正想要做的只是稍微擴充套件它以修復錯誤或交付新功能。
內容解密:
- 支援匯出容器映像檔的重要性:允許開發人員將平台的程式設計環境匯出到通用容器中,避免了從頭開始學習容器相關知識的需求。
- 增量學習的優勢:開發人員可以根據現有的容器映像檔進行小幅調整,以滿足其需求,從而平滑了從高層級平台到低層級基礎設施的過渡路徑。
- 提高平台的通用性:使用該平台並不會給開發人員帶來陡峭的學習曲線,從而增加了平台的通用性。
支援現有的服務和服務發現機制
另一個常見的平台故事是,它們會進化和與其他系統相互連線。許多開發人員可能在您的平台上非常滿意和高效,但任何真實世界的應用程式都會跨越您所構建的平台和更底層的 Kubernetes 應用程式,以及其他平台。與遺留資料函式庫或為 Kubernetes 構建的開源應用程式的連線將始終是足夠大的應用程式的一部分。
內容解密:
- 使用 Kubernetes 原始服務和服務發現機制:不要為了改善平台體驗而重新發明輪子,因為這樣做會建立一個無法與更廣泛的世界互動的「圍牆花園」。
- 將應用程式暴露為 Kubernetes 服務:叢集內的任何應用程式都可以消費您的應用程式,無論它們是否在您的更高層級平台上執行。
- 互連性的重要性:跨不同平台的互連性是任何足夠年齡和複雜性的應用程式的常見設計模式。建立「圍牆花園」將會是您後悔的決定。
建構應用程式平台的最佳實踐
雖然 Kubernetes 為操作軟體提供了強大的工具,但它對使開發人員能夠構建應用程式的關注較少。通常需要在 Kubernetes 上構建平台,以使開發人員更高效和/或使 Kubernetes 更易於使用。在構建這樣的平台時,請牢記以下最佳實踐:
- 使用准入控制器限制和修改對叢集的 API 呼叫。准入控制器可以驗證(並拒絕無效的)Kubernetes 資源。變異准入控制器可以自動修改 API 資源以新增新的 sidecar 或其他使用者可能不需要了解的變更。
- 使用
kubectl外掛程式擴充套件 Kubernetes 使用者經驗,新增新的工具到現有的命令列工具。在極少數情況下,專門構建的工具可能更合適。 - 在 Kubernetes 上構建平台時,仔細思考平台的使用者及其需求將如何演變。簡化事物並使其易於使用顯然是一個好目標,但如果這也會導致使用者被困住,無法在不重寫一切的情況下取得成功,那麼最終將是一種令人沮喪(且不成功)的體驗。