iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 4

Day 04|Service — 為 Pod 提供穩定的存取入口

  • 分享至 

  • xImage
  •  

前言

昨天,我們透過 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-apache Deployment。


一、為什麼不能直接用 Pod IP?

先看看現在的 Pod:

kubectl get pods -o wide

你會看到每個 Pod 都有自己的 IP(例如 192.168.166.135)。看起來只要知道 IP 就能連過去,但真的是這樣嗎?我們來做個實驗。

實驗:刪掉 Pod,IP 會跟著變嗎?

記下目前 Pod 的 IP 後,把它刪掉:

kubectl delete pod <你的pod name>

Deployment 會自動拉起一個新的 Pod,等幾秒再查看:

kubectl get pods -o wide

IP 變了。 同一個 Deployment、同一個應用,但新 Pod 拿到的是全新的 IP。

https://ithelp.ithome.com.tw/upload/images/20260806/20181928wkRRVi1UUi.png

這代表什麼?如果你在程式裡寫死 Pod IP,Pod 一重啟就斷線了。而且問題不只這一個:

  1. 刪掉 Pod,IP 就變了
  2. scale 成多個,不知道連哪個 — 5 個 Pod 5 個 IP,不可能在程式裡寫死
  3. Pod IP 只在叢集內有效 — 外部完全連不到

💡 結論:Pod IP 並非固定不變,因此需要一個穩定的存取入口來代表這組 Pod,而這正是 Service 的用途


二、ClusterIP — 叢集內部的穩定入口

ClusterIP 是 Service 的預設類型。它會分配一個穩定的虛擬 IP(只在叢集內有效),所有流量會自動分配到後端的 Pod。

確認 Service 已建立:

kubectl get svc php-apache

你會看到類似這樣的輸出:

https://ithelp.ithome.com.tw/upload/images/20260806/201819287a8V2UvkrG.png

CLUSTER-IP 就是這個 Service 的穩定 IP,不管後端 Pod 怎麼換,這個 IP 都不會變

實驗:用 Service Name 存取

在叢集內,你甚至不需要記 IP,直接用 Service 名稱 就能連:

kubectl run curl-test --rm -i --image=curlimages/curl --restart=Never \
  -- curl -s http://php-apache

看到 OK! 就代表成功了。

實驗:刪 Pod 再連

# 刪掉目前的 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 不受影響。

https://ithelp.ithome.com.tw/upload/images/20260806/2018192844ZXr6P0Ig.png

ClusterIP 的核心價值:

  • 提供一個穩定的虛擬 IP + DNS 名稱,不隨 Pod 生死而改變
  • 自動做 Round-Robin 負載均衡,流量平均分到每個 Pod
  • 但它只在叢集內有效,外部無法存取

三、NodePort — 從叢集外部存取 Service

ClusterIP 解決了叢集內的問題,但如果你想從瀏覽器或外部機器連進來呢?

NodePort 會在每個 Node 上開一個固定的 port(範圍 30000–32767),外部流量打到任何一台 Node 的這個 port,就會被轉到 Service。

建立 NodePort Service

先刪掉舊的,改建 NodePort 類型:

kubectl delete svc php-apache
kubectl expose deployment php-apache --port=80 --type=NodePort

查看分配到的 port:

kubectl get svc php-apache

這裡的31598 就是 NodePort(你看到的數字可能不同)。

https://ithelp.ithome.com.tw/upload/images/20260806/20181928Kxdkdy8Ed2.png

實驗:從 Node 外部存取

用任何一台 Node 的 IP + NodePort 就能連到:

# 在 master 或任何能連到 Node 的機器上
curl http://<NODE_IP>:31598

https://ithelp.ithome.com.tw/upload/images/20260806/201819281vZOUHhCzq.png

⚠️ GCP 防火牆提醒

如果 Kubernetes 節點部署在 GCP VM 上,需確認防火牆規則已開放對應的 NodePort。

可前往 GCP Console → VPC network → Firewall rules,新增允許 TCP 30000-32767 的輸入規則。若未開放,叢集外部將無法透過 NodePort 存取服務。

NodePort 的限制

  • 每個 Service 佔一個 port,port 範圍有限(30000–32767)
  • 使用者需要記住 IP:Port,缺乏易於辨識的固定存取位址
  • 沒有 HTTPS、沒有域名路由

💡 NodePort 適合測試環境沒有 Load Balancer 的裸機叢集。正式環境通常會搭配 LoadBalancer 或 Ingress。


四、LoadBalancer — 正式環境的做法

在雲端環境(GKE、EKS、AKS),LoadBalancer 類型的 Service 會自動向雲端供應商要一個外部 Load Balancer,拿到一個公開的 IP 或 DNS。使用者只要連這個 IP 就好,不用記 NodePort,也不用知道後端有幾個 Pod。

在 kubeadm 環境的情況

因為我們是用 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 背後的轉發機制是怎麼運作的。


參考資源


上一篇
Day 03|HPA — 讓 Kubernetes 自己決定要跑幾個 Pod
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言