Istio环境下带Sidecar服务调用无Sidecar HTTPS服务异常排查
这个问题我之前帮团队排查过好多次,踩过不少坑,本质是Istio Sidecar的流量拦截逻辑搞的鬼,下面给你拆解原因和对应的解决办法:
你遇到的Unrecognized SSL message, plaintext connection?错误,核心原因是带Sidecar的服务发起HTTPS请求时,被Sidecar拦截后以明文HTTP的方式转发给了目标HTTPS服务。目标服务收到明文请求后,以为是无效的SSL消息,所以抛出了这个错误。
因为Istio默认会拦截Pod的所有出站流量,当你的服务发起HTTPS请求时,如果没有给Sidecar正确的配置指令,它会默认把请求当成普通HTTP来处理,直接明文转发,自然就和目标服务的HTTPS要求不匹配了。
这里给你三个可行的方案,根据你的需求选就行:
方案1:配置ServiceEntry让Sidecar直接透传HTTPS流量(推荐)
如果你不需要Istio对这个无Sidecar的HTTPS服务做流量管理(比如监控、路由规则这些),最简单的办法就是告诉Sidecar不要插手这个服务的流量,让你的服务直接和目标服务建立HTTPS连接。
创建一个ServiceEntry配置:
apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: external-https-service spec: hosts: - "your-target-service-domain.com" # 替换成你实际的目标服务域名 ports: - number: 443 name: https protocol: HTTPS resolution: DNS location: MESH_EXTERNAL
应用这个配置后,Sidecar会把该域名443端口的流量直接透传,不做任何协议转换,你的服务就能正常发起HTTPS请求了。
方案2:配置DestinationRule让Sidecar正确处理HTTPS转发
如果你需要Istio对这个服务做流量管理(比如设置超时、重试,或者后续要加路由规则),那得告诉Sidecar目标服务用的是HTTPS协议,让它加密后再转发。
首先确保你已经有对应的Service或者ServiceEntry(如果是外部服务就用上面的ServiceEntry),然后添加一个DestinationRule:
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: target-https-destination spec: host: your-target-service-domain.com # 和ServiceEntry的host保持一致 trafficPolicy: tls: mode: SIMPLE # 表示Sidecar会和目标服务建立标准HTTPS连接
这样Sidecar就会以HTTPS的方式转发请求,不会再用明文了。
方案3:检查服务代码的请求配置
虽然概率不高,但也别忘了确认你的服务代码里有没有写错请求地址:比如是不是把https://写成了http://,或者错误地使用了80端口而不是443端口。这种低级错误有时候也会导致同样的问题。
- 查看Sidecar日志:通过
kubectl logs <你的Pod名称> istio-proxy命令查看Sidecar的转发日志,能清楚看到请求的协议、目标地址是不是符合预期,帮你快速定位问题。 - 确认出站流量权限:如果目标服务是集群外部的,要确保Istio允许Pod访问外部的443端口,部分严格的Istio配置可能会阻止外部流量,这时候需要配合ServiceEntry和AuthorizationPolicy来放行。
内容的提问来源于stack exchange,提问作者chilu

