Kubernetes - 關於 Service 的介紹
介紹
Kubernetes 中的 Service 是一種資源,說他是資源是因為它是一種 Kubernetes 提供的 API 物件,通過描述和管理網路訪問來控制 Pods 的互動和連接方式。而Service用於將一組執行相同工作的容器 (Pods) 暴露為一個網路服務。
其存在的主要目的是提供一個穩定的網路介面
讓應用程序或其他 Pods 能夠方便地相互通訊,即使 Pod 隨著時間可能會發生變化(例如重新啟動、擴展或縮減)。更具體一點,Service可以達到以下功能:
- 提供固定的訪問入口:Pods 是動態的,IP 可能會變動,但 Service 會提供一個固定的 IP 和 DNS 名稱,讓其他服務或應用可以持續連接,不受 Pods IP 變化的影響。
- 負載平衡:當多個 Pods 提供相同的功能時,Service 會自動分配流量給這些 Pods,確保請求被平均分配,避免單個 Pod 承受過多壓力。
- 解耦:Service 將應用程序的
網路流量
相關設定 與 Pod 的具體運行
位置分離。簡單來說,你設定好Service之後,不管你擴展、縮減或是重新部署Pods,Service 都會自動根據你的設定去連接到正確的Pods,不需要再去修改Service的任何設定。
有不同類型的 Service,例如:
- ClusterIP:只在 Kubernetes 集群內部可訪問,用於內部服務間的通訊,這是默認的 Service 類型。
- 使用時間:當你的應用程序只需要在
集群內部
訪問時。
- 使用時間:當你的應用程序只需要在
- NodePort:在每個 Node(節點)上開放一個特定的端口,讓外部流量可以進入。
- 使用時機:當你的應用程序需要從
集群外部
訪問時。
- 使用時機:當你的應用程序需要從
- LoadBalancer:當你使用 LoadBalancer 類型的 Service 時,它會利用雲服務提供商(例如 AWS、GCP、Azure 等)的外部負載平衡器,將外部請求分配到 Kubernetes 集群中的多個節點(Nodes)上。每個節點上的 Kube-proxy 再將流量分發到與該 Service 關聯的 Pods,這樣可以實現外部請求的負載均衡,確保高可用性和分擔流量壓力。
- 使用時機:客戶端發出多個請求,雲提供商的負載平衡器會根據流量狀況,將請求分配到集群中的不同 Nodes。
- ExternalName:他的作用是將Kubernetes集群內部的請求根據Service的名稱轉發到外部的DNS名稱。當你創建一個 ExternalName 類型的 Service 時,Kubernetes 會在內部建立一個 DNS 記錄,將該 Service 名稱映射到你指定的外部 DNS 名稱。當集群中的 Pods 或其他服務嘗試訪問這個 Service 時,請求會被自動轉發到指定的外部域名。
- 使用時機:假設你創建了一個名為
my-service
的 ExternalName Service,並將它指向api.external-service.com
,那麼在集群內的任何 Pod 或服務訪問my-service
時,實際上會連接到api.external-service.com
。
- 使用時機:假設你創建了一個名為
建立 Service
透過YAML
1 | $ vim svc.yaml |
1 | apiVersion: v1 |
1 | $ kubectl apply -f svc.yaml |
透過Expose
這種方法是將Pod expose給外部使用者,相當於創建一個Service。創建的Service會自動將該Pod的label填入selector欄位,name
欄位則輸入Service的名稱,type
是Service的類別。
1 | $ kubectl expose po <pod-name> --name=<svc-name> --type=<type-of-svc> |
Service 的差異
Service依照不同功能及使用場景,主要有三種Service:NodePort, ClusterIP及LoadBlancer
NodePort
NodePort的目標是將Pod expose給外部使用者
根據上圖可以看到
- 在Node上開放一個特定的Port,讓外部流量可以進入
- 再透過Service將流量分發到Pods上
NodePort 的 YAML 設定如下
1 | # $ vim NP-Svc.yaml |
targetPort
: 指定Pod上允許外部資源存取的Port Number,Service 會將請求導向到Pod的這個Port,如果在YAML裡面沒有指定targetPort
,則預設會使用port
的值。port
: 這個端口定義了集群內部如何訪問該服務,當 Pod 或其他服務嘗試通過該服務的名字來訪問時,這就是它們使用的端口號。如果設置 port: 80,那麼集群內的其他應用可以通過服務名和 port 80 來訪問該服務。nodePort
: 指定節點(Node)要開放哪一個Port,NodePort範圍是30000 ~ 32767,若NodePort欄位沒有給定,K8s會自動assign一個範圍內的Port為NodePort。當你訪問 Kubernetes 節點的這個端口時,Kubernetes 會自動將流量轉發到該服務的後端 Pod 上。nodePort 允許你從集群外部通過節點的 IP 和該端口來訪問服務。
ClusterIP
ClusterIP的目標是將Pod expose給集群內部使用者
ClusterIP是 default的Service Type,它只提供集群內部的服務,集群內的Pod都可以透過它互相訪問,集群外部則無法訪問它。ClusterIP的應用場景通常是保護某些資料不被外部存取,例如一個Web Application有back-end和front-end,我只想將front-end Pod expose出去,但又想back-end和front-end可以溝通,這時就可以用到ClusterIP Service。
但是如果你使用的是前後端分離的話,前端應用(通常是一個獨立的 Web 應用)和後端 API 是獨立部署和運行的。因此,瀏覽器在這種情況下直接與後端 API 進行通訊,而不經過 Kubernetes 集群內的前端 Pods。
1 | # $ vim CIP-Svc.yaml |
LoadBalancer
LoadBalancer的目標是讓流量分配到多個節點上多個Pods上
在 Kubernetes 中,LoadBalancer 用於自動創建一個雲提供商的外部負載均衡器(如 AWS ELB、GCP LB)來將外部流量導向服務的後端 Pod。它可以幫助你將外部請求分配到 Kubernetes 集群中的多個節點和 Pod 上,實現高可用性和負載均衡。儘管 LoadBalancer 可以幫助實現自動的外部流量負載均衡,但在很多情況下,團隊會選擇不使用它,原因包括以下幾點:
成本高
公有雲負載均衡器(如 AWS ELB 或 GCP Load Balancer)通常會按小時或流量計費。對於每個應用使用一個 LoadBalancer 類型的服務,隨著服務數量增多,成本會非常高,特別是在生產環境中部署大量微服務時。
受限於雲供應商的配置
且通常只支持 L4 層(TCP/UDP)(應用程式端口級別)的負載均衡。它不能像自定義的反向代理(如 NGINX 或 Traefik)一樣靈活配置 HTTP 層的負載均衡、路由規則或其他更細緻的流量控制策略。
- L4 層負載均衡(傳輸層): L4 負載均衡基於 TCP(傳輸控制協議)或 UDP(用戶數據報協議)協議來進行流量的分配,它只在網絡層的 IP 地址和端口號的基礎上進行決策,並不理解應用層的數據。
- 與 L4 不同,L7 層負載均衡可以處理應用層的數據,並基於這些數據進行更細緻的路由和控制。例如,L7 負載均衡器能夠解析 HTTP/HTTPS 流量,並根據具體的應用層信息(如 URL 路徑、HTTP headers、Cookies)進行決策。