Kubernetes Ingress 使用指南

什麼是 Ingress?

Kubernetes Ingress 是一個 API 物件,用於管理對叢集內服務的外部存取,通常是 HTTP/HTTPS 流量。Ingress 提供了負載平衡、SSL 終止和基於名稱的虛擬主機功能。

Ingress 的主要功能:

  • 路由管理:根據 URL 路徑或主機名稱將流量路由到不同的服務
  • 負載平衡:在多個後端服務之間分配流量
  • SSL/TLS 終止:處理 HTTPS 加密和解密
  • 域名綁定:支援基於域名的虛擬主機

為什麼使用 Ingress?

相較於直接使用 NodePort 或 LoadBalancer 類型的 Service,Ingress 提供了更靈活的流量管理方式:

  1. 成本效益:一個 Ingress Controller 可以處理多個服務的外部存取
  2. 統一管理:集中管理所有外部流量的路由規則
  3. 高級功能:支援路徑重寫、認證、限流等進階功能

實作範例

這篇沿用前一篇 Service 建立好的 Spring Boot 應用程式與 dockertest-clusterip Service,直接示範如何用 Ingress 將外部 HTTP 流量導向叢集內的 Service。

整體流量會是:

1
2
3
4
5
6
使用者瀏覽器
-> http://dockertest.local/hello
-> Ingress Controller
-> dockertest-ingress
-> dockertest-clusterip Service
-> dockertest Pod:8080

確認前置資源

Namespace、Registry Secret、Deployment 與 ClusterIP Service 的建立方式前一篇 Service 已經示範過,這裡直接沿用那個結果,把重點放在 Ingress 如何接住外部 HTTP 流量。

開始前只要確認叢集裡已有下列資源:

  • dockertest namespace
  • dockertest-deployment Deployment,並且 Pod 已經 Ready
  • dockertest-clusterip Service,對外提供 8080 port
  • Service Endpoints 已經出現後端 Pod IP

可以用下列指令快速檢查:

1
2
3
4
5
6
7
8
9
10
11
# 等待 Deployment 完成 rollout
kubectl rollout status deployment/dockertest-deployment -n dockertest

# 查看 Pod 狀態
kubectl get pods -l app=dockertest -n dockertest

# 查看 Service
kubectl get service dockertest-clusterip -n dockertest

# 查看 Service 後端 Endpoints
kubectl get endpoints dockertest-clusterip -n dockertest

如果 Endpoints 有出現 Pod IP,代表 Service 已經找到符合 app: dockertest label 的 Pod。接下來就不再重複 Deployment 與 Service 的 YAML,直接進入 Ingress 設定。

啟用 Ingress Controller

Ingress 只是 Kubernetes 的路由規則,真正接收外部流量的是 Ingress Controller。以 Minikube 為例,可以先啟用內建的 NGINX Ingress Controller:

1
minikube addons enable ingress

確認 Controller 已啟動:

1
kubectl get pods -n ingress-nginx

建立 Ingress 規則

接著建立 Ingress,讓外部使用者可以透過 dockertest.local 這個網域名稱存取 Spring Boot 服務。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dockertest-ingress
namespace: dockertest
spec:
ingressClassName: nginx
rules:
- host: dockertest.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dockertest-clusterip
port:
number: 8080

這段設定的重點是 backend.service.name 必須指向前面建立的 dockertest-clusterip Service,而 backend.service.port.number 則要對應 Service 的 port: 8080。Ingress 不會直接連到 Pod,而是透過 Service 將流量送到符合 selector 的後端 Pod。

設定本機 hosts

在本機測試時,需要讓 dockertest.local 指向 Minikube IP:

1
minikube ip

取得 IP 後,將下面這行加入 hosts 檔案:

1
<MINIKUBE_IP>  dockertest.local

不同作業系統的 hosts 檔案位置如下:

作業系統 hosts 檔案位置
Windows C:\Windows\System32\drivers\etc\hosts
Linux / macOS /etc/hosts

部署與測試 Ingress

將 Ingress 設定存成 dockertest-ingress.yaml 後,可以使用下列指令部署:

1
2
3
4
5
6
7
8
# 建立 Ingress
kubectl apply -f dockertest-ingress.yaml

# 查看 Ingress 狀態
kubectl get ingress dockertest-ingress -n dockertest

# 查看 Ingress 詳細規則與事件
kubectl describe ingress dockertest-ingress -n dockertest

完成本機 hosts 設定後,就可以測試 Ingress 是否能從外部導流到 Spring Boot 應用程式:

1
curl http://dockertest.local/hello

預期會取得下列回應:

1
Hello, World!

若無法連線,可以先確認 dockertest.local 是否正確指向 Minikube IP,再檢查 Ingress Controller、Ingress 規則、Service Endpoints 與 Pod readinessProbe 狀態。

多路由設定規則

當系統內有多個服務需要共用同一個 Ingress Controller 對外提供 HTTP 入口時,可以在同一份 Ingress 中定義多組 rules 或多個 paths。常見做法有兩種:一種是依照不同網域名稱導向不同 Service,另一種是依照 URL path 導向不同 Service。

以下範例中的 dockertest-admin-clusteripdockertest-api-clusterip 代表額外的後端 Service。實際測試前,需要先用相同方式建立對應的 Deployment 與 Service,否則 Ingress 會找不到可導流的後端。

多網域路由

多網域路由適合用在不同應用程式使用不同 domain 的情境。例如 dockertest.local 導向 Spring Boot 服務,admin.dockertest.local 導向後台管理服務:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dockertest-multi-host-ingress
namespace: dockertest
spec:
ingressClassName: nginx
rules:
- host: dockertest.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dockertest-clusterip
port:
number: 8080
- host: admin.dockertest.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dockertest-admin-clusterip
port:
number: 8080

這種設定會先比對 host,再將流量送到對應的 Service。測試時 hosts 檔案也需要同時加入兩個網域:

1
2
<MINIKUBE_IP>  dockertest.local
<MINIKUBE_IP> admin.dockertest.local

多路徑路由

多路徑路由適合用在同一個 domain 下,依照 API 或功能路徑拆分後端服務。例如 / 導向前台服務,/admin 導向後台服務,/api 導向 API 服務:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dockertest-multi-path-ingress
namespace: dockertest
spec:
ingressClassName: nginx
rules:
- host: dockertest.local
http:
paths:
- path: /admin
pathType: Prefix
backend:
service:
name: dockertest-admin-clusterip
port:
number: 8080
- path: /api
pathType: Prefix
backend:
service:
name: dockertest-api-clusterip
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: dockertest-clusterip
port:
number: 8080

使用 Prefix 時,/admin 會匹配 /admin/admin/users/api 會匹配 /api/api/hello。如果多個 path 都可能匹配同一個請求,Ingress Controller 通常會優先使用最長、最精確的路徑,因此建議把較明確的路徑寫清楚,再保留 / 作為預設入口。

多路由設定時要特別確認每個 backend.service.name 都已經有對應的 Service,而且 Service 的 port 要和 Ingress 的 backend.service.port.number 一致。Ingress 只負責 HTTP 路由規則,真正的 Pod 選取仍然由各自的 Service selector 決定。

多路由部署與測試

如果要測試多網域路由,可以將設定存成 dockertest-multi-host-ingress.yaml 後套用:

1
2
3
kubectl apply -f dockertest-multi-host-ingress.yaml
kubectl get ingress dockertest-multi-host-ingress -n dockertest
kubectl describe ingress dockertest-multi-host-ingress -n dockertest

測試多網域路由前,hosts 檔案需要同時加入主要服務與後台服務的網域:

1
2
<MINIKUBE_IP>  dockertest.local
<MINIKUBE_IP> admin.dockertest.local

接著分別測試兩個網域是否導向正確的 Service:

1
2
3
4
5
# 測試前台服務
curl http://dockertest.local/hello

# 測試後台服務
curl http://admin.dockertest.local/hello

如果要測試多路徑路由,可以將設定存成 dockertest-multi-path-ingress.yaml 後套用:

1
2
3
kubectl apply -f dockertest-multi-path-ingress.yaml
kubectl get ingress dockertest-multi-path-ingress -n dockertest
kubectl describe ingress dockertest-multi-path-ingress -n dockertest

接著用同一個 domain 搭配不同 path 測試導流結果:

1
2
3
4
5
6
7
8
# 測試前台服務
curl http://dockertest.local/hello

# 測試後台服務
curl http://dockertest.local/admin/hello

# 測試 API 服務
curl http://dockertest.local/api/hello

測試多路由時,如果某一條路由無法正常回應,可以先檢查該路由對應的 Service 是否存在,以及 Service Endpoints 是否有 Pod IP:

1
2
kubectl get service -n dockertest
kubectl get endpoints -n dockertest

如果應用程式正常回應,代表外部流量已經成功經過 Ingress Controller、Ingress 規則、ClusterIP Service,最後抵達後端 Pod。

Ingress 欄位說明

欄位 說明
ingressClassName 指定由哪一種 Ingress Controller 處理這份規則,例如 nginx
rules.host 指定要匹配的網域名稱,例如 dockertest.local
paths.path 指定 URL 路徑匹配規則,/ 代表從根路徑開始
paths.pathType 指定路徑比對方式,常見值為 PrefixExact
backend.service.name 指定要導流到哪一個 Service
backend.service.port.number 指定 Service 對外提供的 port

小結

在這個案例中,Deployment 負責建立 Spring Boot Pod,dockertest-clusterip Service 負責提供穩定的叢集內入口,而 Ingress 則負責把 dockertest.local 的外部 HTTP 流量導向該 Service。這也是 Ingress 最常見的使用方式:應用程式本身不需要直接暴露成 NodePort 或 LoadBalancer,而是透過 Service 作為內部入口,再由 Ingress Controller 統一管理對外路由。