Kubernetes 提供多種服務發現機制,讓外部能存取叢集內服務。本文詳細介紹 NodePort、LoadBalancer 和 Ingress,並比較其差異及使用情境。此外,也說明 OpenShift 的 Routes 與 Kubernetes Ingress 的異同,並探討 Downward API 如何讓應用程式感知自身狀態與環境資訊。最後,文章介紹了初始化容器模式,讓開發者能在應用程式啟動前執行必要設定,提升佈署的彈性與安全性。這些技術有助於開發者更有效率地管理 Kubernetes 應用程式,並建構更穩健的雲端原生架構。
Kubernetes 服務發現機制詳解
Kubernetes 提供了多種服務發現機制,讓外部客戶端能夠存取叢集內的服務。本文將探討 NodePort、LoadBalancer 和 Ingress 三種主要的服務發現機制,並分析其特點和適用場景。
NodePort 服務發現
NodePort 是一種簡單的服務發現機制,它在每個節點上開放一個固定的連線埠,讓外部客戶端能夠存取服務。
特點分析
- 連線埠選擇:可以指定固定的連線埠(例如
nodePort: 30036),也可以讓 Kubernetes 自動選擇一個可用的連線埠。 - 防火牆規則:由於需要在所有節點上開放連線埠,因此可能需要設定額外的防火牆規則。
- 節點選擇:外部客戶端可以連線到叢集中的任意節點,但需要自行處理節點容錯移轉。
- Pod 選擇:當客戶端透過
NodePort連線時,Kubernetes 會將流量路由到隨機選擇的 Pod。
程式碼範例
apiVersion: v1
kind: Service
metadata:
name: random-generator
spec:
type: NodePort
selector:
app: random-generator
ports:
- port: 8080
targetPort: 8080
nodePort: 30036
protocol: TCP
內容解密
type: NodePort指定服務型別為NodePort。selector指定服務要路由到的 Pod 標籤。ports指定服務的連線埠組態,包括port、targetPort和nodePort。
LoadBalancer 服務發現
LoadBalancer 是一種更進階的服務發現機制,它利用雲端供應商的負載平衡器來暴露服務。
特點分析
- 自動建立負載平衡器:Kubernetes 會自動建立一個負載平衡器,並將流量路由到後端的 Pod。
- IP 位址管理:Kubernetes 會管理負載平衡器的 IP 位址,並將其更新到服務的
status欄位中。
程式碼範例
apiVersion: v1
kind: Service
metadata:
name: random-generator
spec:
type: LoadBalancer
selector:
app: random-generator
ports:
- port: 80
targetPort: 8080
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
內容解密
type: LoadBalancer指定服務型別為LoadBalancer。selector指定服務要路由到的 Pod 標籤。ports指定服務的連線埠組態,包括port和targetPort。status欄位顯示負載平衡器的 IP 位址。
Ingress 服務發現
Ingress 是一種更靈活的服務發現機制,它允許將多個服務暴露在同一個 IP 位址下,並根據 HTTP 路徑進行路由。
特點分析
- 多服務支援:可以將多個服務暴露在同一個 IP 位址下,並根據 HTTP 路徑進行路由。
- L7 負載平衡:支援 L7 負載平衡,可以根據 HTTP 請求的內容進行路由。
程式碼範例
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: random-generator
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: random-generator
servicePort: 8080
- path: /cluster-status
backend:
serviceName: cluster-status
servicePort: 80
內容解密
kind: Ingress指定資源型別為Ingress。rules指定 Ingress 的路由規則。http指定 HTTP 路由規則。paths指定 HTTP 路徑和對應的後端服務。
OpenShift 路由(Routes)與 Kubernetes 服務探索
Red Hat OpenShift 是廣泛使用的企業級 Kubernetes 發行版,除了完全相容於 Kubernetes 外,還提供了額外的功能。其中一個重要的功能是「路由(Routes)」,與 Kubernetes 的「Ingress」非常相似。事實上,兩者的差異可能難以察覺。首先,Routes 的概念早於 Kubernetes 中的 Ingress 物件出現,因此可以視為 Ingress 的前身。不過,Routes 和 Ingress 之間仍然存在一些技術上的差異。
Routes 與 Ingress 的主要差異
- 自動化負載平衡:Route 會被 OpenShift 整合的 HAProxy 負載平衡器自動擷取,因此不需要額外安裝 Ingress 控制器。
- TLS 終止模式:支援額外的 TLS 終止模式,例如重新加密(re-encryption)或直通(pass-through)至服務。
- 流量分配:支援多個加權後端,用於分配流量。
- 萬用網域支援:支援萬用網域。
儘管如此,在 OpenShift 中也可以使用 Ingress。因此,使用者在使用 OpenShift 時有選擇的餘地。
表 13-1:服務探索機制
| 名稱 | 組態 | 使用者端型別 | 總結 |
|---|---|---|---|
| ClusterIP | type: ClusterIP, .spec.selector | 內部 | 最常見的內部探索機制 |
| 手動 IP | type: ClusterIP, kind: Endpoints | 內部 | 外部 IP 探索 |
| FQDN | type: ExternalName, .spec.externalName | 內部 | 外部 FQDN 探索 |
| 無頭服務 | type: ClusterIP, .spec.clusterIP: None | 內部 | 無虛擬 IP 的 DNS 探索 |
| NodePort | type: NodePort | 外部 | 非 HTTP 流量的首選 |
| LoadBalancer | type: LoadBalancer | 外部 | 需要支援的雲端基礎設施 |
| Ingress | kind: Ingress | 外部 | L7/HTTP 智慧路由機制 |
本章對 Kubernetes 中存取和探索服務的核心概念進行了全面概述。然而,旅程並未就此結束。Knative 專案在 Kubernetes 之上引入了新的原語,幫助應用程式開發人員實作先進的服務和事件處理。在服務探索模式的背景下,Knative Serving 子專案尤其值得關注,因為它引入了一個新的 Service 資源,與本文介紹的 Service 具有相同的種類別(但屬於不同的 API 群組)。Knative Serving 不僅支援應用程式修訂,還支援在負載平衡器後方的服務進行非常靈活的擴充套件。
自我感知(Self Awareness)
某些應用程式需要具備自我感知能力,並需要有關自身的資訊。自我感知模式描述了 Kubernetes 的向下 API(downward API),它提供了一種簡單的機制,用於對應用程式進行自省和後設資料注入。
問題
對於大多數使用案例,雲原生應用程式是無狀態且可丟棄的,沒有與其他應用程式相關的身份。然而,有時即使是這些型別的應用程式也需要有關自身和執行環境的資訊。這可能包括僅在執行時才知道的資訊,例如 Pod 名稱、Pod IP 位址和應用程式所在的主機名稱。或者,其他靜態資訊是在 Pod 級別定義的,例如特定的資源請求和限制,或者一些動態資訊,如註解和標籤,可以在執行時由使用者更改。
例如,根據容器的可用資源,您可能希望調整應用程式的執行緒池大小,或更改垃圾收集演算法或記憶體分配。您可能希望在記錄資訊時或將指標傳送到中央伺服器時使用 Pod 名稱和主機名稱。您可能希望探索同一名稱空間中具有特定標籤的其他 Pod,並將它們加入叢集應用程式中。對於這些和其他使用案例,Kubernetes 提供了向下 API。
解決方案
我們描述的需求和以下解決方案不僅特定於容器,也存在於任何動態環境中,資源的中繼資料會發生變化。例如,AWS 提供例項中繼資料和使用者資料服務,可以從任何 EC2 例項查詢以檢索有關 EC2 例項本身的中繼資料。同樣,AWS ECS 提供 API,可以由容器查詢以檢索有關容器叢集的資訊。
Kubernetes 的方法更加優雅且易於使用。向下 API 允許您透過環境變數和檔案將有關 Pod 的中繼資料傳遞給容器和叢集。這些機制與我們用於從 ConfigMaps 和 Secrets 傳遞應用程式相關資料的機制相同。但在這種情況下,資料不是由我們建立的。相反,我們指定感興趣的鍵,Kubernetes 會動態填充值。圖 14-1 給出了向下 API 如何將資源和執行時資訊注入感興趣的 Pod 的概述。
圖 14-1:應用程式自省機制
這裡的主要觀點是,透過向下 API,中繼資料被注入到您的 Pod 中並在本地可用。應用程式不需要使用客戶端並與 Kubernetes API 互動,可以保持無狀態。
使用 Plantuml 圖表示範向下 API 的工作原理
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 使用 Plantuml 圖表示範向下 API 的工作原理
rectangle "提供中繼資料" as node1
rectangle "注入中繼資料" as node2
rectangle "使用中繼資料" as node3
node1 --> node2
node2 --> node3
@enduml
此圖示說明瞭 Kubernetes API 如何透過向下 API 將中繼資料提供給 Pod,並最終供應用程式使用。
#### 內容解密:
此 Plantuml 圖表呈現了向下 API 的基本工作流程。首先,Kubernetes API 提供必要的中繼資料。接著,向下 API 將這些中繼資料注入到 Pod 中。最後,Pod 中的應用程式可以使用這些中繼資料來調整其行為或進行其他操作。這種機制使得應用程式能夠在不直接與 Kubernetes API 互動的情況下獲得必要的資訊,從而保持了應用的無狀態特性並簡化了開發過程。
Kubernetes 中的 Downward API:容器內取得 Pod 資訊的非侵入式方法
在 Kubernetes 環境中,應用程式往往需要了解自身執行的環境以及相關的後設資料(metadata)。為了滿足這一需求,Kubernetes 提供了 Downward API,允許容器在不依賴外部服務的情況下,取得 Pod 的相關資訊。
透過環境變數取得 Pod 資訊
Kubernetes 允許透過環境變數將 Pod 的 metadata 注入到容器中。以下是一個範例(Example 14-1),展示瞭如何使用環境變數取得 Pod 的 IP 地址和記憶體限制:
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
containerName: random-generator
resource: limits.memory
內容解密:
POD_IP環境變數被設定為 Pod 的 IP 地址,這是在 Pod 啟動時由 Kubernetes 自動注入的。MEMORY_LIMIT環境變數被設定為容器的記憶體限制,這是透過resourceFieldRef取得的。fieldRef用於存取 Pod 級別的 metadata,例如 Pod IP、名稱、名稱空間等。resourceFieldRef用於存取容器級別的資源設定,例如 CPU 和記憶體的請求與限制。
透過 Volume 掛載 Pod 資訊
除了環境變數,Kubernetes 也允許透過 Volume 將 Pod 的 metadata 掛載到容器內的檔案中。以下是一個範例(Example 14-2):
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
volumeMounts:
- name: pod-info
mountPath: /pod-info
volumes:
- name: pod-info
downwardAPI:
items:
- path: labels
fieldRef:
fieldPath: metadata.labels
- path: annotations
fieldRef:
fieldPath: metadata.annotations
內容解密:
downwardAPIVolume 被掛載到/pod-info目錄下。labels檔案包含了 Pod 的所有標籤(labels),以name=value的格式列出。annotations檔案包含了 Pod 的所有註解(annotations),格式與 labels 相同。- 當 Pod 的 metadata 發生變化時,掛載的檔案內容會被更新,但應用程式需要自行偵測檔案變化並讀取更新後的資料。
Downward API 的優缺點
Downward API 提供了一種非侵入式的方式,讓容器能夠取得 Pod 的相關資訊。然而,它也有一些限制:
- Downward API 只能提供有限的 metadata,如果應用程式需要更多的資訊,就需要直接查詢 Kubernetes API Server。
- 環境變數在 Pod 啟動時被設定,如果 metadata 發生變化,環境變數不會自動更新。
- 使用 Volume 掛載的檔案可以反映 metadata 的變化,但應用程式需要實作對檔案變化的監控。
更多資訊
- Self Awareness Example
- AWS EC2: Instance Metadata and User Data
- Expose Pod Information to Containers Through Files
- Expose Pod Information to Containers Through Environment Variables
- Downward API: Available Fields
結構模式:組織容器滿足不同使用案例
在物件導向的世界中,容器映像檔和容器就像類別和物件一樣。容器映像檔是例項化容器的藍圖。這些容器並非獨立執行,而是執行在稱為 Pod 的抽象層中,並與其他容器互動。以下章節將介紹用於組織和管理 Pod 中的容器的模式,以滿足不同的使用案例。
相關章節
- 第 15 章:Init Container,用於初始化相關任務的生命週期,與主應用程式職責分離。
- 第 16 章:Sidecar,用於擴充套件和增強現有容器的功能,而不改變它。
- 第 17 章:Adapter,將異構系統轉換為一致的統一介面,供外部世界使用。
- 第 18 章:Ambassador,用於描述代理如何解耦對外部服務的存取。
這些章節將探討結構模式,以幫助開發者更好地組織和管理容器化應用程式。
初始化容器模式:提升 Kubernetes 應用佈署的靈活性與安全性
初始化容器(Init Container)是 Kubernetes 中的一個基本概念,它允許在主應用容器啟動之前執行初始化任務,從而實作關注點的分離。在本章中,我們將探討這一模式,並瞭解它如何在各種需要初始化邏輯的場景中發揮作用。
問題背景
在許多程式語言中,初始化是一個常見的需求。有些語言透過內建機制來處理初始化,而其他語言則依賴命名約定或設計模式來實作。例如,在 Java 中,建構子(Constructor)用於初始化物件,並確保在物件建立時執行必要的設定。初始化容器與此類別似,但它是在 Pod 層級運作,而非類別層級。
初始化容器的應用場景
在 Kubernetes 中,如果一個 Pod 中有多個容器代表主應用程式,這些容器可能需要在啟動前滿足某些先決條件,例如檔案系統的特殊許可權設定、資料函式庫結構的建立或應用程式種子資料的安裝。此外,初始化邏輯可能需要特定的工具或函式庫,而這些不適合包含在應用程式映像檔中。出於安全考慮,應用程式映像檔可能不具備執行初始化任務的許可權。初始化容器提供瞭解決這些問題的方法。
初始化容器的運作機制
在 Kubernetes 中,初始化容器是 Pod 定義的一部分,它們將 Pod 中的所有容器分為兩類別:初始化容器和應用容器。所有初始化容器按照順序依次執行,並且必須全部成功終止後,應用容器才會啟動。這種機制類別似於 Java 類別中的建構指令,用於幫助物件的初始化。
初始化容器的特性
初始化容器與應用容器分享相同的資源限制、儲存卷和安全設定,並且位於相同的節點上。然而,它們的生命週期、健康檢查和資源處理語義略有不同。初始化容器沒有 livenessProbe、readinessProbe 或 startupProbe,因為它們必須成功終止後,Pod 的啟動過程才能繼續。
資源需求計算
初始化容器會影響 Pod 資源需求的計算,包括排程、自動擴充套件和配額管理。Pod 級別的請求和限制值取決於初始化容器的最高請求/限制值和所有應用容器的請求/限制值總和。這種機制可能導致資源利用效率不高的情況,例如當初始化容器的資源需求遠高於應用容器時。
範例解析
以下是一個具體的範例,展示瞭如何使用初始化容器來克隆 Git 倉函式庫並將資料複製到共用的儲存卷中,然後由應用容器提供 HTTP 服務。
apiVersion: v1
kind: Pod
metadata:
name: www
labels:
app: www
spec:
initContainers:
- name: download
image: axeclbr/git
command:
- git
- clone
- https://github.com/mdn/beginner-html-site-scripted
- /var/lib/data
volumeMounts:
- mountPath: /var/lib/data
name: data-volume
containers:
- name: webserver
image: nginx:alpine
volumeMounts:
- mountPath: /usr/share/nginx/html
name: data-volume
volumes:
- name: data-volume
emptyDir: {}
內容解密:
- 初始化容器組態:範例中定義了一個名為
download的初始化容器,使用axeclbr/git映像檔執行 Git 克隆操作,將倉函式庫內容下載到/var/lib/data目錄。 - 共用儲存卷:初始化容器和應用容器都掛載了名為
data-volume的儲存卷,實作了資料的共用。 - 應用容器組態:名為
webserver的應用容器使用nginx:alpine映像檔,提供 HTTP 服務,並將/var/lib/data中的內容作為網頁內容提供給客戶端。 - 儲存卷定義:使用
emptyDir卷型別建立了一個臨時儲存卷,用於在 Pod 的生命週期內共用資料。