入口閘道
除了支援 Kubernetes Ingress 資源之外,Istio 也允許您使用 Istio Gateway 或 Kubernetes Gateway 資源設定入口流量。與 Ingress
相比,Gateway
提供了更廣泛的自訂和彈性,並允許將監控和路由規則等 Istio 功能應用於進入叢集的流量。
此任務說明如何設定 Istio 以使用 Gateway
將服務公開於服務網格之外。
開始之前
依照安裝指南中的說明設定 Istio。
啟動 httpbin 範例,它將作為入口流量的目標服務。
$ kubectl apply -f @samples/httpbin/httpbin.yaml@
請注意,為了本文檔的目的,它展示如何使用網關來控制進入您的「Kubernetes 叢集」的入口流量,您可以啟動啟用或未啟用 Sidecar 注入的
httpbin
服務(即,目標服務可以在 Istio 網格內部或外部)。
使用閘道設定入口
一個入口 Gateway
描述了一個在網格邊緣運作的負載平衡器,它接收傳入的 HTTP/TCP 連線。它配置公開的埠、協定等,但與 Kubernetes Ingress 資源不同,它不包含任何流量路由配置。入口流量的流量路由改為使用路由規則配置,與內部服務請求的方式完全相同。
讓我們看看如何為 HTTP 流量在埠 80 上配置 Gateway
。
建立一個 Istio Gateway
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
配置通過 Gateway
進入的流量路由
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
您現在已為 httpbin
服務建立了一個 虛擬服務 配置,其中包含兩個允許路徑 /status
和 /delay
流量的路由規則。
gateways 列表指定僅允許通過您的 httpbin-gateway
的請求。所有其他外部請求將被拒絕並返回 404 回應。
建立一個 Kubernetes Gateway
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
hostname: "httpbin.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
EOF
由於建立 Kubernetes Gateway
資源也會部署相關的代理服務,請執行以下命令以等待網關準備就緒。
$ kubectl wait --for=condition=programmed gtw httpbin-gateway
配置通過 Gateway
進入的流量路由
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: httpbin-gateway
hostnames: ["httpbin.example.com"]
rules:
- matches:
- path:
type: PathPrefix
value: /status
- path:
type: PathPrefix
value: /delay
backendRefs:
- name: httpbin
port: 8000
EOF
您現在已為 httpbin
服務建立了一個 HTTP 路由配置,其中包含兩個允許路徑 /status
和 /delay
流量的路由規則。
判斷入口 IP 和連接埠
每個 Gateway
都由一個 LoadBalancer 類型的服務支援。此服務的外部負載平衡器 IP 和埠用於存取網關。在大多數雲端平台上執行的叢集中,預設支援 LoadBalancer
類型的 Kubernetes 服務,但在某些環境(例如,測試)中,您可能需要執行以下操作
minikube
- 在不同的終端中執行以下命令來啟動外部負載平衡器。$ minikube tunnel
kind
- 依照設定 MetalLB 的指南使LoadBalancer
類型的服務正常運作。其他平台 - 您可以使用 MetalLB 為
LoadBalancer
服務取得EXTERNAL-IP
。
為了方便起見,我們將入口 IP 和埠儲存在稍後指令中將使用的環境變數中。根據以下指示設定 INGRESS_HOST
和 INGRESS_PORT
環境變數。
將以下環境變數設定為 Istio 入口網關在您的叢集中所在的位置的名稱和命名空間。
$ export INGRESS_NAME=istio-ingressgateway
$ export INGRESS_NS=istio-system
執行以下命令以確定您的 Kubernetes 叢集是否處於支援外部負載平衡器的環境中。
$ kubectl get svc "$INGRESS_NAME" -n "$INGRESS_NS"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 172.21.109.129 130.211.10.121 ... 17h
如果設定了 EXTERNAL-IP
值,則您的環境具有可供入口網關使用的外部負載平衡器。如果 EXTERNAL-IP
值為 <none>
(或永久處於 <pending>
),則您的環境不會為入口網關提供外部負載平衡器。
如果您的環境不支援外部負載平衡器,您可以嘗試使用節點埠存取入口網關。否則,請使用以下命令設定入口 IP 和埠。
$ export INGRESS_HOST=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
$ export TCP_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')
從 httpbin 網關資源取得網關位址和埠。
$ export INGRESS_HOST=$(kubectl get gtw httpbin-gateway -o jsonpath='{.status.addresses[0].value}')
$ export INGRESS_PORT=$(kubectl get gtw httpbin-gateway -o jsonpath='{.spec.listeners[?(@.name=="http")].port}')
存取入口服務
使用 curl 存取 httpbin 服務
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/status/200" ... HTTP/1.1 200 OK ... server: istio-envoy ...
請注意,您使用
-H
標誌將 Host HTTP 標頭設定為 "httpbin.example.com"。這是必需的,因為您的入口Gateway
被配置為處理 "httpbin.example.com",但在您的測試環境中,您沒有該主機的 DNS 繫結,而只是將請求傳送到入口 IP。存取任何其他尚未明確公開的 URL。您應該會看到 HTTP 404 錯誤。
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/headers" HTTP/1.1 404 Not Found ...
使用瀏覽器存取入口服務
在瀏覽器中輸入 httpbin
服務 URL 將無法運作,因為您無法像使用 curl
一樣將 Host 標頭傳遞給瀏覽器。在真實情況下,這不是問題,因為您可以正確配置請求的主機並使 DNS 可解析。因此,您在 URL 中使用主機的網域名稱,例如 https://httpbin.example.com/status/200
。
您可以按照以下方式解決簡單測試和演示的此問題。
在 Gateway
和 VirtualService
配置中使用萬用字元 *
作為主機的值。例如,將您的入口配置變更為以下內容
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /headers
route:
- destination:
port:
number: 8000
host: httpbin
EOF
如果您從 Gateway
和 HTTPRoute
配置中刪除主機名稱,則它們將應用於任何請求。例如,將您的入口配置變更為以下內容。
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: httpbin-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /headers
backendRefs:
- name: httpbin
port: 8000
EOF
然後,您可以在瀏覽器 URL 中使用 $INGRESS_HOST:$INGRESS_PORT
。例如,http://$INGRESS_HOST:$INGRESS_PORT/headers
將顯示您的瀏覽器傳送的所有標頭。
了解發生了什麼事
Gateway
配置資源允許外部流量進入 Istio 服務網格,並使 Istio 的流量管理和策略功能可用於邊緣服務。
在前面的步驟中,您在服務網格內建立了一個服務,並將該服務的 HTTP 端點公開給外部流量。
使用入口閘道服務的節點連接埠
如果您的環境不支援外部負載平衡器,您仍然可以使用 istio-ingressgateway
服務的 節點埠來試用某些 Istio 功能。
設定入口埠。
$ export INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
$ export TCP_INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="tcp")].nodePort}')
設定入口 IP 取決於叢集提供者
GKE
$ export INGRESS_HOST=worker-node-address
您需要建立防火牆規則以允許 TCP 流量進入 ingressgateway 服務的埠。執行以下命令以允許 HTTP 埠、安全埠 (HTTPS) 或兩者的流量。
$ gcloud compute firewall-rules create allow-gateway-http --allow "tcp:$INGRESS_PORT" $ gcloud compute firewall-rules create allow-gateway-https --allow "tcp:$SECURE_INGRESS_PORT"
IBM Cloud Kubernetes Service
$ ibmcloud ks workers --cluster cluster-name-or-id $ export INGRESS_HOST=public-IP-of-one-of-the-worker-nodes
Docker For Desktop
$ export INGRESS_HOST=127.0.0.1
其他環境
$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n "${INGRESS_NS}" -o jsonpath='{.items[0].status.hostIP}')
疑難排解
檢查
INGRESS_HOST
和INGRESS_PORT
環境變數的值。根據以下命令的輸出,確保它們具有有效的值。$ kubectl get svc -n istio-system $ echo "INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT"
檢查您是否在同一個埠上沒有定義其他 Istio 入口網關。
$ kubectl get gateway --all-namespaces
檢查您是否在同一個 IP 和埠上沒有定義 Kubernetes Ingress 資源。
$ kubectl get ingress --all-namespaces
如果您有外部負載平衡器但無法運作,請嘗試使用其節點埠存取網關。
清理
刪除 Gateway
和 VirtualService
配置,並關閉 httpbin 服務。
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@
刪除 Gateway
和 HTTPRoute
配置,並關閉 httpbin 服務。
$ kubectl delete httproute httpbin
$ kubectl delete gtw httpbin-gateway
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@