使用 kubectl proxy 與 kubectl port-forward 打通 Kubernetes 服務

在 Kubernetes 中,ClusterIP Service 預設只能在叢集內部被存取。這樣的設計很適合讓後端服務、資料庫或內部 API 保持在叢集網路內,但在開發與除錯時,我們常常需要從本機瀏覽器或本機工具暫時連進去確認服務是否正常。

這時候可以使用 kubectl proxykubectl port-forward 建立一條臨時通道,把本機請求導向叢集內的服務。這兩個指令都不需要改 Service Type,也不需要額外建立 NodePort、LoadBalancer 或 Ingress,很適合用在本機測試、問題排查與臨時驗證。

這篇文章會使用一個 Tomcat 服務作為範例,示範如何透過這兩種方式存取 Kubernetes 內部的 ClusterIP Service。


測試環境

這次範例的服務部署在 tomcat-test namespace,裡面有一個 Tomcat Pod、一個 Deployment,以及一個 ClusterIP 類型的 Service。

可以先用以下指令確認目前資源狀態:

1
kubectl get all -n tomcat-test

從畫面可以看到 tomcat-service 的 Type 是 ClusterIP,Service Port 是 8080/TCP。這代表它會在叢集內提供穩定入口,但外部主機無法直接透過這個 ClusterIP 存取服務。

本篇範例的目標是從本機瀏覽器開啟 Tomcat 首頁,確認流量可以從本機順利轉送到叢集內的 Tomcat 服務。

方法一:使用 kubectl proxy

kubectl proxy 會在本機啟動一個 HTTP Proxy,讓我們透過 Kubernetes API Server 存取叢集資源。它的重點不是直接把某個 Service Port 綁到本機,而是先連到 API Server,再透過 API Server 的 proxy 子路徑轉送到指定 Service。

先在本機啟動 proxy:

1
kubectl proxy

預設情況下,kubectl proxy 會監聽 127.0.0.1:8001。終端機會停在前景執行,保持這個視窗不要關閉,接著就可以從瀏覽器或 curl 存取叢集內的 Service。

這次的 Service 位於 tomcat-test namespace,Service 名稱是 tomcat-service,Service Port 是 8080,因此可以使用下列網址:

1
http://localhost:8001/api/v1/namespaces/tomcat-test/services/tomcat-service:8080/proxy/

如果 Service 只有單一 Port,有些情境也可以省略 Port,改用下列格式:

1
http://localhost:8001/api/v1/namespaces/tomcat-test/services/tomcat-service/proxy/

透過 kubectl proxy 存取時,流量路徑大致如下:

1
2
3
4
5
6
本機瀏覽器
-> localhost:8001
-> kubectl proxy
-> Kubernetes API Server
-> tomcat-service:8080
-> Tomcat Pod:8080

允許其他主機連線:--address 0.0.0.0

kubectl port-forward 類似,kubectl proxy 預設也只會監聽本機的 127.0.0.1。如果希望同一個區域網路中的其他主機也能透過這台電腦存取 Kubernetes API proxy,可以加上 --address 0.0.0.0,讓 proxy 綁定在所有網路介面上。

不過 kubectl proxy 還有 Host header 的檢查機制。當其他主機用 http://<主機IP>:8001 連進來時,Host 會變成該主機 IP,而不是 localhost。因此除了 --address 0.0.0.0 之外,通常還需要搭配 --accept-hosts 放行對應的 Host:

1
kubectl proxy --address 0.0.0.0 --accept-hosts '^.*$'

假設執行指令的主機 IP 是 192.168.1.50,其他電腦就可以透過下列網址存取 Tomcat Service:

1
http://192.168.1.50:8001/api/v1/namespaces/tomcat-test/services/tomcat-service:8080/proxy/

使用這種方式時要特別注意安全性,因為這會讓 Kubernetes API proxy 對其他主機開放。建議只在可信任的開發網路中短暫使用,測試完成後立即停止指令;如果外部主機無法連線,也要確認本機防火牆是否允許連入 8001 Port。

kubectl proxy 很適合用來測試 Kubernetes API 相關路徑,或是在不想直接暴露 Pod / Service Port 的情況下,透過 API Server 暫時連到叢集內服務。不過它的 URL 較長,而且請求會經過 API Server,因此比較適合臨時驗證,不建議當成正式服務入口。

方法二:使用 kubectl port-forward

kubectl port-forward 則是另一種更直覺的方式。它會把本機某個 Port 轉送到 Kubernetes 裡的 Pod、Deployment 或 Service,讓本機工具可以像連到本機服務一樣連到叢集內應用程式。

以下指令會把本機 8080 Port 轉送到 tomcat-service8080 Port:

1
kubectl port-forward -n tomcat-test service/tomcat-service 8080:8080

指令格式可以拆成幾個部分來看:

片段 說明
-n tomcat-test 指定 Service 所在的 namespace
service/tomcat-service 指定要轉送的 Kubernetes Service
8080:8080 左邊是本機 Port,右邊是 Service Port

執行後,只要終端機持續保持執行,就可以從本機開啟:

1
http://localhost:8080

成功連線後,就能在瀏覽器看到 Tomcat 首頁。

透過 kubectl port-forward 存取時,流量路徑大致如下:

1
2
3
4
5
本機瀏覽器
-> localhost:8080
-> kubectl port-forward
-> tomcat-service:8080
-> Tomcat Pod:8080

如果本機 8080 Port 已經被其他程式占用,可以換成本機其他 Port,例如把本機 18080 轉送到 Service 的 8080

1
kubectl port-forward -n tomcat-test service/tomcat-service 18080:8080

接著改用下列網址開啟:

1
http://localhost:18080

允許其他主機連線:--address 0.0.0.0

預設情況下,kubectl port-forward 只會綁定在本機的 loopback 位址,也就是 127.0.0.1。因此只有執行指令的那台主機可以透過 localhost:8080 存取服務,區域網路中的其他電腦無法直接連進來。

如果希望讓其他主機也能透過這台電腦的 IP 存取轉送出來的服務,可以加上 --address 0.0.0.0

1
kubectl port-forward --address 0.0.0.0 svc/tomcat-service -n tomcat-test 8080:8080

這個指令會把本機所有網路介面的 8080 Port 都綁起來,並轉送到 tomcat-service8080 Port。假設執行指令的主機 IP 是 192.168.1.50,同一個網路中的其他電腦就可以用下列網址存取 Tomcat:

1
http://192.168.1.50:8080

使用 --address 0.0.0.0 時要特別注意安全性,因為它會讓服務不只暴露給本機,也會暴露給能連到這台主機的其他裝置。建議只在可信任的開發網路中使用,測試完成後立即停止指令;如果連不上,也要確認本機防火牆是否允許外部連入該 Port。

kubectl proxy 與 kubectl port-forward 的差異

kubectl proxykubectl port-forward 都能從本機連到叢集內服務,但它們的使用情境不同。

比較項目 kubectl proxy kubectl port-forward
主要用途 透過 Kubernetes API Server 存取 API 或 Service proxy 路徑 將本機 Port 直接轉送到 Pod 或 Service Port
存取網址 Kubernetes API 路徑較長 像本機服務一樣使用 localhost:<port>
流量路徑 本機 -> API Server -> Service / Pod 本機 -> kubectl -> Service / Pod
適合情境 測試 API Server proxy、臨時查看叢集內服務 本機開發、除錯、用瀏覽器或工具連線
是否需要修改 Service Type 不需要 不需要

簡單來說,如果你想測試 Kubernetes API proxy 路徑,可以用 kubectl proxy;如果你只是想快速從本機瀏覽器、Postman 或其他工具連到叢集內服務,kubectl port-forward 通常會比較直覺。

常見問題排查

確認 Pod 是否正常執行

如果無法連線,先確認 Pod 是否為 Running,以及 READY 狀態是否正常:

1
kubectl get pods -n tomcat-test

確認 Service 是否選到 Pod

Service 必須透過 selector 找到後端 Pod,才有辦法把流量轉送出去。可以用下列指令查看 Endpoints:

1
kubectl get endpoints -n tomcat-test tomcat-service

如果 Endpoints 是空的,通常代表 Service selector 和 Pod label 沒有對上,需要回頭檢查 Deployment 與 Service 的 label 設定。

確認 Service Port

kubectl port-forward 右側的 Port 要對應到 Service Port,而不是隨意填寫。可以用下列指令確認 Service 設定:

1
kubectl get service -n tomcat-test tomcat-service

如果要看更完整的 Service 設定,可以使用:

1
kubectl describe service -n tomcat-test tomcat-service

本機 Port 被占用

如果出現本機 Port 被占用的錯誤,只要更換左側本機 Port 即可。例如:

1
kubectl port-forward -n tomcat-test service/tomcat-service 18080:8080

然後用 http://localhost:18080 存取服務。

小結

kubectl proxykubectl port-forward 都是 Kubernetes 開發與除錯時很實用的臨時連線方式。它們最大的優點是不需要修改 Service Type,也不需要額外建立外部入口,就能快速確認叢集內服務是否正常。

在日常開發中,如果只是要用瀏覽器或 API 工具測試應用程式,通常會優先使用 kubectl port-forward;如果需要透過 Kubernetes API Server 的 proxy 路徑查看資源,則可以使用 kubectl proxy。理解兩者的差異後,就能依照實際情境選擇最適合的方式,把本機與叢集內服務快速接起來。