istio使用ingress gateway通过header实现对不同服务的路由
要在 Istio 中使用 Ingress Gateway 实现基于 HTTP 头的服务路由,并对请求路径进行前缀去除(例如将 /api/details/xx
重写为 /xx
),可以利用 Istio 的 Gateway 和 VirtualService 资源,通过配置路由规则和路径重写来实现。以下是详细的实现步骤和配置说明,以满足你的需求:将 /api/details/xx
路由到 demo-bookinfo
命名空间下的 details
服务,/api/ratings/xx
路由到 ratings
服务,并在路由后去除 /api/details
或 /api/ratings
前缀。
1. 需求分析
- 目标:
- 通过 Istio Ingress Gateway 接收外部 HTTP 请求。
- 根据请求路径(如
/api/details/xx
、/api/ratings/xx
)路由到demo-bookinfo
命名空间下的对应服务(details
或ratings
)。 - 在路由到目标服务之前,去除路径中的服务前缀(例如
/api/details/xx
重写为/xx
)。
- 关键点:
- 使用 Istio 的 Gateway 定义外部流量入口。
- 使用 VirtualService 配置路径匹配、路由目标和路径重写规则。
- 确保路由规则基于路径前缀,并正确处理路径重写。
2. 前提条件
- Istio 已安装:确保 Istio 已部署在 Kubernetes 集群中,且
istio-ingressgateway
服务正常运行。 - 命名空间和目标服务:
demo-bookinfo
命名空间已创建,且details
和ratings
服务已部署,监听端口为 9080(Bookinfo 示例的默认端口)。 - 服务访问:确认
details
和ratings
服务可以通过 Kubernetes Service 访问,例如details.demo-bookinfo.svc.cluster.local:9080
和ratings.demo-bookinfo.svc.cluster.local:9080
。 - Istio Sidecar 注入:
demo-bookinfo
命名空间中的服务已启用 Istio Sidecar 注入(通过kubectl label namespace demo-bookinfo istio-injection=enabled
)。
3. 配置 Istio Gateway 和 VirtualService
以下是实现需求的完整配置,分为 Gateway 和 VirtualService 两部分。
3.0 同时配置
---
# Gateway 配置
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: internal-gatewaynamespace: istio-system
spec:selector:app: istio-ingressgatewayservers:- port:number: 80name: httpprotocol: HTTPhosts:- "*" # 接受所有主机,或使用 "*.demo-bookinfo.svc.cluster.local"
---
# VirtualService 配置
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: internal-routingnamespace: demo-bookinfo
spec:hosts:- "*" # 匹配所有主机,或指定内部域名gateways:- istio-system/internal-gatewayhttp:- match:- headers:service:exact: ratingsroute:- destination:host: ratings.demo-bookinfo.svc.cluster.localport:number: 9080- match:- headers:service:exact: detailsroute:- destination:host: details.demo-bookinfo.svc.cluster.localport:number: 9080- route: # 默认路由(可选)- destination:host: productpage.demo-bookinfo.svc.cluster.localport:number: 9080```### 3.1 配置 GatewayGateway 定义了 Ingress Gateway 监听的端口和协议,用于接收外部流量。我们配置一个 HTTP 端口(80),并允许所有主机(`*`)的请求。```yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: bookinfo-gatewaynamespace: istio-system # 通常与 istio-ingressgateway 所在命名空间一致
spec:selector:istio: ingressgateway # 选择默认的 Istio Ingress Gatewayservers:- port:number: 80name: httpprotocol: HTTPhosts:- "*" # 允许所有主机,生产环境中可指定具体域名
说明:
selector: istio: ingressgateway
:绑定到 Istio 默认的 Ingress Gateway。hosts: ["*"]
:允许任意主机名,简化测试。生产环境中应指定具体域名(如bookinfo.example.com
)。- 部署此配置:
kubectl apply -f bookinfo-gateway.yaml
3.2 配置 VirtualService
VirtualService 定义了具体的路由规则,包括路径匹配、目标服务路由和路径重写。我们为 /api/details
和 /api/ratings
配置路由规则,并使用 rewrite
去除前缀。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: bookinfo-routingnamespace: demo-bookinfo # 与目标服务所在命名空间一致
spec:hosts:- "*" # 匹配所有主机,生产环境中可指定具体域名gateways:- istio-system/bookinfo-gateway # 引用 Gateway,格式为 <namespace>/<gateway-name>http:- match:- uri:prefix: /api/details # 匹配 /api/details 开头的路径rewrite:uri: / # 将 /api/details/xx 重写为 /xxroute:- destination:host: details.demo-bookinfo.svc.cluster.local # 目标服务port:number: 9080- match:- uri:prefix: /api/ratings # 匹配 /api/ratings 开头的路径rewrite:uri: / # 将 /api/ratings/xx 重写为 /xxroute:- destination:host: ratings.demo-bookinfo.svc.cluster.local # 目标服务port:number: 9080
说明:
hosts: ["*"]
:匹配所有主机,与 Gateway 保持一致。gateways
:引用istio-system
命名空间中的bookinfo-gateway
。http
部分:match: uri: prefix
:匹配以/api/details
或/api/ratings
开头的请求。rewrite: uri: /
:将匹配的前缀(如/api/details
或/api/ratings
)替换为/
,例如/api/details/xx
重写为/xx
。route: destination
:指定目标服务的完整域名(<service-name>.<namespace>.svc.cluster.local
)和端口。
- 部署此配置:
kubectl apply -f bookinfo-virtualservice.yaml
4. 工作原理
-
外部请求进入:
- 客户端发送请求到 Ingress Gateway 的外部 IP(例如
http://<INGRESS_HOST>/api/details/xx
)。 - Gateway 监听 80 端口,接收 HTTP 请求。
- 客户端发送请求到 Ingress Gateway 的外部 IP(例如
-
VirtualService 匹配和处理:
- VirtualService 根据
uri: prefix
规则匹配请求路径。 - 如果路径以
/api/details
开头:rewrite: uri: /
将路径重写为/xx
(去除/api/details
)。- 请求路由到
details.demo-bookinfo.svc.cluster.local:9080
。
- 如果路径以
/api/ratings
开头:- 同样重写路径为
/xx
(去除/api/ratings
)。 - 请求路由到
ratings.demo-bookinfo.svc.cluster.local:9080
。
- 同样重写路径为
- VirtualService 根据
-
服务接收请求:
details
或ratings
服务接收到的请求路径为/xx
,符合你的需求。
5. 测试配置
5.1 获取 Ingress Gateway 地址
获取 Istio Ingress Gateway 的外部 IP 和端口:
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
echo "Ingress URL: http://$INGRESS_HOST:$INGRESS_PORT"
如果运行在本地(如 Minikube),可能需要使用 NodePort 或其他方式获取地址。
5.2 测试路由和路径重写
- 测试
details
服务:
curl -v http://$INGRESS_HOST:$INGRESS_PORT/api/details/123
- 预期结果:请求被路由到
details
服务,服务接收到的路径为/123
。 - 检查
details
服务的日志(假设服务支持日志输出):
kubectl -n demo-bookinfo logs <details-pod-name>
确认日志中显示的请求路径为 /123
,而不是 /api/details/123
。
- 测试
ratings
服务:
curl -v http://$INGRESS_HOST:$INGRESS_PORT/api/ratings/456
- 预期结果:请求被路由到
ratings
服务,服务接收到的路径为/456
。 - 同样检查
ratings
服务的日志,确认路径为/456
。
5.3 验证路径重写
如果 details
或 ratings
服务有特定的响应(例如返回请求的路径),可以检查响应内容或日志,确保路径已被正确重写。如果服务不支持日志,可以在服务中临时添加调试端点,或使用 Istio 的请求追踪工具(如 Kiali 或 Jaeger)验证请求路径。
6. 基于 Header 的路由(可选增强)
你的需求中提到“通过 header 路由到对应的服务”,当前配置是基于路径前缀的。如果需要基于 HTTP 头进行路由(例如根据 X-Version: v1
路由到特定版本的 details
服务),可以在 VirtualService
中添加 headers
匹配条件。以下是一个示例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: bookinfo-routingnamespace: demo-bookinfo
spec:hosts:- "*"gateways:- istio-system/bookinfo-gatewayhttp:- match:- uri:prefix: /api/detailsheaders:x-version:exact: v1 # 匹配 X-Version: v1 的请求rewrite:uri: /route:- destination:host: details.demo-bookinfo.svc.cluster.localsubset: v1 # 假设 details 服务有 v1 子集port:number: 9080- match:- uri:prefix: /api/detailsheaders:x-version:exact: v2 # 匹配 X-Version: v2 的请求rewrite:uri: /route:- destination:host: details.demo-bookinfo.svc.cluster.localsubset: v2 # 假设 details 服务有 v2 子集port:number: 9080- match:- uri:prefix: /api/ratingsrewrite:uri: /route:- destination:host: ratings.demo-bookinfo.svc.cluster.localport:number: 9080
6.1 定义 DestinationRule(支持子集)
如果使用基于头的路由到服务子集(如 v1
、v2
),需要定义 DestinationRule 来指定子集:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:name: details-destinationnamespace: demo-bookinfo
spec:host: details.demo-bookinfo.svc.cluster.localsubsets:- name: v1labels:version: v1 # 匹配 Pod 的 version: v1 标签- name: v2labels:version: v2 # 匹配 Pod 的 version: v2 标签
6.2 测试基于 Header 的路由
curl -H "X-Version: v1" http://$INGRESS_HOST:$INGRESS_PORT/api/details/123
curl -H "X-Version: v2" http://$INGRESS_HOST:$INGRESS_PORT/api/details/123
- 确认请求分别路由到
details
服务的v1
和v2
子集,且路径被重写为/123
。
7. 故障排查
如果路由或路径重写不生效,可以按照以下步骤排查:
-
检查 Gateway 和 VirtualService 配置:
- 确保
kubectl get gateway -n istio-system
和kubectl get virtualservice -n demo-bookinfo
显示资源已创建。 - 检查
VirtualService
的gateways
字段是否正确引用 Gateway。
- 确保
-
验证 Ingress Gateway 地址:
- 确保
INGRESS_HOST
和INGRESS_PORT
正确,且可以通过curl
访问。
- 确保
-
检查服务日志:
- 查看
details
和ratings
服务的日志,确认接收到的请求路径是否正确。
- 查看
-
使用 Istio 调试工具:
- 使用
istioctl analyze
检查配置是否有错误:istioctl analyze -n demo-bookinfo
- 使用 Kiali 或 Jaeger 跟踪请求,验证路由和路径重写。
- 使用
-
确认服务端口:
- 确保
details
和ratings
服务的 Kubernetes Service 端口为 9080,且 Pod 监听正确端口。
- 确保
-
检查 Envoy 配置:
- 查看 Ingress Gateway 的 Envoy 配置:
istioctl proxy-config routes -n istio-system <ingress-gateway-pod-name>
- 确认路由规则和路径重写是否正确应用。
- 查看 Ingress Gateway 的 Envoy 配置:
8. 参考资料
- Istio 官方文档:Ingress Gateways
- Istio 官方文档:Virtual Service
- Istio Bookinfo 示例:Request Routing
- Istio 路径重写示例:Path-Based Routing
9. 总结
通过以上配置,Istio Ingress Gateway 可以实现:
- 基于路径前缀(如
/api/details
、/api/ratings
)将请求路由到demo-bookinfo
命名空间的details
和ratings
服务。 - 使用
rewrite: uri: /
去除路径前缀,确保服务接收到的请求路径为/xx
。 - 可选地,通过
headers
匹配实现基于 HTTP 头的路由(例如X-Version
)。