到目前為止,我們已經建立 Deployment 與 Pod replica,也知道 Pod 可以被刪除、重建並重新排程。
不過假設某個 API 要呼叫另一個服務,卻把對方某一顆 Pod 的位址直接填在程式設定裡,例如 http://10.244.1.7:8080。如果那顆 Pod 被刪除後重新建立,新 Pod 可能會換一個 IP,而程式仍呼叫舊 IP,就可能找不到服務。
Service 就是 Kubernetes 提供的穩定入口,常會透用 selector 找出目前符合條件的 Pod,讓呼叫端不必每次都因為變動的 Pod IP 而去頻繁的改相關設定或程式碼。
以下是一個簡單範例:
yaml
apiVersion: v1
kind: Service
metadata:
name: catalog-api
spec:
selector:
app.kubernetes.io/name: catalog-api
ports:
- name: http
port: 80
targetPort: http
這份 Service 有三個主要設定:
| 欄位 | 意義 |
|---|---|
| selector | 挑出帶有指定 Label 的後端 Pod。 |
| port | Service 對呼叫端提供的 Port。 |
| targetPort | 流量最後要送進 Pod container 的 Port;可填數字,也可指向 container port 的名稱。 |
對有設定 selector 的 Service,Kubernetes Control Plane 中的 EndpointSlice controller(端點切片控制器) 會依據符合條件的 Pod,建立或更新 EndpointSlice(端點切片)。
EndpointSlice 是 Kubernetes 用來記錄 Service 後端端點的物件,內容包含 Pod 位址、Port 與端點狀態。
當 Pod 數量較多時,同一個 Service 也可能對應多個 EndpointSlice。這個 controller 是 Kubernetes 的內建 Controller,會隨著 Service 或 Pod 狀態變化協調更新後端清單。實際流量通常會導向其中 Ready 的 endpoint。
Pod 被 Deployment 替換時,EndpointSlice 也會隨之更新。
所以從上述也可以了解到,Service 本身不參與建立、刪除 Pod 的相關事件。

實際封包要怎麼在 Node 上被轉送,會依叢集的網路實作而不同。
例如 kube-proxy 是常見的 Service 實作元件,某些 CNI 方案也能實作或接手處理分 Service 流量。不論底層細節如何,應用程式層的重點是:呼叫 Service,不要直接依賴某一顆 Pod IP。
Service Type 決定 Service 主要在哪個範圍可被存取。今天的主角是 ClusterIP、NodePort 與 LoadBalancer。

| Type | 主要用途 | 從哪裡可連線 | 初學時應注意 |
|---|---|---|---|
| ClusterIP | 叢集內服務互相呼叫 | 叢集內 Pod | 預設類型,通常是叢集內的 Pod 與 Pod之間溝通最常用的入口。 |
| NodePort | 在每台 Node 開出同一個 Port | 可到達任一 Node IP 的用戶端 | 需要處理 Node 網路、防火牆與 Port 範圍;通常不會被做為正式的對外入口。 |
| LoadBalancer | 請平台提供外部 Load Balancer | 由平台配置的外部位址 | 是否真的拿到外部位址,取決於套件以及公、私有雲的相關配置。 |
未指定 type 時,Service 預設就是 ClusterIP。Kubernetes 會配置一個叢集內可使用的虛擬 IP,讓其他 Pod 可以透過 Service name 連線。
同一個 Namespace 中,呼叫端通常可以直接使用:
叢集的 DNS Service(例如 CoreDNS)會把 Service name 解析成對應的叢集內的入口。與直接叫某一顆 Pod 不同的是:後端 Pod 即使被替換,catalog-api 這個 Service 名稱仍保持不變。
NodePort 會讓每台 Node 的 Service proxy 配置同一個 Port,並在叢集設定允許的 Node IP 上接受流量。只要外部用戶端能連到其中一台可達的 Node,就能經由 NodeIP:NodePort 進入該 Service,再被轉送到符合 selector 的 Pod;預設行為仍會受到 kube-proxy mode 與 nodePortAddresses 設定影響。
它適合學習或某些直接暴露服務的情境,但要注意它暴露的是 Node 層級入口,不代表 Pod 一定就在你連到的那台 Node 上。也因為要處理 Node IP、網路路由與防火牆,正式環境通常會再交由專門的 Load Balancer、Ingress 或 Gateway 來管理對外流量。
LoadBalancer 不代表 Kubernetes 自己憑空產生一台負載平衡器。它是向叢集所整合的平台提出需求:請建立或配置一個外部 Load Balancer,並把流量導向這個 Service。
VIP(Virtual IP,虛擬 IP) 是用戶端用來連線的入口 IP,它不屬於某一顆固定 Pod 或單一網卡。
Load Balancer 可以把送到這個 IP 與 Port 的連線,依據不同規則轉送到對應的 Service。
使用者連線到 https://api.example.com 時,DNS 可將名稱解析到一個 VIP;使用者不需要知道後面有幾顆 Node、Pod 是否剛被重建,或實際流量最後進到哪一顆 Pod。這正是外部 Load Balancer 與 Service 要共同提供的穩定入口,整體概念上會有點像 nginx 的反向代理。
叢集完成配置後,會將可供連線的資訊寫入 Service 的 .status.loadBalancer.ingress;可以設定 ip,也可以設定 hostname。因此建議是讓 Client 端指向對應的 FQDN,而不是 VIP。
同一份 type: LoadBalancer YAML,在不同平台背後可能是完全不同的提供者:
| 環境 | 常見的提供者與結果 |
|---|---|
| VMware Tanzu / vSphere 搭配 NSX ALB | AKO 將 Service 需求同步給 NSX Advanced Load Balancer(Avi),由 Avi 建立 Virtual Service 與其 VIP。 |
| AKS | AKS 建立 Azure Load Balancer、配置公用或私用 IP,並設定後端集區與規則。 |
| EKS | EKS Auto Mode 可為 LoadBalancer Service 配置 AWS Network Load Balancer;自行管理的 EKS 叢集常使用 AWS Load Balancer Controller 建立與協調 NLB。 |
| 自建/裸機 Kubernetes | 可安裝 MetalLB 這類 CNCF Sandbox 專案,從管理者設定的 IPAddressPool 配發 IP,並透過 L2(ARP/NDP)或 BGP 對外宣告該 VIP。 |
所以,type: LoadBalancer 是 Kubernetes 的通用介面,不是某一種固定產品或網路拓樸。Kubernetes 也提供 .spec.loadBalancerClass,讓叢集可明確指定由哪一種 Load Balancer 實作接手;具體註解、可用協定、健康檢查與是否能直接導向 Pod,都要查閱該平台或 Controller 的文件。
ExternalName 與前面三種不同,它不會建立 selector、EndpointSlice 或 Proxy,而是回傳一個外部 DNS 名稱的 CNAME。它適合建立名稱別名,但不適合拿來取代一般 Pod Service。
Headless Service 則是將 clusterIP 設為 None 的特殊設定,不是額外的 Service Type。它通常讓呼叫端直接取得後端 Pod 的 DNS 資訊,常見於需要自行處理節點身分或連線對象的 Stateful 工作負載。這兩種先知道存在即可。
Docker Compose 與 Kubernetes 都能讓服務用名稱互相呼叫,但背後模型不同:
| Docker Compose | Kubernetes |
|---|---|
| Compose service name 通常可作為同一 Compose network 內的 DNS 名稱。 | Service name 是 Kubernetes API object 的名稱;常見情況會對應一群符合 selector 的 Pod,也可以對應手動 EndpointSlice 或 ExternalName 的 DNS alias。 |
| container_name 是特定 container 的固定名稱。 | Pod 名稱是個別執行個體名稱,會隨重建或擴縮改變。 |
| 設定 container_name 的 Compose service 不能擴成多個 container。 | Service 本身就是為多個可替換 Pod 提供一個穩定入口。 |
因此,從 Docker Compose 遷移時,最接近「呼叫服務名稱」的概念是 Kubernetes Service。
<pending>,不代表是 selector 壞掉曾經遇過 LoadBalancer Service 的 External IP 一直停在 <pending>。後端 Pod 正常、selector 也正確,但平台無法分配對應 IP:指定的 IP 不在 IPAM Pool 範圍內,或是可用 IP 已耗盡。
後來發現應該往這些邏輯去排查才比較有效率:
遇到這類情況,先看 kubectl describe service 中的 Event,比起直接修改 selector 或重建 Pod 更容易找到根因。
Service 讓呼叫端以穩定名稱與入口存取一群可替換的 Pod。ClusterIP 適合叢集內流量;NodePort 在 Node 層級開 Port;LoadBalancer 則要求平台配置外部入口。