昨天幫 todo-api 和 todo-frontend 各建了一個 Service,Cluster 內部的溝通沒問題了。今天要學 Ingress,建立一個統一的對外入口,把整個 Todo App 的請求路徑完整跑通 !
昨天學了三種 Service 類型,你可能會想:「直接用 LoadBalancer 對外不就好了?」
問題是:
每個 LoadBalancer Service 都會建立一個獨立的雲端負載平衡器,費用和管理成本直線上升。Todo App 有前端和後端兩個服務,如果都用 LoadBalancer,就要維護兩個負載平衡器,兩個對外 IP。
沒有辦法根據路徑做路由。使用者打 /api/todos 要送到後端、打 / 要送到前端,LoadBalancer 沒有這個能力,它只能把流量全部送給同一個 Service。
Ingress 解決這兩個問題:一個入口、根據路徑或 Host 決定流量送給哪個 Service。
Ingress 是 K8s 的 HTTP/HTTPS 路由規則,定義「什麼樣的請求要送給哪個 Service」。
使用者
│
▼
Ingress(唯一對外入口)
│
├── /api/* → todo-api-service → todo-api Pod
│
└── / → todo-frontend-service → todo-frontend Pod
整個 Todo App 只需要一個對外 IP,Ingress 根據路徑把請求分流到對應的 Service。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: todo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: todo-api-service
port:
number: 80
- path: /()(.*)
pathType: ImplementationSpecific
backend:
service:
name: todo-frontend-service
port:
number: 80
ingressClassName: nginx:指定使用哪個 Ingress Controller 來處理這份規則。這裡用 nginx,minikube 有內建的 nginx Ingress Controller。
annotations:rewrite-target: /$2 是告訴 nginx 把路徑重寫,例如 /api/todos 在進到後端之前會被改成 /todos,這樣 FastAPI 的路由不需要加 /api 前綴。
rules:路由規則列表,按順序比對。pathType: ImplementationSpecific 搭配 capture group (.*) 讓路徑可以正確被重寫。
路由順序很重要:/api 放在 / 前面,因為 / 是萬用規則,放在前面會把所有請求都攔截掉。
今天目標:啟用 minikube 的 nginx Ingress Controller,建立 Ingress 把 /api/* 路由到後端、/ 路由到前端,用 port-forward 驗證整個 Todo App 的請求路徑完整跑通。
minikube addons enable ingress
kubectl get pods -n ingress-nginx

/Todo-App/k8s 目錄下,建立 todo-ingress.yaml:apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: todo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: todo-api-service
port:
number: 80
- path: /()(.*)
pathType: ImplementationSpecific
backend:
service:
name: todo-frontend-service
port:
number: 80
kubectl apply -f todo-ingress.yaml
kubectl get ingress

⚠️ 使用 Docker driver 時 ADDRESS 欄位可能是空白的
使用 Docker driver 時,minikube 跑在 Docker 的網路環境裡,Ingress 拿不到可對外的 IP,ADDRESS欄位會一直空白。這不影響實際運作,Ingress 路由規則還是有效的,改用下方的 port-forward 方式存取即可。
本系列使用 Docker driver,minikube 的 Node IP(192.168.49.2)是 Docker 內部網路的 IP,本機連不到,需要用 port-forward 把流量轉進 Ingress Controller:
kubectl port-forward -n ingress-nginx service/ingress-nginx-controller 8888:80
這個視窗要保持開著,之後用 http://127.0.0.1:8888 存取即可。
- port-forward 只是解決本機進入 minikube 網路的通道問題,流量進去之後一樣完整經過 Ingress 路由,所有 YAML 不需要修改。實際的雲端環境(AWS、GCP)上,Ingress 會有真正的外部 IP,不需要這個步驟。
- 非 Docker driver(Linux)使用者:
ADDRESS欄位會顯示 minikube 的 IP(例如192.168.49.2),可以直接用這個 IP 存取,不需要 port-forward。
# 測試 API(後端)
curl http://127.0.0.1:8888/api/todos
# 測試前端(瀏覽器打開)
# http://127.0.0.1:8888
前端打 API 的完整流量路徑是:
瀏覽器
│
▼
Ingress(127.0.0.1:8888)
│
├── /api/* → todo-api-service → todo-api Pod(FastAPI)
│
└── / → todo-frontend-service → todo-frontend Pod(React + nginx)
從 Day 03 架構圖說的「使用者 → Ingress → Service → Pod」,今天完整跑通了。
Ingress 本身只是一份路由規則的設定,它不會自己做任何事。真正處理流量的是 Ingress Controller。
K8s 沒有內建 Ingress Controller,需要另外安裝。常見的選擇:
可以把 Ingress 想成「nginx 的設定檔」,Ingress Controller 就是那個跑著 nginx 的 Pod,負責讀取你寫的 Ingress 規則並真正執行路由。
這也是為什麼 Ingress 的 annotation 要加 nginx.ingress.kubernetes.io/...——這些是告訴 nginx Ingress Controller 怎麼設定 nginx,不同的 Controller 有不同的 annotation。
今天學了 Ingress,把整個 Todo App 的請求路徑跑通了:
/api/* 送後端、/ 送前端,一個 IP 搞定兩個服務從 Day 04 到今天,Todo App 已經完整跑在 K8s 上了:Deployment 管理 Pod、Service 處理內部路由、Ingress 統一對外入口。
明天會學 ConfigMap,把 todo-api 的環境變數設定從 YAML 裡抽出來,讓設定和程式碼分離。