我用 Istio Gateway API 將公開 hostname 導向 Kubernetes Services。叢集外的 reverse proxy 終結 HTTPS,再將 HTTP 送到共用的 Gateway:
external TLS reverse proxy → Istio Gateway Service → HTTPRoute → Kubernetes Service → Pod
範例中的 example-api 對應 api.example.com,example-worker 對應 worker.example.com;example-admin 維持內部使用,不建立公開路由。
分開管理 Gateway 與 route
Gateway API 將入口設定拆成四種資源:Istio 提供的 GatewayClass、共用入口 Gateway、比對 hostname 與 path 的 HTTPRoute,以及授權跨 namespace backend 引用的 ReferenceGrant。共用基礎設施可以管理 Gateway,應用程式則管理或取得自己的 routes。
固定 Gateway Service 的 NodePort
外部 reverse proxy 需要固定的轉送位置。我用 ConfigMap 指定 Gateway Service 的 NodePort:
apiVersion: v1
kind: ConfigMap
metadata:
name: example-istio-gateway-options
namespace: istio-ingress
data:
service: |
spec:
type: NodePort
ports:
- name: status-port
port: 15021
protocol: TCP
targetPort: 15021
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 32080
Gateway 透過 infrastructure.parametersRef 引用這份設定:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example-istio-gateway
namespace: istio-ingress
annotations:
networking.istio.io/service-type: NodePort
spec:
gatewayClassName: istio
infrastructure:
parametersRef:
group: ""
kind: ConfigMap
name: example-istio-gateway-options
listeners:
- name: http
hostname: "*.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
外部 reverse proxy 終結 TLS,再將 HTTP 轉送至 NodePort 32080。Listener 的 allowedRoutes 決定哪些 namespace 的 routes 可以附掛;此例使用 All。
用 HTTPRoute 指向 backend Service
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-api
namespace: istio-ingress
spec:
parentRefs:
- name: example-istio-gateway
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: example-api
namespace: example-api
port: 3000
HTTPRoute 位於 istio-ingress,backend Service 位於 example-api,因此還需要在 backend namespace 建立 ReferenceGrant:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-istio-ingress-to-example-api
namespace: example-api
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: istio-ingress
to:
- group: ""
kind: Service
name: example-api
這份 grant 允許指定 route namespace 引用名為 example-api 的 Service。它和 listener 的 allowedRoutes 管理不同關係:前者處理 backend 引用,後者處理 route 附掛。完整說明見 Gateway API security model。
加入另一個 hostname
Worker UI 使用相同 Gateway,新增自己的 HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-worker
namespace: istio-ingress
spec:
parentRefs:
- name: example-istio-gateway
hostnames:
- worker.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: example-worker
namespace: example-worker
port: 8000
Worker namespace 也要授權這條 backend 引用:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-istio-ingress-to-example-worker
namespace: example-worker
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: istio-ingress
to:
- group: ""
kind: Service
name: example-worker
新增服務時不用另外建立 Gateway。example-admin 雖然也在叢集內、使用 Vault/External Secrets,這裡仍不為它加入公開路由。
與 ambient waypoint 的分工
需要 ambient mesh 的 namespace 使用以下 label:
istio.io/dataplane-mode: ambient
需要 service-scoped L7 處理時,再建立 waypoint:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example-api-waypoint
namespace: example-api
labels:
istio.io/waypoint-for: service
spec:
gatewayClassName: istio-waypoint
listeners:
- name: mesh
port: 15008
protocol: HBONE
建立 waypoint 後,還要在目標 Service 加上 istio.io/use-waypoint: example-api-waypoint;完整 Service 範例見 ambient waypoint 文章。
Ingress Gateway 處理進入叢集的流量。istio.io/use-waypoint 選用的是 mesh 流量的 waypoint,ingress 流量預設會略過它。若公開請求也需要經過 waypoint,Istio 1.25 起支援在目的 Service 或 Namespace 加上 istio.io/ingress-use-waypoint: "true",並在 istiod 啟用 ENABLE_INGRESS_WAYPOINT_ROUTING=true。依賴 waypoint policy 或 telemetry 前,應確認這兩項設定;參考 ingress gateways and waypoints。
辨認外部 HTTPS 目的地
對 Pods 呼叫的外部 API 加入 ServiceEntry,讓 Istio 與 Kiali 能辨認目的地:
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: example-external-api
namespace: example-api
spec:
hosts:
- api.vendor.example
location: MESH_EXTERNAL
ports:
- number: 443
name: tls
protocol: TLS
resolution: DNS
我使用明確的 FQDN,方便審查與對照流量,避免用 wildcard 掩蓋實際存取哪些 hosts。
逐層驗證
先查 Gateway 與產生的 Service,再查 routes 和 grants:
kubectl -n istio-ingress get gateway,svc,deploy
kubectl -n istio-ingress get httproute
kubectl -n example-api get referencegrant
kubectl -n example-worker get referencegrant
從叢集外測試公開入口:
curl https://api.example.com/health
curl https://worker.example.com/
失敗時依序檢查 DNS、reverse proxy 到 NodePort 的連線、listener hostname、HTTPRoute 的 Accepted 狀態、ReferenceGrant,以及 backend Service 的 ready endpoints。