跳轉至

03 - 網路與服務 (Networking & Service)

目標:理解 Pod 一直在生滅、IP 一直在變的情況下,服務之間怎麼穩定互連、外部流量怎麼進來、名字怎麼解析。讀完你要能選對 Service 類型、用 Ingress 對外、講清楚 CoreDNS 的角色。


1. 先建立網路心智模型:K8s 的網路三條規則

K8s 對網路有三個基本承諾(由 CNI 網路外掛實作,例如 Calico、Flannel、Cilium):

  1. 每個 Pod 有自己的 IP,而且是叢集內可路由的真實 IP。
  2. Pod 之間可以直接用 IP 互通,不需要 NAT——不管在不在同一台節點。
  3. 節點上的程式也能跟 Pod 用 IP 互通

這三條是 Kubernetes 網路模型的官方定義。

這帶來一個「扁平網路 (flat network)」的直覺:在叢集內,任何 Pod 都能直接連到任何 Pod 的 IP,彷彿大家都在同一個區網。

flowchart TB
    subgraph N1["Node 1 (10.0.0.0/24)"]
        PA["Pod A<br/>10.0.0.5"]
        PB["Pod B<br/>10.0.0.6"]
    end
    subgraph N2["Node 2 (10.0.1.0/24)"]
        PC["Pod C<br/>10.0.1.7"]
    end
    PA <-->|直接連,不用 NAT| PC
    PA <--> PB

那為什麼還需要 Service? 因為 Pod IP 會變。第 2 章說過 Pod 是用過即丟的——升級、擴縮、故障重建,IP 全變。你不能把另一個服務的 Pod IP 寫死在設定裡。你需要一個穩定的、會自動追蹤後端的入口。這就是 Service。


2. Service:給一群 Pod 一個穩定門牌

Service 做兩件事:

  1. 提供一個固定不變的虛擬 IP(ClusterIP)和 DNS 名稱
  2. 標籤選擇器 (label selector) 自動找到一群符合的 Pod,把進來的流量負載平衡 (load balance) 分給它們。

關鍵:Pod 來來去去,但 Service 的 IP 與名字始終不變。前端只要記得 Service,不用管後面 Pod 怎麼換。

flowchart LR
    Client[呼叫方] --> SVC["Service: web<br/>ClusterIP 10.96.0.10<br/>(固定)"]
    SVC -->|selector: app=web| P1[Pod 10.0.0.5]
    SVC --> P2[Pod 10.0.0.6]
    SVC --> P3[Pod 10.0.1.7]

2.1 它怎麼知道後面有哪些 Pod?Endpoints / EndpointSlice

Service 並不直接連 Pod。背後有個機制:EndpointSlice 控制器持續掃描「符合 selector 且已就緒 (ready) 的 Pod」,把它們的 IP 列成一份清單。Service 的流量就導向這份清單。EndpointSlice 是現行的標準機制,取代舊版的 Endpoints API(舊 API 在大規模叢集下有單一物件被截斷等限制,自 v1.33 起依 KEP-4974 正式標示為棄用,讀寫 v1 Endpoints 會收到 API Server 的棄用警告)(EndpointSlices 官方文件Kubernetes v1.33 部落格:Endpoints → EndpointSlice 過渡說明)。

這也是為什麼 readiness 探針(第 5 章)很重要:沒就緒的 Pod 不會被列入 Endpoints,流量不會打到它。 升級時這保證了「只有準備好的 Pod 才接客」。

kubectl get endpointslices              # 看 Service 背後實際連到哪些 Pod IP
kubectl describe svc web                 # Endpoints 欄位列出後端 IP

2.2 kube-proxy 怎麼讓 ClusterIP 通?

ClusterIP 是個虛擬 IP,沒有任何網卡真的擁有它。是每台節點上的 kube-proxy 設定了封包轉發規則:當有封包要送到這個 ClusterIP,就攔截下來、(預設)隨機挑一個後端 Pod IP、改寫目的地。所以負載平衡其實發生在每台節點的核心網路層,不是某個集中的代理(Virtual IPs and Service Proxies)。

模式現況:Linux 上預設模式是 iptables;nftables 模式已於 v1.33 晉升為穩定版,官方鼓勵在較新核心上嘗試(NFTables mode for kube-proxy);舊有的 IPVS 模式已於 v1.35KEP-5495 被標示為棄用 (deprecated)——這只是「多版本漸進式移除」時程的第一步,完整的棄用/移除排程(1.37 feature gate、1.43 才真正移除程式碼)見 03-ebpf 章節「5. eBPF 與 Kubernetes」第 5.1 節的詳細考證。


3. Service 四種類型

類型 暴露範圍 怎麼存取 典型用途
ClusterIP(預設) 僅叢集內 叢集內 IP / DNS 服務間互連(後端、DB)
NodePort 叢集外(透過節點 IP) <任一節點IP>:<30000-32767> 開發測試、簡單對外
LoadBalancer 叢集外(雲端 LB) 雲端配發的外部 IP 正式環境對外服務
ExternalName DNS CNAME 把外部服務包成叢集內名字

它們是層層疊加的:NodePort 自帶一個 ClusterIP;LoadBalancer 又自帶一個 NodePort 與 ClusterIP。

flowchart LR
    EXT[外部使用者] -->|LoadBalancer 外部 IP| LB
    LB -->|內含 NodePort| NP["NodePort 30080"]
    NP -->|內含 ClusterIP| CIP["ClusterIP 10.96.0.10"]
    CIP --> PODS[後端 Pods]

3.1 ClusterIP(預設,最常用)

只在叢集內可達:給一群 Pod 一個固定虛擬 IP,外部完全連不進來

flowchart LR
    subgraph CLUSTER["叢集內部"]
        C["其他 Pod<br/>(呼叫方)"] --> SVC["ClusterIP<br/>10.96.0.10<br/>(虛擬 IP)"]
        SVC --> P1["Pod :8080"]
        SVC --> P2["Pod :8080"]
    end
    EXT["外部使用者"] -. 連不進來 .-x SVC
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP            # 預設可省略
  selector:
    app: web                 # 把流量導到帶 app=web 標籤的 Pod
  ports:
    - port: 80               # Service 對外的埠(別人連這個)
      targetPort: 8080       # 轉到 Pod 容器的埠

3.2 NodePort

在「每一台節點」上開一個固定埠(預設範圍 30000-32767,可用 kube-apiserver 的 --service-node-port-range 調整),外部用任一節點 IP 加這個埠就能進來。每台節點都監聽同一個埠,打到哪台都會被轉進內部的 ClusterIP(Service 官方文件 — type: NodePort)。

flowchart LR
    EXT["外部使用者"] -->|"任一 NodeIP:30080"| N1
    EXT -->|"任一 NodeIP:30080"| N2
    subgraph CLUSTER["叢集"]
        N1["Node 1<br/>:30080"] --> SVC["ClusterIP<br/>10.96.0.10"]
        N2["Node 2<br/>:30080"] --> SVC
        SVC --> P1["Pod"]
        SVC --> P2["Pod"]
    end
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: NodePort
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30080        # 不指定會隨機配;範圍 30000-32767

NodePort 適合學習與測試,不適合正式環境:埠號醜、要自己知道節點 IP、沒有 L7 路由。

3.3 LoadBalancer

請雲端供應商配一個外部負載平衡器,給你一個對外 IP。本機(kind/minikube)沒有真正的雲端 LB,可以用 minikube tunnel 或 MetalLB 模擬。流量路徑是 雲端 LB → 各節點的 NodePort → ClusterIP → Pod,層層疊加。

flowchart LR
    EXT["外部使用者"] -->|"對外 IP"| LB["雲端負載平衡器<br/>(AWS ELB / GCP LB...)"]
    subgraph CLUSTER["叢集"]
        LB --> N1["Node 1<br/>:30080 (NodePort)"]
        LB --> N2["Node 2<br/>:30080 (NodePort)"]
        N1 --> SVC["ClusterIP<br/>10.96.0.10"]
        N2 --> SVC
        SVC --> P1["Pod"]
        SVC --> P2["Pod"]
    end
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

3.4 ExternalName

不選 Pod,而是把一個叢集內名字對應到外部 DNS(回傳 CNAME)。用來把「外部資料庫」包裝成像叢集內服務一樣呼叫。沒有 selector、沒有 ClusterIP、不做任何代理——它純粹是 DNS 層的別名。

flowchart LR
    P["叢集內 Pod"] -->|"① 查 external-db"| DNS["CoreDNS"]
    DNS -->|"② 回傳 CNAME<br/>db.example.com"| P
    P ==>|"③ 直接連外部"| EXTDB[("外部資料庫<br/>db.example.com")]
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: db.example.com    # 叢集內連 external-db 會被解析成這個外部域名

3.5 Headless Service(無頭服務)

特例:把 clusterIP 設成 None。這時 Service 不分配虛擬 IP、不做負載平衡,而是讓 DNS 直接回傳「所有後端 Pod 的 IP」。對照前面幾種類型「先連到一個 VIP 再分流」,無頭服務是把整份 Pod IP 清單交給呼叫方,由呼叫方自己決定連哪個。第 2 章的 StatefulSet 就靠它給每個 Pod 固定 DNS(web-0.web...)(Service 官方文件 — Headless Services)。

flowchart LR
    P["呼叫方 Pod"] -->|"查 web 的 DNS"| DNS["CoreDNS"]
    DNS -->|"直接回傳全部 Pod IP<br/>(無虛擬 IP、不分流)"| P
    P --> P1["Pod web-0<br/>10.0.0.5"]
    P --> P2["Pod web-1<br/>10.0.0.6"]
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  clusterIP: None            # 關鍵:無頭
  selector:
    app: web
  ports:
    - port: 80

用途:當呼叫方需要「自己知道每個後端是誰」(例如資料庫叢集要直連特定節點),而不是被隨機分流。


4. CoreDNS:叢集內的電話簿

光有固定 IP 還不夠好用——我們希望用名字互相呼叫。叢集裡跑著 CoreDNS(在 kube-system 命名空間),它是叢集的 DNS 伺服器。每個 Service 一建立,CoreDNS 就為它登記一筆 DNS 紀錄。

4.1 DNS 命名規則

Service 的完整域名 (FQDN) 格式:

<service-name>.<namespace>.svc.cluster.local

例如 default 命名空間裡的 web 服務:web.default.svc.cluster.local(DNS for Services and Pods)。

簡寫規則(因為 Pod 的 /etc/resolv.conf 預設帶有 search <namespace>.svc.cluster.local svc.cluster.local cluster.local 這樣的 search domain):

  • 同命名空間內:直接用 web
  • 跨命名空間:用 web.其他namespace
  • 完整寫法:web.其他namespace.svc.cluster.local
# 在某個 Pod 裡測試 DNS 解析
kubectl run test --rm -it --image=busybox -- sh
# 然後在容器內:
nslookup web                              # 同命名空間
nslookup web.default.svc.cluster.local    # 完整域名
wget -qO- http://web                      # 直接用名字呼叫服務

4.2 解析流程

sequenceDiagram
    participant Pod as 呼叫方 Pod
    participant DNS as CoreDNS
    participant API as API Server
    Pod->>DNS: web.default.svc.cluster.local 是哪個 IP?
    Note over DNS,API: CoreDNS 監看 API Server,<br/>掌握所有 Service 的 ClusterIP
    DNS-->>Pod: 回傳 ClusterIP 10.96.0.10
    Pod->>Pod: 連到 10.96.0.10(由 kube-proxy 導向後端 Pod)

設計理念:DNS 讓服務之間「用名字耦合,不用 IP 耦合」。你的程式碼裡寫 http://web,不管 web 服務的 ClusterIP 是多少、後面 Pod 怎麼換,都不用改一行。這是微服務能在 K8s 上鬆耦合運作的基礎。


5. Ingress:在同一個入口做 L7 路由

問題:如果你有 10 個對外服務,難道要開 10 個 LoadBalancer(10 個外部 IP、10 筆雲端費用)?太貴。而且 Service 是 L4(只認 IP/埠),不會看 HTTP 路徑或網域。

Ingress 是一層 L7(HTTP/HTTPS)路由規則:用一個入口,依「網域 (host)」和「路徑 (path)」把請求分流到不同的後端 Service,還能統一處理 TLS。

flowchart LR
    U[外部使用者] -->|HTTPS| IC["Ingress Controller<br/>(實際的反向代理)"]
    IC -->|host: shop.example.com| S1[Service: shop]
    IC -->|path: /api| S2[Service: api]
    IC -->|path: /| S3[Service: web]

5.1 重要區分:Ingress 物件 vs Ingress Controller

  • Ingress 物件:你寫的 YAML,只是一份「路由規則的宣告」。
  • Ingress Controller:真正讀這份規則、執行反向代理的程式(例如 ingress-nginx、Traefik)。叢集預設沒有 Controller,你得自己裝。 官方文件明確指出:「只建立 Ingress 資源本身沒有任何效果」,必須搭配 Ingress Controller 才會生效(Ingress 官方文件)。
# minikube:啟用內建 ingress-nginx(僅供教學實驗,正式環境請見下方退役公告)
minikube addons enable ingress

# kind:手動安裝 ingress-nginx(僅供教學實驗)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

⚠️ 重要公告:Ingress NGINX 專案已於 2026 年 3 月退役。Kubernetes Steering 與 Security Response Committee 聯合聲明,ingress-nginx 因長期僅有 1–2 位志工維護、且既有設計難以安全地繼續維護,已停止發布任何新版本、修補與安全更新;官方估計約 50% 的雲原生環境曾使用它,退役後既有部署仍會繼續運作,但不會再有安全性修補(Kubernetes 官方聲明:Ingress NGINX Retirement)。因此上面的指令僅適合本機教學用途;正式環境請改用 Gateway API(見 5.3 節)或其他仍在維護的 Ingress Controller(如 Traefik)。若要檢查叢集是否還在用它:kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx

5.2 Ingress 範例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /   # Controller 專屬設定常透過 annotation
spec:
  ingressClassName: nginx        # 指定由哪個 Ingress Controller 處理
  tls:
    - hosts:
        - shop.example.com
      secretName: shop-tls       # TLS 憑證存在這個 Secret(第 4 章)
  rules:
    - host: shop.example.com      # 依網域分流
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api          # /api 開頭 → api 服務
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web          # 其餘 → web 服務
                port:
                  number: 80

Service 對外方式比較

方式 工作層級 能依網域/路徑分流 對外 IP 數量 適用
NodePort L4 用節點 IP 測試
LoadBalancer L4 每服務一個 單一服務對外、非 HTTP 流量
Ingress L7 一個共用入口 多個 HTTP 服務共用入口
Gateway API L4–L7 是(更強大) 一個共用入口 新叢集推薦,取代 Ingress

5.3 Gateway API:Ingress 的官方演進版

Gateway API 是 Kubernetes SIG Network 推出的新一代進出口流量 (ingress/egress) API。Gateway API v1.0 於 2023 年 10 月正式宣告 GA(核心資源晉升 v1 穩定版),是官方認可的 Ingress 演進路徑。

來源: - Kubernetes 官方文件:Gateway API - Gateway API 官方文件 - K8s Blog:Gateway API v1.0 GA 公告 - K8s Blog:Gateway API v1.1 GA 公告 - K8s Blog:Gateway API v1.5 公告 - Gateway API v1.6.0 Release Notes - 官方文件:TCPRoute 狀態 / UDPRoute 狀態

版本進度補充:API 持續演進中,v1.1(2024 年 5 月)把 GRPCRoute 晉升為 Standard Channel 穩定版;v1.5(實際發布於 2026 年 2 月 27 日,K8s 官方部落格公告則遲至同年 4 月才刊出)新增 ListenerSetTLSRoute、CORS filter、client cert 驗證等能力晉升為 Standard Channel,ReferenceGrant 也在此版由 v1beta1 升為 v1;v1.6.0(2026 年 6 月 30 日發布)讓 UDPRoute / TCPRoute 晉升為 GA(v1 API,取代舊版 v1alpha2);其後的 v1.6.1(2026 年 7 月,純測試/相容性修補,無新功能)是截至目前的最新 patch 版。本節示範的 GatewayClass / Gateway / HTTPRoute / GRPCRoute / ReferenceGrant 在 v1.6 下皆維持穩定、可直接使用。

為什麼 Ingress 不夠用?

Ingress 的痛點 說明
功能受限 標準只定義 host/path 路由;Header 路由、流量權重等功能靠各家自訂 annotation,不可移植
沒有角色分工 一個 Ingress 物件混合了「基礎設施設定」與「應用路由規則」,開發者和平台 Ops 改同一份 YAML
協定支援有限 只設計給 HTTP/HTTPS,TCP/UDP/gRPC 沒有標準路徑
跨命名空間受限 無法讓不同 namespace 的路由規則共用同一個 Gateway

核心設計:三層角色分工 (Role-Oriented)

Gateway API 最大的突破是把「誰管什麼」明確拆成三個角色與三種資源:

flowchart TB
    subgraph IP["① 基礎設施提供者 Infrastructure Provider"]
        GC["GatewayClass<br/>(定義閘道實作類型:<br/>nginx / cilium / envoy…)"]
    end
    subgraph CO["② 叢集維運者 Cluster Operator"]
        GW["Gateway<br/>(閘道實例:<br/>定義 Listener / 埠 / TLS)"]
    end
    subgraph AD["③ 應用開發者 Application Developer"]
        R1["HTTPRoute<br/>(HTTP 路由規則)"]
        R2["GRPCRoute<br/>(gRPC 路由規則)"]
    end
    GC -->|"gatewayClassName"| GW
    GW -->|"parentRefs"| R1
    GW -->|"parentRefs"| R2
    R1 --> SVC1["Service A"]
    R1 --> SVC2["Service B"]
    R2 --> SVC3["Service C"]

平台團隊控制 Gateway 層(流量入口的設定與安全);應用團隊控制 Route 層(路由規則)——各司其職,不需要互相等待。

穩定版核心資源 (Standard Channel)

資源 API 版本 穩定狀態 說明
GatewayClass v1 ✅ Stable (v1.0.0) 閘道實作類型,對應一個 controller
Gateway v1 ✅ Stable (v1.0.0) 閘道實例,定義 Listener(埠/協定/TLS)
HTTPRoute v1 ✅ Stable (v1.0.0) HTTP/HTTPS 路由規則
GRPCRoute v1 ✅ Stable (v1.1.0) gRPC 路由規則
ReferenceGrant v1(v1.5 起,前身 v1beta1) ✅ Stable (v1.5.0) 授權跨命名空間引用
TLSRoute v1 ✅ Stable (v1.5.0) TLS passthrough 路由規則(SNI 層)
ListenerSet v1 ✅ Stable (v1.5.0) 讓多個 Listener 掛載到同一 Gateway,支援多租戶
TCPRoute v1(取代 v1alpha2) ✅ Stable (v1.6.0) TCP 四層路由規則
UDPRoute v1(取代 v1alpha2) ✅ Stable (v1.6.0) UDP 四層路由規則

Gateway API 是獨立的 CRD,不隨 K8s 版本內建,需額外安裝。Standard Channel 只包含穩定版資源,若要用仍在實驗性 (Experimental) Channel 的新特性(例如較新的 GEP 提案),需另外安裝 Experimental Channel 的 CRD,詳見 Gateway API Releases

安裝 Gateway API CRD

# 安裝 Standard Channel(穩定版):GatewayClass / Gateway / HTTPRoute / GRPCRoute / ReferenceGrant / TLSRoute / ListenerSet(v1.5 起)/ TCPRoute / UDPRoute(v1.6 起)
# 版本請至 https://github.com/kubernetes-sigs/gateway-api/releases 確認最新版
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/latest/download/standard-install.yaml

# 確認 CRD 安裝成功
kubectl get crd | grep gateway.networking.k8s.io

完整 YAML 範例:三層分工實作路由

第一層:GatewayClass(基礎設施提供者建立,通常已預裝)

# GatewayClass:宣告「使用哪個 controller 實作閘道」
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName: gateway.nginx.org/nginx-gateway-fabric

第二層:Gateway(叢集 Ops 建立)

# Gateway:實際的閘道實例,定義 Listener(對外的埠/協定/TLS)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
  namespace: infra          # Gateway 通常放在基礎設施命名空間
spec:
  gatewayClassName: nginx   # 對應哪個 GatewayClass
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: All         # 允許所有命名空間的 Route 附掛
    - name: https
      port: 443
      protocol: HTTPS
      tls:
        certificateRefs:
          - name: shop-tls  # TLS 憑證 Secret(在 infra 命名空間)
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: "true"  # 只允許貼了此標籤的命名空間

第三層:HTTPRoute(應用開發者建立)

# HTTPRoute:HTTP 路由規則,可和 Gateway 在不同命名空間
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop-route
  namespace: shop-ns        # 應用自己的命名空間(與 Gateway 不同!)
spec:
  parentRefs:
    - name: prod-gateway
      namespace: infra      # 附掛到哪個 Gateway
      sectionName: https    # 附掛到哪個 Listener
  hostnames:
    - shop.example.com
  rules:
    # 規則一:依路徑路由
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: api-svc
          port: 80
    # 規則二:進階功能 — 依 Header 做金絲雀路由(Ingress 標準做不到!)
    - matches:
        - path:
            type: PathPrefix
            value: /
          headers:
            - name: X-Canary
              value: "true"
      backendRefs:
        - name: web-canary
          port: 80
    # 規則三:主路徑,帶流量權重(可做 A/B testing)
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: web-stable     # 90% 流量打到穩定版
          port: 80
          weight: 90
        - name: web-canary     # 10% 流量打到金絲雀版
          port: 80
          weight: 10

流量權重 (weight) 讓金絲雀發布 (Canary Deployment)藍綠部署 (Blue-Green) 變得原生可設定,不再需要靠複雜的 annotation 或 Service Mesh。

跨命名空間路由:ReferenceGrant

HTTPRoute 可以附掛到另一個命名空間的 Gateway,但需要 Gateway 所在命名空間的 ReferenceGrant 授權,以防止惡意 Route 跨 namespace 「劫持」流量:

# ReferenceGrant:允許 shop-ns 命名空間的 Route 引用 infra 命名空間的 Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
  name: allow-shop-ns
  namespace: infra          # 在「被引用」的命名空間(Gateway 所在)
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: shop-ns    # 允許 shop-ns 的 HTTPRoute 引用
  to:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: prod-gateway

Gateway API vs Ingress 完整對照

特性 Ingress Gateway API
穩定狀態 (GA) GA(K8s 1.19) GA(Gateway API v1.0,2023,獨立於 K8s 版本)
角色分工 無(全混在一個物件) 三層分工(GatewayClass/Gateway/Route)
Header 路由 不支援(靠 annotation) ✅ 原生支援
流量權重分流 不支援(靠 annotation) ✅ 原生支援(weight 欄位)
跨命名空間路由 不支援 ✅ 支援(透過 ReferenceGrant)
gRPC 不支援 ✅ GRPCRoute(v1.1 穩定)
TLS termination 支援 ✅ 支援(更細緻的設定)
可移植性 差(annotation 各家不同) 好(標準 API,實作可互換)
目前採用度 非常廣泛(成熟生態) 快速增長,各大實作已支援

主流實作 (Implementations)

實作 說明
Cilium 雲原生 CNI,同時支援 Gateway API(EKS/GKE 常用)
NGINX Gateway Fabric NGINX 官方 Gateway API 實作
Envoy Gateway CNCF 專案,以 Envoy 為底層
Contour VMware 維護,以 Envoy 為底層
Traefik 支援 Gateway API(v3+)
AWS Load Balancer Controller EKS 官方實作;AWS 官方公告(2026 年 3 月)宣布 GA 支援 Gateway API,以 CRD 設定(L7 → ALB、L4 → NLB),不再靠 annotation(公告本文未直接標註版本號,對應到 controller 專案的 v3.0.0 發行版)

實務建議:新叢集優先評估 Gateway API;現有叢集的 Ingress API 不需要立刻遷移(Ingress API 不會被棄用),但若你的 controller 是 ingress-nginx,因專案已退役仍需規劃遷移(見 5.1 節公告),且新功能只會出現在 Gateway API 上。

動手練習(Gateway API): 1. 安裝 Gateway API CRD 與一個實作(如 nginx-gateway-fabric)。 2. 依照三層角色建立 GatewayClass → Gateway → HTTPRoute,把兩個服務路由到同一個 Gateway 的不同路徑。 3. 用 HTTPRoute 的 weight 欄位做 9:1 流量分流,體驗金絲雀路由。 4. 嘗試建立跨命名空間的 HTTPRoute + ReferenceGrant,理解為什麼需要授權。


6. NetworkPolicy:Pod 之間的防火牆(進階)

預設情況下,叢集內任何 Pod 都能連任何 Pod(回想第 1 節的扁平網路)。這在正式環境是個安全隱患。NetworkPolicy 讓你像防火牆一樣限制「誰能連誰」。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-api-only
spec:
  podSelector:
    matchLabels:
      app: db                  # 這條規則套用在 db Pod 上
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api          # 只允許帶 app=api 的 Pod 連進來
      ports:
        - protocol: TCP
          port: 5432

注意:NetworkPolicy 需要 CNI 外掛支援(Calico、Cilium 支援;有些簡易 CNI 不支援)。寫了沒效果的話先確認你的 CNI。


7. 除錯網路問題的順序

# 1) Service 有沒有正確選到 Pod?Endpoints 是空的代表 selector 沒對上
kubectl get svc web
kubectl get endpointslices -l kubernetes.io/service-name=web
kubectl describe svc web                  # 看 Endpoints 欄位

# 2) DNS 通不通?
kubectl run test --rm -it --image=busybox -- nslookup web

# 3) 從 Pod 內實際連連看
kubectl run test --rm -it --image=busybox -- wget -qO- http://web

# 4) Ingress 有沒有被 Controller 接管?
kubectl get ingress
kubectl describe ingress app-ingress
kubectl get pods -n ingress-nginx          # Controller 在跑嗎

最常見的坑:Service 的 selector 跟 Pod 的 label 對不上,導致 Endpoints 空空如也,連線一直失敗卻沒報錯。永遠先檢查 Endpoints。


動手練習

  1. 部署一個 nginx Deployment(3 副本)加一個 ClusterIP Service,用 kubectl get endpointslices 確認三個 Pod IP 都在後端。
  2. 起一個臨時 busybox Pod,用 nslookupwget 透過 Service 名字連到 nginx,體會 DNS 的作用。
  3. 把 Service 改成 NodePort,從節點 IP + 埠存取;再試 minikube tunnel 或 LoadBalancer。
  4. 安裝 Ingress Controller,部署兩個服務(web 與 api),寫一個 Ingress 用路徑 //api 分流,用 curl 加 Host header 測試。
  5. 故意把 Service 的 selector 改錯一個字,觀察 Endpoints 變空、連線失敗,體會這個常見坑。
  6. (進階)寫一條 NetworkPolicy 只允許 api 連 db,從別的 Pod 測試是否被擋(需 Calico/Cilium)。

本章檢核點 (Checklist)

  • [ ] 能說明 K8s 扁平網路的三條規則,理解 Pod 之間預設可直連
  • [ ] 能解釋為什麼需要 Service(Pod IP 會變)以及 Service 提供的兩件事
  • [ ] 理解 Service 透過 selector + Endpoints/EndpointSlice 找到後端,且未就緒 Pod 不列入
  • [ ] 能說出 ClusterIP / NodePort / LoadBalancer / ExternalName 的差異與層層疊加關係
  • [ ] 知道 Headless Service(clusterIP: None)的用途與 StatefulSet 的關聯
  • [ ] 能寫出 Service 的完整 FQDN 並用簡寫做跨/同命名空間呼叫
  • [ ] 能解釋 CoreDNS 的角色,以及「用名字耦合不用 IP 耦合」的設計價值
  • [ ] 能區分 Ingress 物件與 Ingress Controller,知道沒裝 Controller 規則不生效
  • [ ] 能寫一個依 host/path 分流並含 TLS 的 Ingress
  • [ ] 理解 Gateway API 三層角色分工(GatewayClass / Gateway / HTTPRoute),能說明它解決了 Ingress 的哪些痛點
  • [ ] 能說出 Gateway API 相較 Ingress 的三個核心優勢:Header 路由、流量權重、跨命名空間路由
  • [ ] 知道 ReferenceGrant 的用途(跨命名空間路由的授權機制)
  • [ ] 會用「先查 Endpoints、再查 DNS、再從 Pod 內實連」的順序除錯網路

下一章:04-config-storage.md — 設定、密碼、資料怎麼跟容器解耦並持久化。