Kubernetes 提供 Namespace、Label 和 Annotation 等機制,有效組織和管理叢集內的資源。Namespace 將叢集物件劃分為邏輯單元,方便 RBAC 控制和資源隔離。Label 則以鍵值對形式標記物件,提供查詢和篩選功能,而 Annotation 則用於儲存非識別性後設資料。Deployment 物件實作應用程式的滾動更新,確保服務的持續可用性。Ingress 作為 HTTP 負載平衡器和路由器,根據路徑和主機名將流量導向不同 Service。StatefulSet 則專為有狀態應用程式設計,提供有序的副本建立和銷毀機制。此外,Job 和 ScheduledJob 負責批次任務的執行和排程,而 DaemonSet 則確保每個節點上執行特定 Pod。Kubernetes 架構採用宣告式組態和調和迴圈機制,實作系統的自我修復和自我糾正。透過 API 伺服器,各元件協同工作,維持叢集的穩定執行。
Kubernetes 的組織管理:Namespace、Label 和 Annotation
Kubernetes 提供多種機制來組織和管理叢集中的物件,包括 Namespace、Label 和 Annotation。這些機制使得叢集的管理變得更加容易和靈活。
Namespace:叢集物件的目錄
Namespace 可以被視為 Kubernetes API 物件的資料夾。它為大多數叢集物件提供了目錄結構,並可以為角色基礎的存取控制(RBAC)規則提供範圍。就像資料夾一樣,當你刪除一個 Namespace 時,其中的所有物件也會被銷毀,因此需要謹慎操作。每個 Kubernetes 叢集都有一個內建的 Namespace 名為 default,大多數 Kubernetes 安裝也包含一個名為 kube-system 的 Namespace,用於建立叢集管理容器。
Kubernetes 物件分為 namespaced 和 non-namespaced 物件,取決於它們是否可以被放置在 Namespace 中。大多數常見的 Kubernetes API 物件都是 namespaced 物件,但一些適用於整個叢集的物件(如 Namespace 物件本身或叢集級別的 RBAC)則不是。
除了組織 Kubernetes 物件之外,Namespace 也被用於建立 Service 的 DNS 名稱和提供給容器的 DNS 搜尋路徑。Service 的完整 DNS 名稱類別似於 my-service.svc.my-namespace.cluster.internal,這意味著不同 Namespace 中的兩個不同 Service 將具有不同的完整網域名稱(FQDN)。此外,每個容器的 DNS 搜尋路徑都包含 Namespace,因此對於 foo Namespace 中的容器,DNS 查詢 frontend 將被翻譯為 frontend.svc.foo.cluster.internal。
內容解密:
- Namespace 的作用:組織和管理叢集物件,提供 RBAC 範圍。
- 預設 Namespace:
default和kube-system。 - namespaced 和 non-namespaced 物件:區分物件是否屬於特定 Namespace。
Label 和 Label 查詢
Kubernetes API 中的每個物件都可以具有任意的 Label。Label 是字串鍵值對,有助於識別物件。例如,Label 可以是 "role": "frontend",表示該物件是前端服務。這些 Label 可以用於查詢和過濾 API 中的物件。例如,你可以請求 API 伺服器提供所有具有 role 為 backend 的 Pod 清單。這種請求稱為 Label 查詢或 Label 選擇器。許多 Kubernetes API 物件使用 Label 選擇器來識別它們所應用的物件集合。例如,Pod 可以具有節點選擇器,用於識別 Pod 可以在其上執行的節點集合(例如,具有 GPU 的節點)。同樣,Service 具有 Pod 選擇器,用於識別 Service 應該負載平衡流量的 Pod 集合。Label 和 Label 選擇器是 Kubernetes 將其物件鬆散耦合在一起的基本方式。
內容解密:
- Label 的定義:用於識別 Kubernetes 物件的字串鍵值對。
- Label 查詢:用於查詢和過濾具有特定 Label 的物件。
- Label 選擇器的應用:用於識別物件集合,如 Pod 和 Service。
Annotation:物件的註解
並非所有要分配給 API 物件的後設資料都是識別資訊。有些資訊只是關於物件本身的註解。因此,每個 Kubernetes API 物件也可以具有任意的 Annotation。這些 Annotation 可能包括顯示在物件旁邊的圖示或更改系統解釋物件的方式的修飾符。
實驗性或供應商特定的功能在 Kubernetes 中通常最初使用 Annotation 實作,因為它們不是正式 API 規範的一部分。在這些情況下,Annotation 本身應該帶有一些關於功能穩定性的概念(例如,beta.kubernetes.io/activate-some-beta-feature)。
內容解密:
- Annotation 的用途:為 Kubernetes 物件新增非識別性的後設資料。
- 實驗性功能的實作:使用 Annotation 實作尚未正式納入 API 的功能。
Kubernetes 核心物件詳解
Kubernetes 提供多種 API 物件來管理容器化應用程式的佈署、擴充套件和網路組態。這些物件包括 Deployment、Ingress 和 StatefulSet,分別用於不同的應用場景,確保應用程式的高用性和可擴充套件性。
Deployment:安全且可控的應用程式更新
Deployment 是 Kubernetes 中最常用的物件之一,用於管理應用程式的佈署和更新。它透過 ReplicaSet 來維護應用程式的多個副本,並在更新過程中確保應用的持續可用性。
當你要求 Deployment 更新應用程式映像檔(例如,從 v1 更新到 v2)時,它會建立一個新的 ReplicaSet(rs-v2),並逐步將流量從舊的 ReplicaSet(rs-v1)遷移到新的 ReplicaSet。這個過程稱為滾動更新(Rolling Update)。
滾動更新流程
- 建立新的 ReplicaSet:Deployment 建立一個新的 ReplicaSet(rs-v2),並啟動一個新的 Pod。
- 等待新的 Pod 變為健康狀態:Deployment 等待新的 Pod 變為健康狀態後,再繼續更新流程。
- 逐步減少舊的 Pod:Deployment 逐步減少舊的 ReplicaSet(rs-v1)中的 Pod 數量,同時增加新的 ReplicaSet(rs-v2)中的 Pod 數量。
- 持續更新直到完成:這個過程持續進行,直到所有舊的 Pod 都被新的 Pod 取代。
Deployment 提供了多種可調引數,以確保應用程式在更新過程中的穩定性和安全性。這使得 Deployment 成為現代 Kubernetes 叢集中最常用的物件之一。
Ingress:HTTP 載入平衡和路由
雖然 Service 物件提供了基本的 TCP 載入平衡功能,但它們無法提供應用層的載入平衡和路由功能。Ingress API 的引入正是為了滿足這方面的需求。
Ingress 代表了一個根據路徑和主機的 HTTP 載入平衡器和路由器。當你建立一個 Ingress 物件時,它會獲得一個虛擬 IP 位址,就像 Service 一樣。但是,Ingress 可以根據 HTTP 請求的內容將請求路由到不同的 Service。
Ingress 工作原理
假設我們有兩個 Kubernetes Service,分別命名為 “foo” 和 “bar”。我們可以建立一個 Ingress 物件,並將其 IP 位址與 foo.company.com 和 bar.company.com 的 DNS 名稱相關聯。在 Ingress 物件中,我們將兩個不同的主機名對映到兩個不同的 Kubernetes Service。
這樣,當收到 https://foo.company.com 的請求時,它會被路由到叢集中的 “foo” Service,同樣地,https://bar.company.com 的請求會被路由到 “bar” Service。Ingress 可以根據主機名或路徑進行路由,甚至可以同時根據兩者進行路由。
Ingress API 的靈活性
Ingress API 是 Kubernetes 中最解耦和最靈活的 API 之一。預設情況下,雖然 Kubernetes 會儲存 Ingress 物件,但當它們被建立時不會發生任何動作。相反,您需要在叢集中執行一個 Ingress Controller,以便在 Ingress 物件被建立時採取適當的動作。其中最流行的 Ingress Controller 是 nginx,但也有許多其他實作使用不同的 HTTP 載入平衡器或雲端或實體載入平衡器 API。
StatefulSet:有狀態應用的管理
大多數應用程式在水平擴充套件時可以正常運作,並且可以被視為相同的副本。但是,一些有狀態的應用程式,例如儲存工作負載或分片應用程式,需要在副本之間進行更多的區分。
StatefulSet 就是為瞭解決這個問題而引入的。與 ReplicaSet 類別似,StatefulSet 會建立多個相同的容器映像檔例項,但是它們的建立和銷毀順序是確定的,並且每個副本都有一個唯一的名稱。
StatefulSet 的特點
- 有序的副本名稱:StatefulSet 中的每個副本都有一個單調遞增的索引(例如,backend-0、backend-1 等)。
- 有序的建立和銷毀:StatefulSet 保證副本零會在副本一之前被建立並變為健康狀態。銷毀副本時,也是按照索引從高到低的順序進行。
- DNS 名稱:StatefulSet 中的每個副本都可以直接透過 DNS 名稱進行存取,這使得客戶端可以輕鬆地定位特定的分片。
StatefulSet 為有狀態的應用程式提供了更強的管理能力,使得它們可以更容易地進行擴充套件和管理。
Kubernetes 中的批次工作負載:Job 與 ScheduledJob
在 Kubernetes 中,除了有狀態的工作負載之外,還有一類別特殊的工作負載被稱為批次或一次性工作負載。與之前討論的工作負載不同,這些工作負載並非持續提供服務。相反,它們執行某些計算任務,任務完成後即被銷毀。
Job:定義與運作機制
在 Kubernetes 中,Job 代表了一組需要執行的任務。與 ReplicaSets 和 StatefulSets 類別似,Job 透過建立 Pod 來執行工作,Pod 執行容器映像。然而,與 ReplicaSets 和 StatefulSets 不同,由 Job 建立的 Pod 只會執行直到完成並離開。一個 Job 包含它所建立的 Pod 的定義、Job 應該執行的次數,以及最大平行建立的 Pod 數量。例如,一個具有 100 次重複和最大平行度為 10 的 Job 將同時執行 10 個 Pod,當舊的 Pod 完成時建立新的 Pod,直到成功執行了 100 次容器映像。
ScheduledJob:定時任務的擴充套件
ScheduledJob 在 Job 物件的基礎上增加了排程功能。一個 ScheduledJob 包含了想要建立的 Job 物件的定義,以及應該建立該 Job 的排程計劃。這使得使用者可以根據特定的時間表來執行 Job。
叢集代理與實用工具:DaemonSet
許多人在遷移到 Kubernetes 時會問:“如何執行我的機器代理?”代理的任務包括入侵檢測、日誌記錄和監控等。許多人嘗試使用非 Kubernetes 的方法來啟用這些代理,例如新增新的 systemd 單元檔案或初始化指令碼。雖然這些方法可以工作,但它們有幾個缺點。首先,Kubernetes 不會將代理的活動納入叢集中使用的資源會計中。其次,容器映像和 Kubernetes API 用於健康檢查、監控等,不能應用於這些代理。幸運的是,Kubernetes 為使用者提供了 DaemonSet API,以便在叢集中安裝這類別代理。
DaemonSet 的工作原理
DaemonSet 提供了一個 Pod 的範本,該 Pod 應該在每台機器上執行。當建立一個 DaemonSet 時,Kubernetes 確保這個 Pod 在叢集中的每個節點上執行。如果稍後增加了一個新的節點,Kubernetes 也會在該節點上建立一個 Pod。雖然預設情況下 Kubernetes 在叢集中的每個節點上放置一個 Pod,但 DaemonSet 也可以提供一個節點選擇器標籤查詢,Kubernetes 只會將 DaemonSet 的 Pod 放置在與該標籤查詢比對的節點上。
Kubernetes 架構
儘管 Kubernetes 的目的是使佈署和管理分散式系統變得更容易,但 Kubernetes 本身也是一個需要管理的分散式系統。要做到這一點,開發人員需要對系統架構、系統中每個部分的角色以及它們如何協同工作有深入的瞭解。
概念
要了解 Kubernetes 的架構,首先對控制其開發的概念和設計原則有良好的理解是非常有幫助的。儘管系統看起來相當複雜,但它實際上是根據相對較少的概念,這些概念在整個系統中重複出現。這使得 Kubernetes 能夠增長,同時仍然對開發人員保持可接近性。瞭解系統中的一個元件通常可以直接應用於其他元件。
宣告式組態
宣告式組態的概念——使用者宣告所需的世界狀態以產生結果——是 Kubernetes 開發背後的主要驅動力之一。例如,使用者可能會對 Kubernetes 說:“我希望始終有五個我的 Web 伺服器的副本在執行。”Kubernetes 反過來接受這個宣告式宣告,並負責確保它是真的。不幸的是,Kubernetes 無法理解自然語言指令,因此該宣告實際上是以結構化的 YAML 或 JSON 檔案的形式出現的。
宣告式組態與命令式組態的區別
宣告式組態與命令式組態不同,在命令式組態中,使用者採取一系列直接的操作(例如,建立他們想要執行的五個副本)。命令式操作通常更容易理解——人們可以簡單地說“執行這個”,而不是使用更複雜的宣告式語法。然而,宣告式組態提供了更大的靈活性和可擴充套件性,使其成為管理複雜系統如 Kubernetes 的理想選擇。
Kubernetes 架構的設計理念
Kubernetes 的宣告式(declarative)方法賦予系統自主運作的能力,使其能夠在無需使用者持續干預的情況下實作自我修復和自我糾正。這對於開發者而言至關重要,因為系統可以在不需要人工介入的情況下自動修復問題。
調和迴圈(Reconciliation Loop)或控制器(Controllers)
Kubernetes 的設計根據大量獨立的調和迴圈或控制迴圈,這些迴圈不斷觀察系統的當前狀態,並將其與期望狀態進行比較,然後採取必要的措施使系統的當前狀態與期望狀態保持一致。這種設計模式使 Kubernetes 更加靈活和穩定。
單體式與分散式設計
在系統設計中,通常有兩種不同的方法:單體式(monolithic)和分散式(decentralized)。單體式設計將系統的整體狀態納入考量,並以此為基礎進行協調運作。雖然這種方法易於理解,但其穩定性較差,一旦出現意外情況,整個系統可能會當機。Kubernetes 採用的是分散式設計,將控制權分散到多個獨立的控制器中,每個控制器負責系統的一小部分,並執行獨立的調和迴圈。這種方法雖然使得系統的整體行為更難理解,但大大提高了系統的穩定性。
調和迴圈的工作原理
調和迴圈的基本步驟如下圖所示(此圖示):
- 取得系統的期望狀態。
- 觀察系統的當前狀態。
- 找出觀察到的狀態與期望狀態之間的差異。
- 採取措施使系統的當前狀態與期望狀態保持一致。
簡單的例子:家中的恆溫器
恆溫器的工作原理是調和迴圈的一個簡單例子。它有一個期望狀態(設定的溫度),觀察當前溫度,找出差異,然後透過加熱或冷卻來使實際溫度與期望溫度保持一致。
Kubernetes 中的控制器
Kubernetes 中的控制器以類別似的方式運作。它們透過 Kubernetes API 伺服器取得系統的期望狀態。例如,使用者可能宣告希望有四個某個 web 伺服器的副本。Kubernetes 的副本控制器(replication controller)觀察到目前只有三個副本,於是找出差異並建立第四個副本以使當前狀態與期望狀態保持一致。
標籤和標籤查詢的作用
要管理這種宣告式狀態,需要確定調和控制迴圈應該關注的物件集合。這就是 Kubernetes 設計中標籤(labels)和標籤查詢(label queries)的作用所在。
隱式或動態分組
在 Kubernetes 的實作中,無論是將一組副本聚集在一起還是識別負載平衡器的後端,都需要識別出一組事物。在分組時,有兩種可能的方法:顯式/靜態分組和隱式/動態分組。靜態分組使用一個具體的列表來定義組成員,列表中的成員是明確指定的。然而,這種方法缺乏彈性,無法應對動態變化的情況。Kubernetes 使用的是動態分組,透過標籤和標籤查詢來動態地識別和管理組成員,這種方法提供了更大的靈活性。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Kubernetes 核心物件與架構設計詳解
package "Kubernetes Cluster" {
package "Control Plane" {
component [API Server] as api
component [Controller Manager] as cm
component [Scheduler] as sched
database [etcd] as etcd
}
package "Worker Nodes" {
component [Kubelet] as kubelet
component [Kube-proxy] as proxy
package "Pods" {
component [Container 1] as c1
component [Container 2] as c2
}
}
}
api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2
note right of api
核心 API 入口
所有操作經由此處
end note
@enduml此圖示展示了一個通用的調和迴圈。
內容解密:
此圖示展示了調和迴圈的基本步驟。首先,系統取得期望狀態;然後觀察當前狀態;接著找出兩者之間的差異;最後採取必要的措施使當前狀態與期望狀態保持一致。這個過程不斷重複,以確保系統始終處於期望的狀態。
Kubernetes 架構設計概念與實作
Kubernetes 採用動態群組管理方式,透過標籤(labels)與標籤查詢(label selectors)實作靈活的群組定義。與傳統靜態群組不同,Kubernetes 的群組定義是隱式的,不需要明確列出成員,而是透過評估物件屬性來動態決定群組成員。
隱式群組定義的優勢
隱式群組定義提供了更高的彈性與穩定性,能夠適應不斷變化的環境。例如,當系統中的物件屬性發生變化時,群組成員會自動更新,無需手動調整靜態列表。
標籤與註解的區別
在 Kubernetes 中,每個 API 物件都可以擁有多個鍵值對形式的標籤(labels)。標籤可用於查詢和識別物件。另一方面,註解(annotations)則用於儲存物件的一般元資料,這些元資料不代表物件的身份識別,例如圖形介面顯示的圖示等。
Kubernetes 設計原則
Kubernetes 的設計遵循 Unix 哲學,強調模組化和小型元件的組合。系統由多個獨立的應用程式組成,各元件透過 API 伺服器進行互動,而非直接在執行程式中通訊。這種模組化設計使得 Kubernetes 具有高度的靈活性,可以方便地替換或升級個別元件。
API 驅動的互動
Kubernetes 的元件互動完全由 API 驅動,所有元件使用相同的 API。這意味著任何元件都可以被替換或擴充套件,而不會影響系統的核心架構。同時,API 的版本控制機制有助於減少版本不一致(version skew)帶來的問題,提高系統的穩定性。
元件分類別
Kubernetes 的元件可以分為三類別:
Head Node Components(控制平面節點元件):執行在控制平面節點上,實作 Kubernetes 的核心功能,如 etcd 和 API 伺服器。
- 控制平面節點通常為奇數個(1、3 或 5),以便使用 Raft/Paxos 演算法保持共識。
所有節點上執行的元件:包括 worker 節點和 head 節點上都需要的元件。
排程到叢集上的元件:這些元件作為 Kubernetes 工作負載的一部分執行,但它們實作了 Kubernetes API 的一部分功能。
控制平面節點元件
控制平面節點是 Kubernetes 叢集的大腦,包含實作 Kubernetes API 功能的核心元件。通常,只有這些元件執行在控制平面節點上,不會與使用者容器共用這些節點。