迁移Kubernetes服务时,使用Istio ServiceEntry实现跨GKE集群访问内部Kubernetes FQDN的故障排查求助
你的核心困扰在于Istio对Kubernetes集群原生域名(.svc.cluster.local后缀)的默认处理逻辑——Istio会优先把这类域名的解析请求交给集群DNS,而不是通过你配置的ServiceEntry来路由。哪怕你手动把ServiceEntry的location设为MESH_EXTERNAL,Istio的内置规则还是会优先走K8s DNS,导致你的配置没起作用。另外,你的Pod里用的是短名serviceA,如果不做额外配置,这个短名的请求可能也没被Istio正确拦截。
这里有几个逐步推进的方案,优先推荐第一个,因为它更灵活且不影响全局配置:
方案1:用自定义虚拟域名实现路由
这个思路是绕开集群原生域名,用一个自定义域名来映射旧集群的ILB,再通过VirtualService把短名serviceA的请求转发过去。
第一步:创建指向旧集群ILB的ServiceEntry
用一个非.svc.cluster.local的域名,比如serviceA.remote,来定义外部服务:
apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: serviceA-remote namespace: default spec: hosts: - serviceA.remote location: MESH_EXTERNAL ports: - number: 50051 name: grpc protocol: GRPC resolution: STATIC endpoints: - address: 'XX.XX.XX.XX' # 替换成旧集群内部负载均衡器的IP
第二步:配置VirtualService映射短名到虚拟域名
让Istio拦截serviceA和serviceA.default.svc.cluster.local这两个主机名的请求,转发到上面定义的serviceA.remote:
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: serviceA-route namespace: default spec: hosts: - serviceA - serviceA.default.svc.cluster.local gateways: - mesh http: - timeout: 5s route: - destination: host: serviceA.remote
第三步:验证配置
应用完配置后,在新集群的Pod里测试一下:
# 用Istio兼容的curl镜像测试GRPC连接 kubectl run -it --rm --image=curlimages/curl curl-test -- sh curl -v --http2-prior-knowledge http://serviceA:50051/your/grpc/method
如果有grpcurl工具,也可以直接用它来验证GRPC服务的可用性。
方案2:调整Sidecar配置(可选)
如果你的Sidecar设置了严格的出站规则,可能需要允许访问serviceA.remote,或者放开默认出站流量:
apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default-sidecar namespace: default spec: egress: - hosts: - "*/*" # 允许所有出站流量,也可以精确指定"default/serviceA.remote"
方案3:修改Istio全局配置(不推荐)
如果你一定要用.svc.cluster.local后缀,可以修改Istio的MeshConfig,让它忽略特定集群域名的默认DNS解析:
apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: meshConfig: serviceDiscovery: ignoreHosts: - serviceA.default.svc.cluster.local
然后重新部署Istio控制平面。不过这个方案会影响全局配置,风险较高,只作为备选。
- Istio的域名优先级规则:
.svc.cluster.local是Kubernetes集群的原生服务域名,Istio默认会把这类请求交给集群DNS处理,跳过ServiceEntry的路由逻辑。新集群里没有serviceA服务,DNS解析失败或超时,就会出现你看到的upstream request timeout错误。 - VirtualService的主机名覆盖不全:你的VirtualService只匹配了
serviceA.default.svc.cluster.local,但Pod里用的是短名serviceA,如果K8s DNS无法解析这个短名,请求可能根本没进入Istio的路由流程。
内容的提问来源于stack exchange,提问作者sc-leeds

