入口网关
除了支持 Kubernetes Ingress 资源之外,Istio 还允许您使用 Istio 网关 或 Kubernetes 网关 资源来配置 Ingress 流量。Gateway
比 Ingress
提供更广泛的自定义和灵活性,并允许将 Istio 功能(例如监控和路由规则)应用于进入集群的流量。
本任务介绍如何配置 Istio 以使用 Gateway
将服务暴露在服务网格之外。
开始之前
按照 安装指南 中的说明设置 Istio。
启动 httpbin 示例,它将用作 Ingress 流量的目标服务。
$ kubectl apply -f @samples/httpbin/httpbin.yaml@
请注意,出于本文档的目的,本文档展示了如何使用网关来控制进入“Kubernetes 集群”的 Ingress 流量,您可以启用或禁用 Sidecar 注入来启动
httpbin
服务(即,目标服务可以位于 Istio 网格内或网格外)。
使用网关配置入口
Ingress Gateway
描述了在网格边缘运行的负载均衡器,该负载均衡器接收传入的 HTTP/TCP 连接。它配置了暴露的端口、协议等,但与 Kubernetes Ingress 资源 不同,它不包含任何流量路由配置。Ingress 流量的流量路由是使用路由规则配置的,与内部服务请求的路由规则完全相同。
让我们看看您如何为 HTTP 流量在端口 80 上配置 Gateway
。
创建一个 Istio 网关
$ 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 网关
$ 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
。
为了方便起见,我们将 Ingress IP 和端口存储在环境变量中,这些环境变量将在后面的说明中使用。根据以下说明设置 INGRESS_HOST
和 INGRESS_PORT
环境变量。
将以下环境变量设置为 Istio Ingress 网关在集群中所在的名称和命名空间。
$ 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
值,则您的环境具有外部负载均衡器,您可以将其用于 Ingress 网关。如果 EXTERNAL-IP
值为 <none>
(或永久为 <pending>
),则您的环境不会为 Ingress 网关提供外部负载均衡器。
如果您的环境不支持外部负载均衡器,您可以尝试 使用 Ingress 网关的节点端口访问它。否则,使用以下命令设置 Ingress 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”。这是必需的,因为您的 IngressGateway
配置为处理“httpbin.example.com”,但在您的测试环境中,您没有为该主机进行 DNS 绑定,并且只是将您的请求发送到 Ingress IP。访问任何尚未明确暴露的 URL。您应该会看到 HTTP 404 错误。
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/headers" HTTP/1.1 404 Not Found ...
使用浏览器访问 Ingress 服务
在浏览器中输入 httpbin
服务 URL 不会起作用,因为您无法像使用 curl
一样将 Host 标头传递到浏览器。在现实世界中,这不是问题,因为您正确配置了请求的主机并可以进行 DNS 解析。因此,您在 URL 中使用主机的域名,例如,https://httpbin.example.com/status/200
。
您可以通过以下方式解决此问题,以进行简单的测试和演示。
在 Gateway
和 VirtualService
配置中,对主机使用通配符 *
值。例如,将您的 Ingress 配置更改为以下内容。
$ 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
配置中删除主机名,它们将应用于任何请求。例如,将您的 Ingress 配置更改为以下内容。
$ 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 端点暴露给外部流量。
使用 Ingress 网关服务的节点端口
如果您的环境不支持外部负载均衡器,您仍然可以使用 istio-ingressgateway
服务的 节点端口 来试验一些 Istio 功能。
设置 Ingress 端口。
$ 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}')
设置 Ingress 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 Ingress 网关。
$ 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@