Kubernetes 服務暴露是將應用程式服務釋出到叢集外部的關鍵機制。NodePort 提供簡單的連線埠轉發,LoadBalancer 則整合雲端供應商的負載平衡功能,而 ExternalName 則用於連線到外部服務。理解這些服務型別對於構建穩健且可擴充套件的 Kubernetes 應用程式至關重要。除了服務型別,Ingress 控制器也扮演著重要的角色,它作為第七層負載平衡器,可以根據網域名稱或 URL 路徑將流量路由到不同的服務。在沒有 DNS 伺服器的情況下,nip.io 提供了一種便捷的網域名稱解析方案,方便開發者在本地測試 Ingress 規則。最後,MetalLB 作為一個功能強大的 Layer 4 負載平衡器,可以與 Ingress 控制器配合使用,提供更完善的流量管理和負載平衡解決方案。
Kubernetes 服務暴露:NodePort、LoadBalancer 與 ExternalName 服務型別解析
在 Kubernetes 中,服務(Service)扮演著將應用程式暴露給外部請求的重要角色。本文將探討三種主要的服務型別:NodePort、LoadBalancer 和 ExternalName,並分析其使用場景、優缺點及實作細節。
NodePort 服務型別
NodePort 是一種將服務暴露給叢集外部的簡單方法。它在每個節點上開啟一個特定的連線埠,將流量轉發到對應的 Pod。
NodePort 的運作原理
當建立一個 NodePort 服務時,Kubernetes 會在每個節點上開啟一個指定的連線埠(NodePort)。外部請求可以透過任何一個節點的 IP 地址加上 NodePort 連線埠來存取服務。Kubernetes 會自動將流量轉發到對應的 Pod。
apiVersion: v1
kind: Service
metadata:
name: nginx-frontend
spec:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443
type: NodePort
NodePort 的優缺點
優點:
- 簡單易用,無需額外的基礎設施支援。
- 可以快速將服務暴露給外部請求。
缺點:
- NodePort 的連線埠號是隨機分配的,如果服務被刪除並重新建立,連線埠號可能會改變。
- 需要記住每個服務對應的 NodePort 連線埠號,容易造成混淆。
- 如果目標節點離線或故障,請求將會失敗。
LoadBalancer 服務型別
LoadBalancer 是一種將服務暴露給外部請求的高階方法。它需要一個外部的 LoadBalancer 元件來支援,通常由雲端供應商提供。
LoadBalancer 的運作原理
當建立一個 LoadBalancer 服務時,Kubernetes 會向外部的 LoadBalancer 元件請求一個外部 IP 地址,並將流量轉發到對應的 Pod。
LoadBalancer 的優缺點
優點:
- 提供了一個外部 IP 地址,可以直接被外部請求存取。
- 負載平衡功能可以提高服務的可用性和擴充套件性。
缺點:
- 需要外部的 LoadBalancer 元件支援,通常需要雲端供應商提供。
- 在本地叢集中,可能無法正常運作,因為缺乏必要的基礎設施支援。
ExternalName 服務型別
ExternalName 是一種特殊的服務型別,它將一個外部的 DNS 名稱對映到一個 Kubernetes 服務名稱。
ExternalName 的運作原理
當建立一個 ExternalName 服務時,Kubernetes 會建立一個 DNS 記錄,將服務名稱對映到外部的 DNS 名稱。
apiVersion: v1
kind: Service
metadata:
name: sql-db
namespace: finance
spec:
type: ExternalName
externalName: sqlserver1.foowidgets.com
ExternalName 的優缺點
優點:
- 可以將外部服務整合到 Kubernetes 的 DNS 系統中。
- 可以簡化應用程式的組態,避免硬編碼外部服務的 DNS 名稱。
缺點:
- 需要小心處理 SSL/TLS 證書驗證問題,因為外部服務的 DNS 名稱可能與證書上的名稱不匹配。
- 需要額外的組態和管理,以確保 ExternalName 服務的正確運作。
Kubernetes 中的服務、負載平衡與外部 DNS
在 Kubernetes 中,要實作服務的外部存取,需要使用服務(Service)和負載平衡(Load Balancer)。本章節將介紹如何使用服務和負載平衡來暴露 Kubernetes 中的應用程式。
刪除 ExternalName 服務並建立新服務
要實作第二個目標,請按照以下步驟進行:
- 刪除
ExternalName服務。 - 建立一個新的服務,使用名稱
ext-sql-db,並使用app=sql-app作為選擇器。該服務的 YAML 清單如下所示:
apiVersion: v1
kind: Service
metadata:
labels:
app: sql-db
name: sql-db
namespace: finance
spec:
ports:
- port: 1433
protocol: TCP
targetPort: 1433
name: sql
selector:
app: sql-app
type: ClusterIP
內容解密:
此 YAML 清單定義了一個名為 sql-db 的服務,該服務選擇標籤為 app=sql-app 的 Pod,並將流量轉發到這些 Pod 的 1433 埠。由於我們使用相同的服務名稱,因此應用程式無需進行任何更改。
負載平衡簡介
在討論不同型別的負載平衡之前,瞭解 OSI 模型(開放式系統互連模型)非常重要。OSI 模型是一個七層模型,每層提供不同的功能。
OSI 模型的七層
| 層級 | 名稱 | 描述 |
|---|---|---|
| 1 | 物理層 | 定義物理裝置之間的連線 |
| 2 | 資料鏈路層 | 提供錯誤檢測和糾正 |
| 3 | 網路層 | 路由資料包 |
| 4 | 傳輸層 | 提供可靠的資料傳輸 |
| 5 | 會話層 | 建立和管理會話 |
| 6 | 表示層 | 提供資料表示和轉換 |
| 7 | 應用層 | 提供應用程式之間的通訊 |
對於本章節,我們關注的是第 4 層和第 7 層。
- 第 4 層:負責裝置之間的通訊流量,提供 TCP/UDP 資訊。根據第 4 層的負載平衡器提供應用程式服務於任何 TCP/UDP 埠的能力。
- 第 7 層:負責為應用程式提供網路服務,例如 HTTP 和 HTTPS。
第 7 層負載平衡器
Kubernetes 提供第 7 層負載平衡器,以 Ingress 控制器的形式出現。有多種解決方案可以為叢集提供 Ingress 功能,包括 NGINX、Envoy、Traefik 和 HAProxy。
使用 NGINX 作為 Ingress 控制器
NGINX 可以用作 Kubernetes 的 Ingress 控制器,用於路由傳入的 HTTP/HTTPS 請求到暴露的服務。
名稱解析和第 7 層負載平衡器
要處理 Kubernetes 叢集中的第 7 層流量,需要佈署 Ingress 控制器。Ingress 控制器依賴傳入的名稱來路由流量到正確的服務。
示例:使用泛網域名稱進行 Ingress
假設我們的公司名為 FooWidgets,我們有三個 Kubernetes 叢集,前端由外部負載平衡器和多個 Ingress 控制器的端點組成。我們的 DNS 伺服器將為每個叢集建立一個泛網域名稱,指向負載平衡器的虛擬 IP 地址。
| 叢集名稱 | 泛網域名稱 |
|---|---|
| cluster1 | *.cluster1.foowidgets.com |
| cluster2 | *.cluster2.foowidgets.com |
| cluster3 | *.cluster3.foowidgets.com |
下圖顯示了請求的整個流程: 圖表翻譯: 此圖表顯示了使用者請求到達 Kubernetes 叢集中的服務的整個流程。首先,使用者傳送請求到 DNS 伺服器,DNS 解析後將請求轉發到負載平衡器。然後,負載平衡器將請求轉發到 Ingress 控制器,最後由 Ingress 控制器將請求路由到正確的服務。
- 使用者使用瀏覽器請求 URL
https://timesheets.cluster1.foowidgets.com。 - DNS 查詢被髮送到 DNS 伺服器。DNS 伺服器查詢
cluster1.foowidgets.com的區域詳細資訊。在 DNS 區域中,有一個條目解析為負載平衡器的虛擬 IP 地址。 - 負載平衡器的虛擬 IP 地址有三個後端伺服器,指向佈署了 Ingress 控制器的三個工作節點。
- 使用其中一個端點,將請求傳送到 Ingress 控制器。
- Ingress 控制器將請求的 URL 與 Ingress 規則列表進行比較。當找到匹配的請求時,Ingress 控制器將請求轉發到分配給 Ingress規則的服務。
使用 nip.io 進行名稱解析
大多數個人開發叢集,如 KinD 安裝,可能沒有足夠的許可權來新增記錄到 DNS 伺服器。為了測試 Ingress 規則,我們需要針對對映到 Kubernetes 服務的唯一主機名稱。沒有 DNS 伺服器的情況下,您需要在本地主機檔案中新增多個名稱,指向 Ingress 控制器的 IP 位址。
舉例來說,如果您佈署了四個網頁伺服器,您需要在本地主機檔案中新增所有四個名稱,如下所示:
192.168.100.100 webserver1.test.local
192.168.100.100 webserver2.test.local
192.168.100.100 webserver3.test.local
192.168.100.100 webserver4.test.local
也可以將其表示在一行中,而不是多行:
192.168.100.100 webserver1.test.local webserver2.test.local webserver3.test.local webserver4.test.local
如果您使用多台機器來測試您的佈署,您需要在每台計劃用於測試的機器上編輯主機檔案。在多台機器上維護多個檔案是一項管理噩夢,並將導致使測試成為挑戰的問題。
幸運的是,有免費服務可用,提供 DNS 服務,我們可以在不為 KinD 叢集組態複雜 DNS 基礎架構的情況下使用。Nip.io 是我們將用於 KinD 叢集名稱解析需求的服務。
nip.io 的工作原理
使用前面的網頁伺服器範例,我們不需要建立任何 DNS 記錄。我們仍然需要將不同伺服器的流量傳送到執行在 192.168.100.100 上的 NGINX 伺服器,以便 Ingress 可以將流量路由到適當的服務。Nip.io 使用包含 IP 位址的主機名格式來解析名稱到 IP。
例如,假設我們有四個網頁伺服器,分別命名為 webserver1、webserver2、webserver3 和 webserver4,並且 Ingress 規則執行在 192.168.100.100 上。我們可以使用以下命名標準:<所需名稱>.<INGRESS IP>.nip.io
四個網頁伺服器的名稱如下表所示:
| 名稱 | nip.io 網域名稱 |
|---|---|
| webserver1 | webserver1.192.168.100.100.nip.io |
| webserver2 | webserver2.192.168.100.100.nip.io |
| webserver3 | webserver3.192.168.100.100.nip.io |
| webserver4 | webserver4.192.168.100.100.nip.io |
當您使用上述任何名稱時,nip.io 將解析它們到 192.168.100.100。您可以在下面的截圖中看到每個名稱的 ping 範例:
使用 nip.io 進行名稱解析範例
圖表翻譯: 此圖示展示了客戶端如何透過 nip.io 解析網域名稱並將請求路由到對應的 Kubernetes 服務。首先,客戶端向 nip.io 傳送 DNS 請求,nip.io 傳回對應的 IP 位址。然後,客戶端向該 IP 位址傳送請求,Ingress 控制控制器根據請求中的網域名稱將流量路由到正確的服務。
建立 Ingress 規則
Ingress 規則使用名稱來路由傳入請求到正確的服務。以下是一個圖形表示,顯示了傳入請求如何被 Ingress 路由:
Ingress 流量流程
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Kubernetes 服務暴露型別與 Ingress 負載平衡
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
圖表翻譯: 此圖示展示了客戶端的請求如何透過 Ingress 被路由到後端的 Pod。首先,客戶端向 nip.io 傳送 DNS 請求以取得 IP 位址。然後,客戶端向該 IP 位址傳送請求,Ingress 控制控制器根據組態的規則將流量路由到正確的 Kubernetes 服務,最終轉發到後端的 Pod。
建立 Ingress 規則的步驟
- 使用者在瀏覽器中請求一個 URL 名為
webserver1.192.168.200.20.nip.io。DNS 請求被傳送到本地 DNS 伺服器,最終被傳送到 nip.io DNS 伺服器。 - nip.io 伺服器將網域名稱解析為 IP 位址
192.168.200.20,並傳回給客戶端。 - 客戶端將請求傳送到執行在
192.168.200.20上的 Ingress 控制控制器。請求中包含完整的 URL 名稱webserver1.192.168.200.20.nip.io。 - Ingress 控制控制器在組態的規則中查詢所請求的 URL 名稱,並將 URL 名稱與服務進行匹配。
- 伺服器端點將被用於將流量路由到分配的 Pod。
- 請求被路由到執行網頁伺服器的端點 Pod。
建立 Kubernetes 物件
首先,我們需要在一個名稱空間中執行一個簡單的網頁伺服器。我們將在預設名稱空間中佈署一個基本的 NGINX 網頁伺服器。使用以下
kubectl run命令可以快速建立佈署:kubectl run nginx-web --image bitnami/nginx內容解密:
kubectl run:用於建立一個新的佈署。nginx-web:佈署的名稱。--image bitnami/nginx:指定使用的 Docker 映象。
使用
kubectl expose命令為佈署建立一個服務。Bitnami NGINX 映象執行在埠8080上,因此我們將使用相同的埠來暴露服務:kubectl expose deployment nginx-web --port 8080 --target-port 8080內容解密:
kubectl expose:用於為一個佈署或 Pod 建立一個服務。deployment nginx-web:指定要暴露的佈署名稱。--port 8080:指定服務要暴露的埠。--target-port 8080:指定後端 Pod 的目標埠。
這樣,我們就成功地建立了一個簡單的網頁伺服器佈署和對應的 Kubernetes 服務,為進一步組態 Ingress 規則奠定了基礎。
使用Ingress規則與MetalLB進行負載平衡
建立Ingress規則
在建立了Deployment和Service之後,最後一步是建立Ingress規則。要建立Ingress規則,需要建立一個使用Ingress物件型別的manifest檔。以下是一個範例Ingress規則,它假設Ingress控制器正在192.168.200.20上執行。
nginx-ingress.yaml 範例
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-web-ingress
spec:
rules:
- host: webserver1.192.168.200.20.nip.io
http:
paths:
- path: /
backend:
serviceName: nginx-web
servicePort: 8080
建立Ingress規則
使用kubectl apply指令建立Ingress規則:
kubectl apply -f nginx-ingress.yaml
測試Ingress規則
在內部網路中的任何客戶端上,可以透過瀏覽http://webserver1.192.168.200.20.nip.io來測試Deployment是否成功。
Layer 4 負載平衡器
Layer 4 負載平衡器執行在OSI模型的第四層,負責處理TCP和UDP等協定的流量。根據IP位址和埠號接受傳入的流量,並根據一組規則將流量轉發到目標IP位址和埠號。
Layer 4 負載平衡器選項
有多種Layer 4 負載平衡器可供選擇,包括:
- HAproxy
- NGINX Pro
- SeeSaw
- F5 Networks
- MetalLB
使用MetalLB作為Layer 4 負載平衡器
MetalLB是一個免費且易於組態的Layer 4 負載平衡器。它提供了強大的組態選項,使其能夠執行在開發實驗室或企業叢集中。
安裝MetalLB
要佈署MetalLB到KinD叢集,需要使用MetalLB的GitHub儲存函式庫中的manifests檔。
- 建立一個名為
metallb-system的新名稱空間:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml
- 佈署MetalLB到叢集中:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml
- 建立一個用於加密通訊的secret:
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
設定MetalLB
MetalLB使用ConfigMap來儲存組態。由於我們將在Layer 2模式下使用MetalLB,因此所需的組態檔相對簡單,只需要提供一個IP範圍。
要取得Docker正在使用的子網路,可以檢查預設的橋接網路:
docker network inspect bridge
設定MetalLB的ConfigMap範例
apiVersion: v1
kind: ConfigMap
metadata:
name: config
namespace: metallb-system
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.200.20/32
詳細解說:
此ConfigMap定義了MetalLB的組態。其中,address-pools欄位定義了可用的IP位址範圍。在此範例中,我們使用layer2協定,並指定了一個IP位址範圍。
MetalLB BGP模式
MetalLB還提供了BGP模式,允許建立對等節點以交換網路路由。有關MetalLB的BGP模式的更多資訊,請參閱MetalLB官方檔案。
重點回顧
- 使用Ingress規則來管理傳入的HTTP請求。
- Layer 4 負載平衡器執行在OSI模型的第四層,負責處理TCP和UDP等協定的流量。
- MetalLB是一個免費且易於組態的Layer 4 負載平衡器,提供了強大的組態選項。
- 設定MetalLB需要提供一個IP範圍,並使用ConfigMap來儲存組態。