iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
Kubernetes

不囉唆圖解 Kubernetes系列 第 16 篇

Day 16:大門地圖看板 Ingress,一個網域分流到多個服務

  • 分享至 

  • xImage
  •  

Day 16:大門地圖看板 Ingress,一個網域分流到多個服務

Ingress 忙什麼?

有五個服務要對外。
開五個 NodePort,就是五個難記的埠號;開五個 LoadBalancer,就是五份帳單。

https://ithelp.ithome.com.tw/upload/images/20260929/20124462Wc7FsbzsjT.png
島的大門旁立著一塊地圖看板(Ingress),看板上分岔出兩條路線,分別指向島內兩根不同的圖騰柱(Service)。

柱子 Service 只認埠號,看板 Ingress 才認網址

https://ithelp.ithome.com.tw/upload/images/20260929/20124462799NezOsV3.png
昨天那三種柱子(Service)有個共同的限制:它們只認得埠號,不認得網址。

從外面打進來的封包,柱子(Service)看到的是「有人敲 30080 這個門」。
它沒辦法知道對方想去 /hello 還是 /api,也不知道對方輸入的網域是 shop.com 還是 blog.com。
要分辨這些,得先把 HTTP 內容拆開來看,而柱子(Service)的層級太低,看不到那裡。

所以島的大門旁邊立了一塊地圖看板(Ingress),做的事情很單純:先讀你要去哪,再告訴你走哪條路。

看板(Ingress)自己不提供任何服務,它只是把「網址」翻譯成「哪一根柱子(Service)」。
真正讀取規則並轉送流量的是旁邊的 守門員(Ingress Controller)。

在常見的單一 Controller 配置裡,多個對外服務可以共用入口與位址,再靠網址分流;實際也可能有多個 Controller 或 443 HTTPS 入口。
這一下就解決了開頭那個痛點:五個服務,一個入口,零份額外帳單。

看板(Ingress)認得兩種規則,通常混著用:

path 規則:看路徑
/hello 送到 hello 柱子(Service),/api 送到 api 柱子,適合同一個網域下拆功能。

host 規則:看網域
shop.example.com 送到一根柱子(Service),blog.example.com 送到另一根,適合一座島上放好幾個不同的網站。

今天最大的坑:Ingress 本身不會動

https://ithelp.ithome.com.tw/upload/images/20260929/20124462shREVQsxcQ.png
地圖看板(Ingress)後面站著一位讀看板的居民,手上的指示牌指向其中一根圖騰柱(Service),這位居民本身才是真的在幹活的人。

Ingress 這個資源本身不會動。
寫的那份 YAML 只是一張規則表,它需要有人真的去讀它、然後真的去轉發封包。
那個「有人」叫做 Ingress Controller,而它預設不存在,要自己另外裝。

這跟目前為止學的所有東西都不一樣。
部署管家(Deployment)、貓頭鷹(ReplicaSet)、柱子(Service)由叢集元件直接處理;Ingress 資源則需要額外的 Controller。

寫完 Ingress 卻發現完全沒反應,沒裝或沒對上 Ingress Controller 是常見原因之一;也要檢查 class、Service、DNS 與 port mapping。

Controller 有很多牌子,最常見的是 ingress-nginx(就是拿 Nginx 改的)。
裝好之後,Controller 自己也會以 Pod 與 Service 的形式運作;Ingress 資源則由它讀取並執行。

Ingress 管的只有 HTTP

還有一個界線要劃清楚:標準 Ingress API 主要描述 HTTP/HTTPS 路由。

資料庫、Redis 或自訂 TCP 流量要看 Controller 是否提供額外的 TCP/UDP 能力;gRPC 通常可透過 HTTP/2 支援,那些還是得走昨天的柱子(Service)。
看板(Ingress)主要描述網站的 HTTP/HTTPS 入口;其他協定要依 Controller 能力與 Service 設計處理。

HTTPS 憑證也是掛在看板(Ingress)上的(spec.tls 欄位)。
所有服務共用一個入口的另一個好處,就是憑證只要管一份。

最後一句話交代 ingressClassName:島上可以同時裝好幾牌 Controller,這個欄位就是在說「這張規則表歸誰管」。
裝 ingress-nginx 就填 nginx。

動手 5 分鐘

前十五天我們有一根 ClusterIP 的 hello 柱子(Service)。今天要在大門立看板(Ingress),讓你的瀏覽器能直接打進來。

先講一件事:Kind 的島預設沒有把 80 埠接到你的筆電上,所以我們得重建叢集,另外也不會遺失設定,這正是宣告式設定的優勢,你的東西全在 YAML 檔案裡,也是寫檔案的價值。

建立 kind-config.yaml:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP

extraPortMappings 把樹的 80 埠接到你電腦的 80 埠;ingress-ready=true 是貼在樹上的貼紙(Label),等一下 Controller 會拿放大鏡(Selector)找它。

砍掉重蓋:

kind delete cluster --name hello
kind create cluster --name hello --config kind-config.yaml
kubectl get nodes

一分鐘後新島就緒。把你的服務搬回來:

kubectl apply -f hello-deployment.yaml
kubectl apply -f hello-service.yaml
kubectl get pods,svc

三顆泡泡(Pod)加一根柱子(Service),兩行指令復原。

現在裝 Controller:

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

等它起來(這行會卡住直到準備好,最多九十秒):

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

看看那位居民:

kubectl get pods -n ingress-nginx

Controller 自己就是一顆泡泡(Pod),住在 ingress-nginx 這道圍籬(Namespace)裡。

https://ithelp.ithome.com.tw/upload/images/20260929/201244623kNbIelOL7.png
看板(Ingress)要由島上的守門員(Ingress Controller)讀取後才會產生效果。

立看板(Ingress)。建立 hello-ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello
  annotations:
    # 若後端服務本身沒有處理 /hello 前綴,才需使用 rewrite-target 轉發
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          - path: /hello(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: hello
                port:
                  number: 80

那個 rewrite-target 是在說「把 /hello 這段砍掉再往後送」── 因為你的 Nginx 根本沒有 /hello 這個頁面,它只有 /。不加這行你會拿到 404。

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

打開瀏覽器輸入 http://localhost/hello:

Nginx 的 Welcome 頁出現了。 沒有 port-forward、沒有奇怪的埠號、沒有雲端帳單。

https://ithelp.ithome.com.tw/upload/images/20260929/20124462Rs1dZCrbNy.png
網址列就是 localhost/hello,走的是 80 埠。

試試 host 規則。把 spec.rules 那段改成:

  rules:
    - host: hello.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: hello
                port:
                  number: 80
kubectl apply -f hello-ingress.yaml
curl -s -H "Host: hello.local" http://localhost | head -5
curl -s http://localhost | head -3

第一行通了,第二行回 404 ── 看板(Ingress)現在只認 hello.local 這個網域,其他一律不理。

那個 -H "Host: hello.local" 是在騙看板(Ingress)說「我是從這個網域來的」。
實際上線時這一段由 DNS 負責,你把網域指到看板的 IP 就好,規則寫法完全一樣。想在本機用真的網址測,把 hello.local 加進你的 /etc/hosts 指到 127.0.0.1,瀏覽器就能直接開。

小結

看板(Ingress)只是規則表,得有人讀它才會動。

參考資源


上一篇
Day 15:k8s 的 ClusterIP、NodePort、LoadBalancer 差在哪?
系列文
不囉唆圖解 Kubernetes 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言