昨天,我們透過 HPA 讓 Pod 副本數能依照負載自動調整:負載升高時增加 Pod,負載降低後逐步減少 Pod。
不過,當 Pod 數量發生變化時,使用者的請求要如何找到這些 Pod?
每個 Pod 都有自己的 IP,但 Pod 在重新建立後,IP 位址可能會改變。當副本數從 1 個增加到 5 個時,也不適合由使用者手動選擇特定的 Pod IP 進行連線。
這時就需要 Kubernetes Service。Service 會提供穩定的存取端點,並將流量分配至符合條件的 Pod,讓使用者不需要直接管理 Pod 的 IP 位址。
今天我們會依序介紹三種常見的 Service 類型:ClusterIP、NodePort 與 LoadBalancer,逐步了解 Kubernetes 如何解決 Pod 存取與流量轉送的問題。
以下操作皆在 master 節點 執行,沿用 Day 3 的
php-apacheDeployment。
先看看現在的 Pod:
kubectl get pods -o wide
你會看到每個 Pod 都有自己的 IP(例如 192.168.166.135)。看起來只要知道 IP 就能連過去,但真的是這樣嗎?我們來做個實驗。
記下目前 Pod 的 IP 後,把它刪掉:
kubectl delete pod <你的pod name>
Deployment 會自動拉起一個新的 Pod,等幾秒再查看:
kubectl get pods -o wide
IP 變了。 同一個 Deployment、同一個應用,但新 Pod 拿到的是全新的 IP。

這代表什麼?如果你在程式裡寫死 Pod IP,Pod 一重啟就斷線了。而且問題不只這一個:
💡 結論:Pod IP 並非固定不變,因此需要一個穩定的存取入口來代表這組 Pod,而這正是 Service 的用途
ClusterIP 是 Service 的預設類型。它會分配一個穩定的虛擬 IP(只在叢集內有效),所有流量會自動分配到後端的 Pod。
確認 Service 已建立:
kubectl get svc php-apache
你會看到類似這樣的輸出:

CLUSTER-IP 就是這個 Service 的穩定 IP,不管後端 Pod 怎麼換,這個 IP 都不會變。
在叢集內,你甚至不需要記 IP,直接用 Service 名稱 就能連:
kubectl run curl-test --rm -i --image=curlimages/curl --restart=Never \
-- curl -s http://php-apache
看到 OK! 就代表成功了。
# 刪掉目前的 Pod
kubectl delete pod -l app=php-apache
# Deployment 會自動拉起新 Pod,等幾秒再連
kubectl run curl-test2 --rm -i --image=curlimages/curl --restart=Never \
-- curl -s http://php-apache
還是通! Pod 換了,IP 變了,但 Service 不受影響。

ClusterIP 的核心價值:
ClusterIP 解決了叢集內的問題,但如果你想從瀏覽器或外部機器連進來呢?
NodePort 會在每個 Node 上開一個固定的 port(範圍 30000–32767),外部流量打到任何一台 Node 的這個 port,就會被轉到 Service。
先刪掉舊的,改建 NodePort 類型:
kubectl delete svc php-apache
kubectl expose deployment php-apache --port=80 --type=NodePort
查看分配到的 port:
kubectl get svc php-apache
這裡的31598 就是 NodePort(你看到的數字可能不同)。

用任何一台 Node 的 IP + NodePort 就能連到:
# 在 master 或任何能連到 Node 的機器上
curl http://<NODE_IP>:31598

⚠️ GCP 防火牆提醒
如果 Kubernetes 節點部署在 GCP VM 上,需確認防火牆規則已開放對應的 NodePort。
可前往 GCP Console → VPC network → Firewall rules,新增允許 TCP
30000-32767的輸入規則。若未開放,叢集外部將無法透過 NodePort 存取服務。
IP:Port,缺乏易於辨識的固定存取位址💡 NodePort 適合測試環境或沒有 Load Balancer 的裸機叢集。正式環境通常會搭配 LoadBalancer 或 Ingress。
在雲端環境(GKE、EKS、AKS),LoadBalancer 類型的 Service 會自動向雲端供應商要一個外部 Load Balancer,拿到一個公開的 IP 或 DNS。使用者只要連這個 IP 就好,不用記 NodePort,也不用知道後端有幾個 Pod。
因為我們是用 kubeadm 自己建的叢集,沒有雲端 LB 供應商,如果你嘗試建立 LoadBalancer 類型的 Service,會看到 EXTERNAL-IP 一直卡在 <pending>。這是正常的 — 不是你的設定有問題,而是 kubeadm 環境本來就沒有外部 LB 可以分配。
💡 想在裸機環境使用 LoadBalancer?
可安裝 MetalLB,為裸機 Kubernetes 提供
LoadBalancer類型 Service 的實作。MetalLB 會從預先設定的 IP 位址池中,分配可供外部存取的 IP。本章不進一步介紹 MetalLB 的安裝與設定,有興趣可再自行延伸練習。
今天我們體驗了三種 Service 類型,解決了「流量怎麼進到 Pod」的問題:
| 類型 | 存取範圍 | 適用場景 |
|---|---|---|
| ClusterIP | 叢集內部 | 微服務之間互相呼叫(預設類型) |
| NodePort | Node IP + Port | 測試環境、裸機叢集 |
| LoadBalancer | 外部公開 IP | 雲端正式環境(GKE / EKS / AKS) |
Service 解決了「穩定入口 + 負載均衡」的問題,但你有沒有好奇過 — 流量打到 Service 之後,到底是誰在背後幫你轉發到正確的 Pod?
明天我們來揭開 kube-proxy 的面紗 — 看看 Service 背後的轉發機制是怎麼運作的。