iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0

前言

昨天我們拆解了 Service 背後的轉發機制 — Label Selector、Endpoints、kube-proxy,搞清楚流量是怎麼從 ClusterIP 到達 Pod 的。

但回到一個現實問題:如果你有十幾個微服務,難道每個都開一個 NodePort,讓使用者記一堆 port 號?

這時候你需要的是 Ingress — 一個統一的入口,透過 URL 路徑或域名 把流量分發到不同的 Service。

今天會從三個層面來學 Ingress:

  1. Ingress 是什麼? — 了解 Ingress 的用途,以及與 Service 的差異
  2. Ingress Controller — 負責讀取 Ingress 規則並執行流量轉送
  3. 動手實作 — 建立路徑與網域路由規則

以下操作皆在 master 節點 執行。


一、Ingress 是什麼?

先來搞清楚 Ingress 在 Kubernetes 網路架構中的定位:

比較項目 Service(NodePort) Ingress
運作層級 L4(TCP / UDP) L7(HTTP / HTTPS)
路由方式 透過 Node IP:NodePort 存取指定 Service 根據 Host / Path 將流量導向不同 Service
TLS 終止 本身不負責 TLS 終止 可由 Ingress Controller 統一處理 TLS 終止
適合場景 直接將 Service 暴露至叢集外部 多個 HTTP / HTTPS Service 共用對外入口

簡單說:Service 對應一組後端 Pod,Ingress 則可以透過路由規則把流量導向多個 Service

但這裡有一個很重要的觀念:

Ingress 只是「規則」,不是「執行者」

Ingress 資源本身只定義路由規則,例如「哪個路徑要導向哪個 Service」。

真正讀取這些規則並執行流量轉送的,是 Ingress Controller。如果沒有安裝 Ingress Controller,即使建立了 Ingress 資源,也不會實際產生流量轉送效果。


二、Ingress Controller — 路由規則的執行者

你可以把 Ingress Controller 想成是 L7 層的 kube-proxy

  • kube-proxy:監看 Service / EndpointSlice 的變化 → 設定 L4 流量轉送規則(iptables / nftables / IPVS)
  • Ingress Controller:監看 Ingress 資源的變化 → 建立 L7 路由與反向代理設定(例如 NGINX 設定),並依照 Host / Path 將流量轉送到對應的 Service

常見的 Ingress Controller

Controller 底層技術 特色
Traefik Traefik Proxy 支援 Kubernetes Ingress,設定相對簡單,並可動態更新路由設定。
AWS Load Balancer Controller AWS ALB / NLB 可根據 Ingress 建立 ALB,也可根據 Service 建立 NLB,適合 AWS 環境。
HAProxy Kubernetes Ingress Controller HAProxy 支援 HTTP、TCP 路由,適合需要高效能與進階流量控制的場景。
Ingress NGINX NGINX 過去非常普及,但已於 2026 年 3 月停止維護,不建議新環境採用。

本章為了理解 Ingress 的基本運作方式,仍使用 Ingress NGINX 進行實作。實際新建的正式環境,建議評估其他仍持續維護的 Ingress Controller,或採用 Gateway API。


安裝 NGINX Ingress Controller

用官方提供的 YAML manifest 安裝,這裡使用 裸機(Bare Metal) 版本,Service 類型會自動設為 NodePort:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.1/deploy/static/provider/baremetal/deploy.yaml

這一行指令會建立 ingress-nginx namespace,並部署 Controller 所需的所有資源(Deployment、Service、ConfigMap、RBAC 等)。

https://ithelp.ithome.com.tw/upload/images/20260808/20181928RlCHKC8013.png

等待 Controller Pod 跑起來:

kubectl get pods -n ingress-nginx -w

看到 ingress-nginx-controller-xxx 狀態為 Running 就 OK 了。

https://ithelp.ithome.com.tw/upload/images/20260808/201819282TfC0eKwsh.png

確認 Ingress Controller 建立的 Service:

kubectl get svc -n ingress-nginx

你會看到 ingress-nginx-controller 的 Service 類型是 NodePort,記下 80:3xxxx443:3xxxx 對應的 NodePort,後面測試會用到。

https://ithelp.ithome.com.tw/upload/images/20260808/20181928L14aLSnPAr.png

為什麼使用 baremetal 版本?

Ingress Controller 會依部署環境提供不同的安裝方式。雲端環境通常可透過 LoadBalancer 類型的 Service,整合雲端供應商提供的 Load Balancer 與外部 IP。

裸機環境通常沒有雲端 Load Balancer 可直接整合,因此可使用 baremetal 版本,透過 NodePort 將 Ingress Controller 對外暴露,並使用 Node IP:NodePort 的方式進行存取。


三、準備兩組後端服務

為了測試 Ingress 的路由功能,我們需要兩組不同的服務來分辨流量有沒有正確分流。

建立 app-a

kubectl create deployment app-a --image=nginx
kubectl expose deployment app-a --port=80

建立 app-b

kubectl create deployment app-b --image=nginx
kubectl expose deployment app-b --port=80

確認兩個服務都正常:

kubectl get pods,svc -l 'app in (app-a, app-b)'

https://ithelp.ithome.com.tw/upload/images/20260808/20181928B35SLn21KA.png

等 Pod 都 Running 之後,分別寫入不同的首頁內容來區分兩個服務:

# 寫入 app-a 的回應
kubectl exec deploy/app-a -- bash -c 'echo "Hello from App A" > /usr/share/nginx/html/index.html'

# 寫入 app-b 的回應
kubectl exec deploy/app-b -- bash -c 'echo "Hello from App B" > /usr/share/nginx/html/index.html'

四、Path-based Routing — 依路徑分流

現在來建立第一個 Ingress 規則:根據 URL 路徑決定流量去哪裡。

建立 YAML 檔案:

vim ingress.yaml

寫入以下內容:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /app-a
        pathType: Prefix
        backend:
          service:
            name: app-a
            port:
              number: 80
      - path: /app-b
        pathType: Prefix
        backend:
          service:
            name: app-b
            port:
              number: 80

關鍵欄位說明

  • rewrite-target: / — 將符合規則的請求路徑改寫為 / 後,再轉送至後端 Service。
  • ingressClassName: nginx — 指定由 NGINX Ingress Controller 處理這個 Ingress。
  • rules[].http.paths[] — 定義不同路徑要轉送到哪個 Service。
  • pathType: Prefix — 使用路徑前綴進行匹配,例如 /app-a 也可以匹配 /app-a/xxx

套用並查看狀態:

kubectl apply -f ingress.yaml
kubectl get ingress demo-ingress

測試路由

curl 測試(把 <NODE_IP><NODE_PORT> 替換成實際值):

# 打 /app-a 路徑
curl http://<NODE_IP>:<NODE_PORT>/app-a

# 打 /app-b 路徑
curl http://<NODE_IP>:<NODE_PORT>/app-b

你應該會看到:

https://ithelp.ithome.com.tw/upload/images/20260808/20181928WYecR8usZx.png

https://ithelp.ithome.com.tw/upload/images/20260808/20181928X3i2nfXfQB.png

同一個入口,不同路徑,自動導到不同的 Service! 這就是 Ingress 的核心價值。


五、Host-based Routing — 依域名分流

除了路徑,Ingress 也可以根據 域名(Host) 來分流。這在多個應用共用同一個 IP 時特別有用。

建立 YAML 檔案:

vim host-ingress.yaml

寫入以下內容:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: host-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: a.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-a
            port:
              number: 80
  - host: b.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-b
            port:
              number: 80

套用:

kubectl apply -f host-ingress.yaml

用 /etc/hosts 模擬域名

在測試機器上加入 DNS 映射(把 <NODE_IP> 換成你的 Node IP):

echo "<NODE_IP> a.example.com b.example.com" | sudo tee -a /etc/hosts

測試

curl http://a.example.com:<NODE_PORT>/
# → Hello from App A

curl http://b.example.com:<NODE_PORT>/
# → Hello from App B

https://ithelp.ithome.com.tw/upload/images/20260808/20181928kQHwzcxX8r.png

同一個 IP 和 Port,不同域名,自動導到不同 Service。 這就是 Host-based Routing 的威力。


六、TLS — 讓 Ingress 支援 HTTPS

在生產環境中,通常會使用 HTTPS。Ingress Controller 可以在入口處進行 TLS 終止(TLS Termination),將外部 HTTPS 流量解密後,再以 HTTP 轉送至後端 Service。

建立自簽憑證(測試用)

openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout tls.key \
  -out tls.crt \
  -subj "/CN=a.example.com"

把憑證存成 Kubernetes Secret

kubectl create secret tls demo-tls \
  --cert=tls.crt \
  --key=tls.key

更新 Ingress 加上 TLS

建立 YAML 檔案:

vim tls-ingress.yaml

寫入以下內容:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - a.example.com
    secretName: demo-tls
  rules:
  - host: a.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-a
            port:
              number: 80

因為 tls-ingress 和前面的 host-ingress 都定義了 a.example.com + / 的規則,NGINX Ingress Controller 不允許重複,所以要先刪掉 host-ingress 再套用:

kubectl delete ingress host-ingress
kubectl apply -f tls-ingress.yaml

測試 HTTPS(-k 忽略自簽憑證警告):

curl -k https://a.example.com:<HTTPS_NODE_PORT>/
# → Hello from App A

https://ithelp.ithome.com.tw/upload/images/20260808/20181928ldlxkU0rSi.png

生產環境建議

手動管理 TLS 憑證較為繁瑣,建議使用 cert-manager 搭配 Let's Encrypt,自動申請與續期 TLS 憑證。

這部分會在後續章節再進一步介紹。


七、完整流量路徑圖

把今天學到的串起來,從外部請求到 Pod 的完整路徑:

Client(瀏覽器 / curl)
  │
  │  https://a.example.com/api/users
  │
  ▼
Ingress Controller(NGINX Pod)
  │
  │  ① TLS 終止,解密 HTTPS
  │  ② 根據 Ingress 規則進行路由判斷
  │  ③ Host: a.example.com → 匹配對應規則
  │  ④ Path: /api/users → 導向 app-a Service
  │
  ▼
Service(ClusterIP)
  │
  │  根據 kube-proxy 建立的轉送規則
  │  選擇一個後端 Endpoint
  │
  ▼
Pod(實際處理請求)

小結

今天我們學會了用 Ingress 統一管理微服務的入口流量:

概念 角色 說明
Ingress 路由規則 定義「哪個 Host / Path 要導向哪個 Service」。
Ingress Controller 規則執行者 監看 Ingress 規則,建立反向代理設定,並實際處理與轉送外部流量。
Path-based Routing 路徑分流 根據 URL Path 將流量導向不同 Service,例如 /app-a → Service A。
Host-based Routing 網域分流 根據 Host 將流量導向不同 Service,例如 a.example.com → Service A。
TLS Termination HTTPS 處理 由 Ingress Controller 在入口處終止 TLS,再將請求轉送至後端 Service。

到目前為止,我們已經完成 Pod → Service → Ingress 的完整流量路徑,了解外部請求如何一路被導向實際處理請求的 Pod。

不過,應用程式除了需要接收流量,也需要管理各種設定檔與機密資訊,例如資料庫密碼、API Key 等。

明天我們會接著介紹 ConfigMap 與 Secret,看看 Kubernetes 如何管理應用程式的設定與機密資料!


參考資源


上一篇
Day 05|Service 背後的秘密 — kube-proxy 與流量轉發機制
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言