Istio 出站流量管理,化解爬虫被 502 的小尴尬
2023-12-06 02:53:40
Istio 作为一种服务网格,在解决微服务架构中各种复杂问题上大显神通,出站流量管理正是它众多强项之一。前不久,笔者在将一个基于 Puppeteer 的小型数据爬虫迁移到自建的微服务架构时,就遇到了 Istio 出站流量管理的难题。
初遇 502
在将爬虫迁移到 Kubernetes 集群后,一切看起来都很顺利。Ingress 配置的 API 接口可以正常调用,但数据爬取却总是以 502 状态码失败。困惑中,我排查了爬虫代码和 Kubernetes 日志,却始终找不到原因。
Istio 疑云
直到我注意到 Kubernetes 中部署了 Istio 服务网格,才恍然大悟:可能是 Istio 在作怪。果然,当我禁用 Istio 注入时,爬虫可以正常工作了。这让我不禁好奇,Istio 到底做了什么,导致了 502 错误?
出站流量管理
经过一番探索,我发现 Istio 出站流量管理是罪魁祸首。Istio 默认对所有出站流量进行拦截,并将其重定向到一个称为 Sidecar 的代理容器中。Sidecar 负责流量的路由、安全性和可观测性。
问题根源
在我们的案例中,Istio Sidecar 拦截了爬虫发往目标网站的 HTTP 请求,并将其重定向到 Kubernetes 集群的内部 DNS 名称。然而,目标网站并不知道这个内部 DNS 名称,因此返回了 502 错误。
解决之道
要解决这个问题,需要配置 Istio,使其绕过对特定流量的拦截。可以使用 VirtualService
资源来实现这一点。我创建了一个 VirtualService
,将爬虫的出站流量排除在 Istio 的管理之外,如下所示:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: puppeteer-bypass
spec:
hosts:
- "*"
gateways:
- istio-gateway
http:
- route:
- destination:
host: puppeteer-service
port:
number: 8080
exclude:
- destination:
host: kubernetes.default.svc
port:
number: 443
在这个配置中,hosts
字段表示该 VirtualService
适用于所有主机。gateways
字段指定了流量将通过哪个网关,这里使用的是默认的 istio-gateway
。http
字段定义了如何处理 HTTP 流量。
route
部分指定了将流量路由到名为 puppeteer-service
的服务。exclude
部分指定了要排除在路由之外的流量,这里是 Kubernetes 集群的内部 DNS 名称 kubernetes.default.svc
。
重获新生
应用这个 VirtualService
配置后,爬虫终于可以正常工作了。Istio 不再拦截发往目标网站的 HTTP 请求,502 错误也随之消失。
附:技术指南
步骤 1:创建 VirtualService 资源
kubectl apply -f puppeteer-bypass.yaml
步骤 2:验证配置
kubectl get virtualservice puppeteer-bypass -o yaml
步骤 3:重新启动爬虫
步骤 4:验证爬虫是否正常工作