Kubernetes LoadBalancer 使用指南
什麼是 LoadBalancer Service?
Kubernetes LoadBalancer Service 是一種 Service 類型,用於將叢集內的應用程式暴露給外部網路。它會提供一個可從叢集外部存取的入口 IP,並透過 Service selector 將流量導向後端 Pod。
在雲端 Kubernetes 環境中,type: LoadBalancer 通常會自動建立雲端供應商的負載平衡器;在本機或裸機環境中,Kubernetes 本身不會自動分配外部 IP,因此常見做法是搭配 MetalLB,讓本地叢集也能取得 LoadBalancer IP。
LoadBalancer Service 的主要功能:
- 外部存取:讓叢集外部可以透過固定 IP 與連接埠存取應用程式
- 服務入口:透過 Service 提供穩定入口,避免直接依賴會變動的 Pod IP
- 負載分配:將進入 Service 的流量分配到符合 selector 的後端 Pod
- 流量策略:支援來源 IP 保留、會話親和性與內外部流量策略等設定
為什麼使用 LoadBalancer Service?
相較於 ClusterIP 或 NodePort,LoadBalancer Service 更適合需要直接對外提供 IP 入口的服務:
- 外部連線更直覺:使用者可以直接透過 LoadBalancer IP 與 Service port 存取服務
- 部署設定更清楚:Service 負責穩定入口,Deployment 負責維護後端 Pod
- 適合非 HTTP 場景:除了 HTTP 服務,也能暴露 TCP 或 UDP 類型的服務
實作範例
這篇沿用前面 Service 範例已經建立好的 Spring Boot 應用程式,重點放在 LoadBalancer Service 如何提供外部 IP 入口。開始前先確認叢集裡已有下列條件:
dockertestnamespace 已存在dockertest-deployment已建立,Pod 具有app: dockertestlabel- 應用程式容器實際監聽
8080port - Pod 已經 Ready,可以回應
/hello
Service 會透過下列 selector 找到這組 Pod:
1 | selector: |
只要 Deployment 的 template.metadata.labels 也包含 app: dockertest,LoadBalancer Service 就能將外部流量導到這些 Pod。這裡不再重複 Deployment、Registry Secret 與 Namespace 的完整 YAML,只保留必要檢查指令:
1 | kubectl rollout status deployment/dockertest-deployment -n dockertest |
私有映像提醒
如果映像放在 GitLab Container Registry 等私有 registry,請在部署工作負載時先建立
imagePullSecrets。文章或 Git repository 中不建議放入實際的.dockerconfigjsonbase64 內容。
LoadBalancer Service 做了什麼?
LoadBalancer Service 可以理解成「叢集外部入口」加上「Service 負載分配」的組合。
當我們建立 type: LoadBalancer 的 Service 後,Kubernetes 會建立一個 Service 物件,並等待底層環境提供外部 IP。外部請求進入這個 IP 與 Service port 後,Kubernetes 會依照 selector 找到符合條件的 Pod,再把流量轉送到 targetPort。
以下方設定為例:
1 | ports: |
它代表:
- 外部使用者連到 LoadBalancer IP 的
8080port - Service 將流量轉送到後端 Pod 的
8080port - 後端 Pod 由
selector.app: dockertest決定
因此整體流量會像這樣:
1 | Client -> LoadBalancer IP:8080 -> Service -> Pod:8080 |
Case 1:建立基本 LoadBalancer Service
第一個案例只建立 dockertest-loadbalancer,讓外部使用者可以直接透過 LoadBalancer IP 與 8080 port 存取 Spring Boot 服務。
1 | apiVersion: v1 |
套用後查看 Service 狀態:
1 | kubectl apply -f dockertest-loadbalancer-service.yaml |
dockertest-loadbalancer 會向底層環境申請外部 IP。取得 IP 後,可以直接從叢集外部呼叫:
1 | curl http://<EXTERNAL-IP>:8080/hello |
這種方式適合需要直接暴露 TCP/HTTP 服務的場景,例如本機測試、內網系統、或不需要透過網域路由的服務。測試時重點是確認 EXTERNAL-IP 已取得位址,並且能透過 http://<EXTERNAL-IP>:8080/hello 取得 Hello, World! 回應。
Case 2:外部 port 與容器 port 不同
第二個案例只建立一個 LoadBalancer Service,並把外部 7777 port 轉送到容器的 8080 port。
1 | apiVersion: v1 |
這段設定的重點在於 port 與 targetPort 不同:
port: 7777:Service 對外提供的連接埠targetPort: 8080:Pod 容器實際接收流量的連接埠
因此流量會變成:
1 | Client -> LoadBalancer IP:7777 -> Service -> Pod:8080 |
如果應用程式實際仍然監聽 8080,但你希望外部使用者用 7777 連線,就可以使用這種寫法。這在遊戲伺服器、內部測試服務、或需要符合既有連線規則的系統中很常見。
測試方式如下:
1 | kubectl get service dockertest-loadbalancer -n dockertest |
下圖可以看到 LoadBalancer 對外提供 7777 port,但仍然能將流量轉送到後端 Pod 的 8080 port;多次請求也會被分配到不同 Pod。
常用欄位說明
type
type 決定 Service 的暴露方式:
ClusterIP:只提供叢集內部 IP,適合內部服務互連NodePort:在每個 Node 開一個固定範圍的 port,讓外部可透過 Node IP 存取LoadBalancer:向底層環境申請外部 IP,適合直接暴露服務
selector
selector 決定 Service 要把流量導向哪些 Pod。本文範例使用:
1 | selector: |
只要 Pod label 符合 app: dockertest,就會被加入這個 Service 的 endpoints。
可以用下列指令確認 Service 是否有找到 Pod:
1 | kubectl get endpoints dockertest-loadbalancer -n dockertest |
如果 endpoints 是空的,通常代表 Service selector 與 Pod label 對不起來,或 Pod 尚未 Ready。
port 與 targetPort
port 是 Service 暴露出來的連接埠,targetPort 是 Pod 實際接收流量的連接埠。
1 | ports: |
代表外部連到 8080,Service 也轉送到 Pod 的 8080。
1 | ports: |
代表外部連到 7777,Service 轉送到 Pod 的 8080。
externalTrafficPolicy
externalTrafficPolicy 會影響外部流量進入叢集後的轉發方式。
Cluster:預設值,流量可以被轉發到任一節點上的 Pod,負載分散較平均Local:只轉發到接收該流量節點上的 Pod,可保留來源 IP,但需要注意 Pod 分布
開發與一般測試場景通常使用 Cluster 即可。如果應用程式需要取得真實 Client IP,才會優先考慮 Local。
sessionAffinity
sessionAffinity 決定是否要讓同一個 client 固定連到同一個 Pod。
None:預設值,每次請求可被分配到不同 PodClientIP:同一個 Client IP 會盡量被導向同一個 Pod
無狀態服務通常使用 None。如果應用程式把登入狀態或連線狀態放在 Pod 本機記憶體中,才需要考慮 ClientIP,但更建議把狀態移到 Redis、資料庫或其他共享儲存中。
在 Minikube 測試 LoadBalancer
Minikube 預設不會像雲端平台一樣自動建立外部負載平衡器,因此 type: LoadBalancer 需要搭配本機的 LoadBalancer 實作才會取得 EXTERNAL-IP。MetalLB 的安裝與位址池設定會放到下一篇文章介紹,這裡先聚焦在 Service 本身的使用方式。
如果環境已經能提供 LoadBalancer IP,就可以直接建立 Service 並查看狀態:
1 | kubectl apply -f loadbalancer-service.yaml |
如果只是要在 Minikube 快速測試,也可以使用 tunnel 讓 LoadBalancer Service 取得本機可存取的路由:
1 | minikube tunnel |
minikube tunnel 需要管理員或 root 權限,執行後會替 LoadBalancer Service 建立本機可存取的路由。
部署與檢查指令
如果前置 Deployment 已經存在,這篇只需要套用 LoadBalancer Service YAML:
1 | kubectl apply -f dockertest-loadbalancer-service.yaml |
檢查 Service
1 | kubectl get service dockertest-loadbalancer -n dockertest |
檢查 Pod 與 endpoints
1 | kubectl get pods -n dockertest -l app=dockertest |
測試連線
1 | EXTERNAL_IP=$(kubectl get service dockertest-loadbalancer -n dockertest -o jsonpath='{.status.loadBalancer.ingress[0].ip}') |
如果使用 case2 的 7777 port,測試指令改成:
1 | curl http://$EXTERNAL_IP:7777/hello |
疑難排解
LoadBalancer IP 一直是 pending
先確認 Service 狀態:
1 | kubectl get service dockertest-loadbalancer -n dockertest |
常見原因包含:
- 目前環境沒有提供 LoadBalancer IP 的實作
- 本機叢集尚未啟用對應的 LoadBalancer 機制
- 使用 Minikube 時尚未執行
minikube tunnel - 雲端環境的負載平衡器資源尚未建立完成
Service 有外部 IP,但連不到應用程式
先檢查 Pod 是否正常 Ready:
1 | kubectl get pods -n dockertest -l app=dockertest |
再檢查 Service endpoints:
1 | kubectl get endpoints dockertest-loadbalancer -n dockertest |
如果 endpoints 是空的,請確認 Deployment 的 Pod label 與 Service selector 是否一致。
如果 endpoints 正常,則檢查應用程式是否真的監聽 targetPort,以及 readinessProbe 是否通過:
1 | kubectl describe pod -n dockertest -l app=dockertest |
使用建議
如果只是讓叢集內部服務互相呼叫,使用 ClusterIP 就好。如果需要從叢集外部直接用 IP 和 port 存取服務,可以使用 LoadBalancer。如果服務是 HTTP/HTTPS,並且需要用網域、路徑或 TLS 管理多個應用程式,則建議交給 Ingress 處理,這樣 LoadBalancer 只需要出現在 Ingress Controller 入口或真正需要 IP 直連的服務上。
簡單來說:
- 內部服務互連:
ClusterIP - 外部 IP 直連:
LoadBalancer - 網域與 HTTP/HTTPS 路由:
Ingress搭配ClusterIP - 同時需要 IP 直連與網域路由:只在真的需要直連時替應用程式保留
LoadBalancer
透過這樣的分工,可以讓 Kubernetes 服務入口更清楚,也比較容易在開發、測試與正式環境之間維持一致的部署方式。