## Kubernetes Ingress 筆記
### 一句話理解
Ingress 是 Kubernetes 對外 HTTP/HTTPS 流量的「總機規則」。
它根據使用者輸入的網域名稱或 URL 路徑,把請求轉送到正確的 Service,再由 Service 找到實際處理請求的 Pod。
想像一棟辦公大樓:
```text
使用者
↓
大樓總機(Ingress Controller)
↓ 依網域或路徑判斷
A 公司櫃台(Service)
↓
實際員工(Pod)
```
例如:
```text
https://note.example.com → note-web Service → 筆記網站 Pods
https://buy.example.com → group-buy Service → 團購網站 Pods
https://buy.example.com/api → group-buy-api Service → API Pods
```
### Ingress 解決什麼問題?
沒有 Ingress 時,若每個網站都要對外公開,常見作法是每個 Service 都使用 `LoadBalancer`:
```text
note-web Service → 一個公開 IP
group-buy Service → 一個公開 IP
group-buy-api Service → 一個公開 IP
```
這可以運作,但會有幾個問題:
- 每個服務都要一個對外入口與 IP。
- HTTPS 憑證設定分散在每個服務。
- 想依網域或 `/api`、`/admin` 等路徑分流時,設定較零散。
- 雲端環境可能增加 Load Balancer 與公開 IP 的成本。
使用 Ingress 後,通常只要一個公開入口:
```text
Internet
↓
同一個公開 IP / Load Balancer
↓
Ingress Controller
├── note.example.com → note-web
├── buy.example.com → group-buy-web
└── buy.example.com/api → group-buy-api
```
### Ingress、Ingress Controller、Service、Pod 的差別
| 元件 | 角色 | 可以想成 |
|---|---|---|
| Pod | 真正執行程式的單位 | 員工 |
| Service | 為一組 Pod 提供固定名稱與負載平衡 | 部門櫃台 |
| Ingress | 宣告網域、路徑應該轉往哪個 Service 的規則 | 總機轉接表 |
| Ingress Controller | 讀取 Ingress 規則並真正轉送流量的程式 | 真正接電話的總機 |
最重要的觀念:
> `Ingress` 只是規則;`Ingress Controller` 才是實際執行規則的反向代理。
只建立這個 YAML:
```yaml
kind: Ingress
```
但叢集裡沒有 NGINX Ingress Controller、Traefik 等 Controller,就像寫了一張「總機轉接表」,卻沒有聘請總機人員,外部流量不會自動被轉送。
### 請求實際怎麼走?
假設使用者開啟:
```text
https://buy.example.com/api/orders
```
整條路徑如下:
```text
Browser
↓ DNS 查詢
公開 IP 或雲端 Load Balancer
↓
Ingress Controller
↓ 比對 host=buy.example.com、path=/api
group-buy-api Service
↓ 依 selector 尋找健康的 Pod
group-buy-api Pod
↓
回傳 HTTP response
```
其中每一層都各自負責不同事情:
- DNS:把 `buy.example.com` 解析成公開 IP。
- Load Balancer:把 Internet 流量送進 Kubernetes。
- Ingress Controller:判斷該送到哪個 Service。
- Service:從符合 label 的健康 Pod 中挑一個。
- Pod:執行真正的應用程式。
### 最小範例
假設已有一個筆記網站的 Service:
```yaml
apiVersion: v1
kind: Service
metadata:
name: note-web
spec:
# 只在叢集內提供穩定的服務名稱。
type: ClusterIP
selector:
# 找到具有這個 label 的 note-web Pods。
app: note-web
ports:
- port: 80
# Service 的 80 port 轉到 Pod 容器的 8080 port。
targetPort: 8080
```
再建立 Ingress:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: note-web
spec:
# 指定由哪一個 Ingress Controller 處理這份規則。
ingressClassName: nginx
rules:
- host: note.example.com
http:
paths:
- path: /
# /、/posts、/settings 都會符合 Prefix。
pathType: Prefix
backend:
service:
# Ingress 應指向 Service,不是直接寫 Pod IP。
name: note-web
port:
number: 80
```
使用者請求 `https://note.example.com/posts` 時,Ingress Controller 會將請求代理到:
```text
note-web:80 → 某個 app=note-web 的 Pod:8080
```
### HTTPS 在哪裡處理?
Ingress 常常也是 HTTPS 的集中入口。
```yaml
spec:
tls:
- hosts:
- note.example.com
# Secret 內含 TLS 憑證與私鑰。
secretName: note-web-tls
```
流程會變成:
```text
Browser
↓ HTTPS
Ingress Controller
↓ 解開 TLS 後轉送 HTTP 或 HTTPS
note-web Service
↓
Pod
```
好處是應用程式 Pod 通常不必每個都自行管理憑證。實務上常搭配 `cert-manager` 自動申請與續期憑證。
### Ingress 適合與不適合的情境
適合:
- 對外提供網站或 REST API。
- 多個網域共用同一個公開入口。
- 需要依網域或 URL path 分流。
- 想集中處理 TLS、redirect、限流、基本驗證等 HTTP 層需求。
不適合:
- Pod 對 Pod 的內部呼叫:直接使用 Service DNS,例如 `http://group-buy-api`。
- PostgreSQL、Redis、RabbitMQ 等非 HTTP 協定服務。
- 只公開單一服務,且雲端 Load Balancer 已足夠簡單時;直接用 `Service type: LoadBalancer` 也合理。
### 常見誤解
| 誤解 | 正確理解 |
|---|---|
| 建立 Ingress 就能對外連線 | 還需要可運作的 Ingress Controller 與對外入口 |
| Ingress 直接連到 Pod | 標準作法是 Ingress → Service → Pod |
| Service 和 Ingress 功能重複 | Service 處理服務發現與 Pod 分流;Ingress 處理外部 HTTP 路由 |
| Ingress 能代理所有協定 | 主要是 HTTP/HTTPS;資料庫等 TCP 服務通常不應這樣公開 |
| 所有 Ingress 設定都通用 | 基本 `host`、`path` 可攜性較高;許多 annotation 是特定 Controller 的功能 |
### 最後記憶法
```text
Pod = 真正跑程式的人
Service = 找得到人的固定部門電話
Ingress = 哪個網址該轉到哪個部門的規則
Controller = 真正接電話、依規則轉接的總機
```
所以,Ingress 的核心不是「公開一個 Pod」,而是用統一入口,安全且有規則地把外部 HTTP/HTTPS 請求導向正確的 Service。