Kubernetes Ingress 筆記

Posted by Adam on August 24, 2022
## 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。