Istio 运维实战系列(2):让人头大的『无头服务』-上

本文探讨了Kubernetes中的无头服务(Headless Service)及其在Istio服务网格中的特殊处理,特别是遇到的mTLS故障问题。故障表现为Envoy Sidecar在向未安装Sidecar的Redis集群发起mTLS连接失败。通过分析Envoy配置,发现是由于Istio 1.6之前的版本存在Bug。解决方案是通过Destination Rule禁用Headless Service的mTLS。建议升级至Istio 1.6或使用腾讯云的TCM服务来避免此类问题。
摘要由CSDN通过智能技术生成

本系列文章将介绍用户从 Spring Cloud,Dubbo 等传统微服务框架迁移到 Istio 服务网格时的一些经验,以及在使用 Istio 过程中可能遇到的一些常见问题的解决方法。

什么是『无头服务』?

『无头服务』即 Kubernetes 中的 Headless Service。Service 是 Kubernetes 对后端一组提供相同服务的 Pod 的逻辑抽象和访问入口。Kubernetes 会根据调度算法为 Pod 分配一个运行节点,并随机分配一个 IP 地址;在很多情况下,我们还会对 Pod 进行水平伸缩,启动多个 Pod 来提供相同的服务。在有多个 Pod 并且 Pod IP 地址不固定的情况下,客户端很难通过 Pod 的 IP 地址来直接进行访问。为了解决这个问题,Kubernetes 采用 Service 资源来表示提供相同服务的一组 Pod。

在缺省情况下,Kubernetes 会为 Service 分配一个 Cluster IP,不管后端的 Pod IP 如何变化,Service 的 Cluster IP 始终是固定的。因此客户端可以通过这个 Cluster IP 来访问这一组 Pod 提供的服务,而无需再关注后端的各个真实的 Pod IP。我们可以将 Service 看做放在一组 Pod 前的一个负载均衡器,而 Cluster IP 就是该负载均衡器的地址,这个负载均衡器会关注后端这组 Pod 的变化,并把发向 Cluster IP 的请求转发到后端的 Pod 上。(备注:这只是对 Service 的一个简化描述,如果对 Service 的内部实现感兴趣,可以参考这篇文章 如何为服务网格选择入口网关?

对于无状态的应用来说,客户端并不在意其连接的是哪一个 Pod,采用 Service 是没有问题的。但在某些特殊情况下,并不能这样做。例如,如果后端的这一组 Pod 是有状态的,需要由客户端根据某种应用相关的算法来选择哪一个 Pod 提供服务;或者客户端需要连接所有的后端 Pod,这时我们就不能在这一组 Pod 前放一个负载均衡器了。这种情况下,我们需要采用 Headless Service,即无头服务(该命名把多个 Pod 前面的负载均衡器比作服务的头,很形象是不是?)。在定义 Headless Service,我们需要把 Service 的 Cluster IP 显示设置为 None,这样 Kubernetes DNS 在解析该 Service 时会直接返回其后端的多个 Pod IP,而不是 Service 的 Cluster IP。

假设从客户端访问一个 Redis 集群,分别采用带 Cluster IP 的普通 Service 和 Headless Service 进行访问的过程如下图所示:

Istio 中『无头服务』的 mTLS 故障

由于 Headless Service 的特殊性,Istio 中对 Headless Service 的处理和普通 Service 有所不同,在应用迁移到 Isito 的过程中也常常遇到由于 Headless Service 导致的一些问题。下面我们就以一个由于 Headless Service 的 mTLS 故障导致的典型案例进行说明。

故障现象:运维同学反馈从带 Envoy Sidecar 的 Pod 中访问 Redis 服务器,但在没有安装 Sidecar 的 Pod 中可以正常访问该 Redis 服务器。

遇到无法进行出向访问的问题,我们可以首先通过 Envoy 的管理接口来查看 Envoy 的访问日志。在客户端 Pod 中运行下面的命令查看 Envoy 日志:

kubectl logs -f redis-client-6d4c6c975f-bm5w6 -c istio-proxy

日志中对 Redis 的访问记录如下,其中 UR,URX 是 Response Flag,表示 upstream connection failure,即连接上游失败。

[2020-09-12T13:38:23.077Z] "- - -" 0 UF,URX "-" "-" 0 0 1001 - "-" "-" "-" "-" "10.1.1.24:6379" outbound|6379||redis.default.svc.cluster.local - 10.1.1.24:6379 10.1.1.25:45940 - -

我们可以通过 Envoy 管理接口导出其 xDS 配置,以进一步分析其失败原因。

kubectl exec redis-client-6d4c6c975f-bm5w6 -c istio-proxy curl http://127.0.0.1:15000/config_dump

由于是出向访问错误,因此我们主要关注客户端中该出向访问的 Cluster 的配置。在导出的 xDS 配置中,可以看到 Redis Cluster 的配置,如下面的 yaml 片段所示(为了方便读者查看,去掉了该 yaml 中一些无关的内容):

{
   
     "version_info": "2020-09-13T00:33:43Z/5",
     "cluster": {
   
      "@type": "type.googleapis.com/envoy.api.v2.Cluster",
      "name": "outbound|6379||redis.default.svc.cluster.local",
      "type": "ORIGINAL_DST",
      "connect_timeout": "1s",
      "lb_policy": "CLUSTER_PROVIDED",
      "circuit_breakers": {
   
        ...
      },

      # mTLS 相关设置
      "transport_socket": {
   
       "name": "envoy.transport_sockets.tls",
       "typed_config": {
   
        "@type": "type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext",
        "common_tls_context": {
   
         "alpn_protocols": [
          "istio-peer-exchange",
          "istio"
         ],

         # 访问 Redis 使用的客户端证书
         "tls_certificate_sds_secret_configs": [
          {
   
           "name": "default",
           "sds_config"
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值