微服务网格Service Mesh初探之Istio

微服务网格Service Mesh初探之Istio

1 微服务架构的演进

作为一种架构模式,微服务将复杂系统切分为数十乃至上百个小服务,每个服务负责实现一个独立的业务逻辑。这些小服务易于被小型的软件工程师团队所理解和修改,并带来了语言和框架选择灵活性,缩短应用开发上线时间,可根据不同的工作负载和资源要求对服务进行独立缩扩容等优势。

另一方面,当应用被拆分为多个微服务进程后,进程内的方法调用变成了了进程间的远程调用。引入了对大量服务的连接、管理和监控的复杂性。

img

该变化带来了分布式系统的一系列问题,例如:

  • 如何找到服务的提供方?
  • 如何保证远程方法调用的可靠性?
  • 如何保证服务调用的安全性?
  • 如何降低服务调用的延迟?
  • 如何进行端到端的调试?

另外生产部署中的微服务实例也增加了运维的难度,例如:

  • 如何收集大量微服务的性能指标已进行分析?
  • 如何在不影响上线业务的情况下对微服务进行升级?
  • 如何测试一个微服务集群部署的容错和稳定性?

这些问题涉及到成百上千个服务的通信、管理、部署、版本、安全、故障转移、策略执行、遥测和监控等,要解决这些微服务架构引入的问题并非易事。

让我们来回顾一下微服务架构的发展过程。在出现服务网格之前,我们最开始在微服务应用程序内理服务之间的通讯逻辑,包括服务发现,熔断,重试,超时,加密,限流等逻辑。

img

在一个分布式系统中,这部分逻辑比较复杂,为了为微服务应用提供一个稳定、可靠的基础设施层,避免大家重复造轮子,并减少犯错的可能,一般会通过对这部分负责服务通讯的逻辑进行抽象和归纳,形成一个代码库供各个微服务应用程序使用,如下图所示:

img

公共的代码库减少了应用程序的开发和维护工作量,降低了由应用开发人员单独实现微服务通讯逻辑出现错误的机率,但还是存在下述问题: 公共的代码库减少了应用程序的开发和维护工作量,降低了由应用开发人员单独实现微服务通讯逻辑出现错误的机率,但还是存在下述问题:

  • 微服务通讯逻辑对应用开发人员并不透明,应用开发人员需要理解并正确使用代码 库,不能将其全部精力聚焦于业务逻辑。
  • 需要针对不同的语言/框架开发不同的代码库,反过来会影响微服务应用开发语言和框架的选择,影响技术选择的灵活性。
  • 随着时间的变化,代码库会存在不同的版本,不同版本代码库的兼容性和大量运行环境中微服务的升级将成为一个难题。

可以将微服务之间的通讯基础设施层和TCP/IP协议栈进行类比。TCP/IP协议栈为操作系统中的所有应用提供基础通信服务,但TCP/IP协议栈和应用程序之间并没有紧密的耦合关系,应用只需要使用TCP/IP协议提供的底层通讯功能,并不关心TCP/IP协议的实现,如IP如何进行路由,TCP如何创建链接等。

同样地,微服务应用也不应该需要关注服务发现,Load balancing,Retries,Circuit Breaker等微服务之间通信的底层细节。如果将为微服务提供通信服务的这部分逻辑从应用程序进程中抽取出来,作为一个单独的进程进行部署,并将其作为服务间的通信代理,可以得到如下图所示的架构:

img

因为通讯代理进程伴随应用进程一起部署,因此形象地把这种部署方式称为“sidecar”/边车(即三轮摩托的挎斗)。

应用间的所有流量都需要经过代理,由于代理以sidecar方式和应用部署在同一台主机上,应用和代理之间的通讯可以被认为是可靠的。由代理来负责找到目的服务并负责通讯的可靠性和安全等问题。

当服务大量部署时,随着服务部署的sidecar代理之间的连接形成了一个如下图所示的网格,该网格成为了微服务的通讯基础设施层,承载了微服务之间的所有流量,被称之为Service Mesh(服务网格)

img

服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求可以在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由 一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但应用程序不需要知道它们的存在。

William Morgan WHAT’S A SERVICE MESH? AND WHY DO I NEED ONE?_

服务网格中有数量众多的Sidecar代理,如果对每个代理分别进行设置,工作量将非常巨大。为了更方便地对服务网格中的代理进行统一集中控制,在服务网格上增加了控制面组件。

img

这里我们可以类比SDN的概念,控制面就类似于SDN网管中的控制器,负责路由策略的指定和路由规则下发;数据面类似于SDN网络中交换机,负责数据包的转发。

由于微服务的所有通讯都由服务网格基础设施层提供,通过控制面板和数据面板的配合,可以对这些通讯进行监控、托管和控制,以实现微服务灰度发布,调用分布式追踪,故障注入模拟测试,动态路由规则,微服务闭环控制等管控功能。

2 Istio 是什么2?

云平台令使用它们的公司受益匪浅。但不可否认的是,上云会给 DevOps 团队带来压力。为了可移植性,开发人员必须使用微服务来构建应用,同时运维人员也正在管理着极端庞大的混合云和多云的部署环境。 Istio 允许您连接、保护、控制和观察服务。

从较高的层面来说,Istio 有助于降低这些部署的复杂性,并减轻开发团队的压力。它是一个完全开源的服务网格,作为透明的一层接入到现有的分布式应用程序里。它也是一个平台,拥有可以集成任何日志、遥测和策略系统的 API 接口。Istio 多样化的特性使您能够成功且高效地运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法。

服务网格是什么?

Istio 解决了开发人员和运维人员所面临的从单体应用向分布式微服务架构转变的挑战。了解它是如何做到这一点的可以让我们更详细地理解 Istio 的服务网格。

术语服务网格用来描述组成这些应用程序的微服务网络以及它们之间的交互。随着服务网格的规模和复杂性不断的增长,它将会变得越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、度量和监控等。服务网格通常还有更复杂的运维需求,比如 A/B 测试、金丝雀发布、速率限制、访问控制和端到端认证。

Istio 提供了对整个服务网格的行为洞察和操作控制的能力,以及一个完整的满足微服务应用各种需求的解决方案。

为什么使用 Istio?

通过负载均衡、服务间的身份验证、监控等方法,Istio 可以轻松地创建一个已经部署了服务的网络,而服务的代码只需很少更改甚至无需更改。通过在整个环境中部署一个特殊的 sidecar 代理为服务添加 Istio 的支持,而代理会拦截微服务之间的所有网络通信,然后使用其控制平面的功能来配置和管理 Istio,这包括:

  • 为 HTTP、gRPC、WebSocket 和 TCP 流量自动负载均衡。
  • 通过丰富的路由规则、重试、故障转移和故障注入对流量行为进行细粒度控制。
  • 可插拔的策略层和配置 API,支持访问控制、速率限制和配额。
  • 集群内(包括集群的入口和出口)所有流量的自动化度量、日志记录和追踪。
  • 在具有强大的基于身份验证和授权的集群中实现安全的服务间通信。

Istio 为可扩展性而设计,可以满足不同的部署需求。

核心特性

Istio 以统一的方式提供了许多跨服务网络的关键功能:

流量管理

Istio 简单的规则配置和流量路由允许您控制服务之间的流量和 API 调用过程。Istio 简化了服务级属性(如熔断器、超时和重试)的配置,并且让它轻而易举的执行重要的任务(如 A/B 测试、金丝雀发布和按流量百分比划分的分阶段发布)。

有了更好的对流量的可视性和开箱即用的故障恢复特性,您就可以在问题产生之前捕获它们,无论面对什么情况都可以使调用更可靠,网络更健壮。

请参考流量管理文档获取更多细节。

安全

Istio 的安全特性解放了开发人员,使其只需要专注于应用程序级别的安全。Istio 提供了底层的安全通信通道,并为大规模的服务通信管理认证、授权和加密。有了 Istio,服务通信在默认情况下就是受保护的,可以让您在跨不同协议和运行时的情况下实施一致的策略——而所有这些都只需要很少甚至不需要修改应用程序。

Istio 是独立于平台的,可以与 Kubernetes(或基础设施)的网络策略一起使用。但它更强大,能够在网络和应用层面保护pod到 pod 或者服务到服务之间的通信。

请参考安全文档获取更多细节。

可观察性

Istio 健壮的追踪、监控和日志特性让您能够深入的了解服务网格部署。通过 Istio 的监控能力,可以真正的了解到服务的性能是如何影响上游和下游的;而它的定制 Dashboard 提供了对所有服务性能的可视化能力,并让您看到它如何影响其他进程。

Istio 的 Mixer 组件负责策略控制和遥测数据收集。它提供了后端抽象和中介,将一部分 Istio 与后端的基础设施实现细节隔离开来,并为运维人员提供了对网格与后端基础实施之间交互的细粒度控制。

所有这些特性都使您能够更有效地设置、监控和加强服务的 SLO。当然,底线是您可以快速有效地检测到并修复出现的问题。

请参考可观察性文档获取更多细节。

平台支持

Istio 独立于平台,被设计为可以在各种环境中运行,包括跨云、内部环境、Kubernetes、Mesos 等等。您可以在 Kubernetes 或是装有 Consul 的 Nomad 环境上部署 Istio。Istio 目前支持:

  • Kubernetes 上的服务部署
  • 基于 Consul 的服务注册
  • 服务运行在独立的虚拟机上

整合和定制

Istio 的策略实施组件可以扩展和定制,与现有的 ACL、日志、监控、配额、审查等解决方案集成。

3 Istio服务网格

Istio架构

Istio是一个Service Mesh开源项目,是Google继Kubernetes之后的又一力作,主要参与的公司包括Google,IBM和Lyft。

凭借kubernetes良好的架构设计及其强大的扩展性,Google围绕kubernetes打造一个生态系统。Kubernetes用于微服务的编排(编排是英文Orchestration的直译,用大白话说就是描述一组微服务之间的关联关系,并负责微服务的部署、终止、升级、缩扩容等)。其向下用CNI(容器网络接口),CRI(容器运行时接口)标准接口可以对接不同的网络和容器运行时实现,提供微服务运行的基础设施。向上则用Istio提供了微服务治理功能。

由下图可见,Istio补充了Kubernetes生态圈的重要一环,是Google的微服务版图里一个里程碑式的扩张。

img

Google借Istio的力量推动微服务治理的事实标准,对Google自身的产品Google Cloud有极其重大的意义。其他的云服务厂商,如Redhat,Pivotal,Nginx,Buoyant等看到大势所趋,也纷纷跟进,宣布自身产品和Istio进行集成,以避免自己被落下,丢失其中的市场机会。

可以预见不久的将来,对于云原生应用而言,采用kubernetes进行服务部署和集群管理,采用Istio处理服务通讯和治理,将成为微服务应用的标准配置。

Istio服务包括网格由数据面和控制面两部分。

  • 数据面由一组智能代理(Envoy)组成,代理部署为边车,调解和控制微服务之间所有的网络通信。
  • 控制面负责管理和配置代理来路由流量,以及在运行时执行策略。

img

服务网格选择Istio

  • 在控制面上,Istio作为一种全新的设计,在功能、形态、架构和扩展性上提供了远超服务网格的能力范围;
  • Istio基于xDS协议提供了一套标准的控制面规范,想数据面传递服务信息和治理规范;
  • Istio的早期版本使用Envoy V1版本的API,即RESTful方式,其新版本使用Envoy V2版本的API,即gRPC协议;
  • Envoy是用C++开发的,其性能和资源占用比用Rust开发的Linkerd Proxy更好,更能满足服务网格中对透明代理的轻量高性能的要求;
  • Envoy提供L3/L4过滤器、HTTP L7过滤器、支持HTTP/2、HTTP L7路由及gRPC、MongoDB、DynamoDB等协议;
  • Envoy有服务发现、健康检查、高级LB、前端代理等能力,具有极好的可观察性、动态配置功能;
  • Envoy是一个可高度定制化的程序,通过Filter机制提供了高度扩展性,还支持热重启,其代码基于模块化编码,易于测试;
  • 在大厂支持上,Istio由谷歌和IBM共同推出,从应用场景的分析规划到本身的定位,从自身架构的设计到与周边生态的结合,都有着比较严密的论证;
  • Istio与Kubernetes无缝结合,Istio称为架构的默认部分,就像容器和Kubernetes已经成为云原生架构的默认部分一样。

4 Istio与Kubernetes

Kubernetes的Service基于每个节点的kube-proxy从kube-apiserver上获取Service和Endpoint的信息,并将对Service的请求经过负载均衡转发到对应的Endpoint上。

但Kubernetes只提供了4层负载均衡能力,无法基于应用层的信息进行负载均衡,更不能提供应用层的流量管理,在服务运行管理上也只提供了基本的探针机制,并不能提供服务访问的指标和调用链追踪这种应用的服务运行诊断能力。

Istio复用了Kubernetes Service的定义,在实现上进行了更细粒度的控制。

Istio的服务发现就是从kube-apiserver中获取Service和Endpoint,然后将其转换成Istio服务模型的Service和ServiceInstance,但是其数据面组件不再是kube-proxy,而是在每个Pod里部署的Sidecar,也可以将其看作每个服务实例的Proxy。

通过拦截Pod的Inbound流量和Outbound流量,并在Sidecar上解析各种应用层协议,Istio可以提供真正的应用层治理、监控和安全等能力。

总之,Istio和Kubernetes从设计理念、使用体验、系统架构甚至代码风格等小细节来看,关系都非常紧密,甚至有人认为Istio就是Kubernetes团队开发的Kubernetes可插拔的增强特性。
image.png

5 流量管理

Istio 的流量路由规则可以让您很容易的控制服务之间的流量和 API 调用。Istio 简化了服务级别属性的配置,比如熔断器、超时和重试,并且能轻松的设置重要的任务,如 A/B 测试、金丝雀发布、基于流量百分比切分的概率发布等。它还提供了开箱即用的故障恢复特性,有助于增强应用的健壮性,从而更好地应对被依赖的服务或网络发生故障的情况。

Istio 的流量管理模型源于和服务一起部署的 Envoy 代理。网格内服务发送和接收的所有流量(data plane流量)都经由 Envoy 代理,这让控制网格内的流量变得异常简单,而且不需要对服务做任何的更改。

本节中描述的功能特性,如果您对它们是如何工作的感兴趣的话,可以在架构概述中找到关于 Istio 的流量管理实现的更多信息。本部分只介绍 Istio 的流量管理特性。

Istio 流量管理介绍

为了在网格中导流,Istio 需要知道所有的 endpoint 在哪和属于哪个服务。为了定位到service registry(服务注册中心),Istio 会连接到一个服务发现系统。例如,如果您在 Kubernetes 集群上安装了 Istio,那么它将自动检测该集群中的服务和 endpoint。

使用此服务注册中心,Envoy 代理可以将流量定向到相关服务。大多数基于微服务的应用程序,每个服务的工作负载都有多个实例来处理流量,称为负载均衡池。默认情况下,Envoy 代理基于轮询调度模型在服务的负载均衡池内分发流量,按顺序将请求发送给池中每个成员,一旦所有服务实例均接收过一次请求后,重新回到第一个池成员。

Istio 基本的服务发现和负载均衡能力为您提供了一个可用的服务网格,但它能做到的远比这多的多。在许多情况下,您可能希望对网格的流量情况进行更细粒度的控制。作为 A/B 测试的一部分,您可能想将特定百分比的流量定向到新版本的服务,或者为特定的服务实例子集应用不同的负载均衡策略。您可能还想对进出网格的流量应用特殊的规则,或者将网格的外部依赖项添加到服务注册中心。通过使用 Istio 的流量管理 API 将流量配置添加到 Istio,就可以完成所有这些甚至更多的工作。

和其他 Istio 配置一样,这些 API 也使用 Kubernetes 的自定义资源定义(CRDs)来声明,您可以像示例中看到的那样使用 YAML 进行配置。

本章节的其余部分将分别介绍每个流量管理 API 以及如何使用它们。这些资源包括:

指南也对构建在 API 资源内的网络弹性和测试做了概述。

虚拟服务

虚拟服务(Virtual Service)目标规则(Destination Rule) 是 Istio 流量路由功能的关键拼图。虚拟服务让您配置如何在服务网格内将请求路由到服务,这基于 Istio 和平台提供的基本的连通性和服务发现能力。每个虚拟服务包含一组路由规则,Istio 按顺序评估它们,Istio 将每个给定的请求匹配到虚拟服务指定的实际目标地址。您的网格可以有多个虚拟服务,也可以没有,取决于您的使用场景。

为什么使用虚拟服务?

虚拟服务在增强 Istio 流量管理的灵活性和有效性方面,发挥着至关重要的作用,通过对客户端请求的目标地址与真实响应请求的目标工作负载进行解耦来实现。虚拟服务同时提供了丰富的方式,为发送至这些工作负载的流量指定不同的路由规则。

为什么这如此有用?就像在介绍中所说,如果没有虚拟服务,Envoy 会在所有的服务实例中使用轮询的负载均衡策略分发请求。您可以用您对工作负载的了解来改善这种行为。例如,有些可能代表不同的版本。这在 A/B 测试中可能有用,您可能希望在其中配置基于不同服务版本的流量百分比路由,或指引从内部用户到特定实例集的流量。

使用虚拟服务,您可以为一个或多个主机名指定流量行为。在虚拟服务中使用路由规则,告诉 Envoy 如何发送虚拟服务的流量到适当的目标。路由目标地址可以是同一服务的不同版本,也可以是完全不同的服务。

一个典型的用例是将流量发送到被指定为服务子集的服务的不同版本。客户端将虚拟服务视为一个单一实体,将请求发送至虚拟服务主机,然后 Envoy 根据虚拟服务规则把流量路由到不同的版本。例如,“20% 的调用转到新版本”或“将这些用户的调用转到版本 2”。这允许您创建一个金丝雀发布,逐步增加发送到新版本服务的流量百分比。流量路由完全独立于实例部署,这意味着实现新版本服务的实例可以根据流量的负载来伸缩,完全不影响流量路由。相比之下,像 Kubernetes 这样的容器编排平台只支持基于实例缩放的流量分发,这会让情况变得复杂。您可以在使用 Istio 进行金丝雀部署的文章里阅读到更多用虚拟服务实现金丝雀部署的内容。

虚拟服务可以让您:

  • 通过单个虚拟服务处理多个应用程序服务。如果您的网格使用 Kubernetes,可以配置一个虚拟服务处理特定命名空间中的所有服务。映射单一的虚拟服务到多个“真实”服务特别有用,可以在不需要客户适应转换的情况下,将单体应用转换为微服务构建的复合应用系统。您的路由规则可以指定为“对这些 monolith.com 的 URI 调用转到microservice A”等等。您可以在下面的一个示例看到它是如何工作的。
  • 网关整合并配置流量规则来控制出入流量。

在某些情况下,您还需要配置目标规则来使用这些特性,因为这是指定服务子集的地方。在一个单独的对象中指定服务子集和其它特定目标策略,有利于在虚拟服务之间更简洁地重用这些规则。在下一章节您可以找到更多关于目标规则的内容。

虚拟服务示例

下面的虚拟服务根据请求是否来自特定的用户,把它们路由到服务的不同版本。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v3

hosts 字段

使用 hosts 字段列举虚拟服务的主机——即用户指定的目标或是路由规则设定的目标。这是客户端向服务发送请求时使用的一个或多个地址。

hosts:
- reviews

虚拟服务主机名可以是 IP 地址、DNS 名称,或者依赖于平台的一个简称(例如 Kubernetes 服务的短名称),隐式或显式地指向一个完全限定域名(FQDN)。您也可以使用通配符(“*”)前缀,让您创建一组匹配所有服务的路由规则。虚拟服务的 hosts 字段实际上不必是 Istio 服务注册的一部分,它只是虚拟的目标地址。这让您可以为没有路由到网格内部的虚拟主机建模。

路由规则

http 字段包含了虚拟服务的路由规则,用来描述匹配条件和路由行为,它们把 HTTP/1.1、HTTP2 和 gRPC 等流量发送到 hosts 字段指定的目标(您也可以用 tcptls 片段为 TCP 和未终止的 TLS 流量设置路由规则)。一个路由规则包含了指定的请求要流向哪个目标地址,具有 0 或多个匹配条件,取决于您的使用场景。

匹配条件

示例中的第一个路由规则有一个条件,因此以 match 字段开始。在本例中,您希望此路由应用于来自 ”jason“ 用户的所有请求,所以使用 headersend-userexact 字段选择适当的请求。

- match:
   - headers:
       end-user:
         exact: jason
Destination

route 部分的 destination 字段指定了符合此条件的流量的实际目标地址。与虚拟服务的 hosts 不同,destination 的 host 必须是存在于 Istio 服务注册中心的实际目标地址,否则 Envoy 不知道该将请求发送到哪里。可以是一个有代理的服务网格,或者是一个通过服务入口被添加进来的非网格服务。本示例运行在 Kubernetes 环境中,host 名为一个 Kubernetes 服务名:

route:
- destination:
    host: reviews
    subset: v2

请注意,在该示例和本页其它示例中,为了简单,我们使用 Kubernetes 的短名称设置 destination 的 host。在评估此规则时,Istio 会添加一个基于虚拟服务命名空间的域后缀,这个虚拟服务包含要获取主机的完全限定名的路由规则。在我们的示例中使用短名称也意味着您可以复制并在任何喜欢的命名空间中尝试它们。

只有在目标主机和虚拟服务位于相同的 Kubernetes 命名空间时才可以使用这样的短名称。因为使用 Kubernetes 的短名称容易导致配置出错,我们建议您在生产环境中指定完全限定的主机名。

destination 片段还指定了 Kubernetes 服务的子集,将符合此规则条件的请求转入其中。在本例中子集名称是 v2。您可以在目标规则章节中看到如何定义服务子集。

路由规则优先级

路由规则按从上到下的顺序选择,虚拟服务中定义的第一条规则有最高优先级。本示例中,不满足第一个路由规则的流量均流向一个默认的目标,该目标在第二条规则中指定。因此,第二条规则没有 match 条件,直接将流量导向 v3 子集。

- route:
  - destination:
      host: reviews
      subset: v3

我们建议提供一个默认的“无条件”或基于权重的规则(见下文)作为每一个虚拟服务的最后一条规则,如案例所示,从而确保流经虚拟服务的流量至少能够匹配一条路由规则。

路由规则的更多内容

正如上面所看到的,路由规则是将特定流量子集路由到指定目标地址的强大工具。您可以在流量端口、header 字段、URI 等内容上设置匹配条件。例如,这个虚拟服务让用户发送请求到两个独立的服务:ratings 和 reviews,就好像它们是 http://bookinfo.com/ 这个更大的虚拟服务的一部分。虚拟服务规则根据请求的 URI 和指向适当服务的请求匹配流量。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    - destination:
        host: reviews
  - match:
    - uri:
        prefix: /ratings
    route:
    - destination:
        host: ratings
...

  http:
  - match:
      sourceLabels:
        app: reviews
    route:
...

有些匹配条件可以使用精确的值,如前缀或正则。

您可以使用 AND 向同一个 match 块添加多个匹配条件,或者使用 OR 向同一个规则添加多个 match 块。对于任何给定的虚拟服务也可以有多个路由规则。这可以在单个虚拟服务中使路由条件变得随您所愿的复杂或简单。匹配条件字段和备选值的完整列表可以在 HTTPMatchRequest 参考中找到。

另外,使用匹配条件您可以按百分比”权重“分发请求。这在 A/B 测试和金丝雀发布中非常有用:

spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 75
    - destination:
        host: reviews
        subset: v2
      weight: 25

您也可以使用路由规则在流量上执行一些操作,例如:

  • 添加或删除 header。
  • 重写 URL。
  • 为调用这一目标地址的请求设置重试策略

想了解如何利用这些操作,查看 HTTPRoute 参考

目标规则

虚拟服务一样,目标规则也是 Istio 流量路由功能的关键部分。您可以将虚拟服务视为将流量如何路由到给定目标地址,然后使用目标规则来配置该目标的流量。在评估虚拟服务路由规则之后,目标规则将应用于流量的“真实”目标地址。

特别是,您可以使用目标规则来指定命名的服务子集,例如按版本为所有给定服务的实例分组。然后可以在虚拟服务的路由规则中使用这些服务子集来控制到服务不同实例的流量。

目标规则还允许您在调用整个目的地服务或特定服务子集时定制 Envoy 的流量策略,比如您喜欢的负载均衡模型、TLS 安全模式或熔断器设置。在目标规则参考中可以看到目标规则选项的完整列表。

负载均衡选项

默认情况下,Istio 使用轮询的负载均衡策略,实例池中的每个实例依次获取请求。Istio 同时支持如下的负载均衡模型,可以在 DestinationRule 中为流向某个特定服务或服务子集的流量指定这些模型。

  • 随机:请求以随机的方式转到池中的实例。
  • 权重:请求根据指定的百分比转到实例。
  • 最少请求:请求被转到最少被访问的实例。

查看 Envoy 负载均衡文档获取这部分的更多信息。

目标规则示例

在下面的示例中,目标规则为 my-svc 目标服务配置了 3 个具有不同负载均衡策略的子集:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: my-destination-rule
spec:
  host: my-svc
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
  - name: v3
    labels:
      version: v3

每个子集都是基于一个或多个 labels 定义的,在 Kubernetes 中它是附加到像 Pod 这种对象上的键/值对。这些标签应用于 Kubernetes 服务的 Deployment 并作为 metadata 来识别不同的版本。

除了定义子集之外,目标规则对于所有子集都有默认的流量策略,而对于该子集,则有特定于子集的策略覆盖它。定义在 subsets 上的默认策略,为 v1v3 子集设置了一个简单的随机负载均衡器。在 v2 策略中,轮询负载均衡器被指定在相应的子集字段上。

网关

使用网关为网格来管理入站和出站流量,可以让您指定要进入或离开网格的流量。网关配置被用于运行在网格边界的独立 Envoy 代理,而不是服务工作负载的 sidecar 代理。

与 Kubernetes Ingress API 这种控制进入系统流量的其他机制不同,Istio 网关让您充分利用流量路由的强大能力和灵活性。您可以这么做的原因是 Istio 的网关资源可以配置 4-6 层的负载均衡属性,如对外暴露的端口、TLS 设置等。作为替代应用层流量路由(L7)到相同的 API 资源,您绑定了一个常规的 Istio 虚拟服务到网关。这让您可以像管理网格中其他数据平面的流量一样去管理网关流量。

网关主要用于管理进入的流量,但您也可以配置出口网关。出口网关让您为离开网格的流量配置一个专用的出口节点,这可以限制哪些服务可以或应该访问外部网络,或者启用出口流量安全控制为您的网格添加安全性。您也可以使用网关配置一个纯粹的内部代理。

Istio 提供了一些预先配置好的网关代理部署(istio-ingressgatewayistio-egressgateway)供您使用——如果使用我们的演示安装它们都已经部署好了;如果使用默认或 sds 配置文件则只部署了入口网关。可以将您自己的网关配置应用到这些部署或配置您自己的网关代理。

Gateway 示例

下面的示例展示了一个外部 HTTPS 入口流量的网关配置:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: ext-host-gwy
spec:
  selector:
    app: my-gateway-controller
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - ext-host.example.com
    tls:
      mode: SIMPLE
      serverCertificate: /tmp/tls.crt
      privateKey: /tmp/tls.key

这个网关配置让 HTTPS 流量从 ext-host.example.com 通过 443 端口流入网格,但没有为请求指定任何路由规则。为想要工作的网关指定路由,您必须把网关绑定到虚拟服务上。正如下面的示例所示,使用虚拟服务的 gateways 字段进行设置:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: virtual-svc
spec:
  hosts:
  - ext-host.example.com
  gateways:
    - ext-host-gwy

然后就可以为出口流量配置带有路由规则的虚拟服务。

服务入口

使用服务入口(Service Entry) 来添加一个入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样。配置服务入口允许您管理运行在网格外的服务的流量,它包括以下几种能力:

  • 为外部目标 redirect 和转发请求,例如来自 web 端的 API 调用,或者流向遗留老系统的服务。
  • 为外部目标定义重试超时故障注入策略。
  • 添加一个运行在虚拟机的服务来扩展您的网格
  • 从逻辑上添加来自不同集群的服务到网格,在 Kubernetes 上实现一个多集群 Istio 网格

您不需要为网格服务要使用的每个外部服务都添加服务入口。默认情况下,Istio 配置 Envoy 代理将请求传递给未知服务。但是,您不能使用 Istio 的特性来控制没有在网格中注册的目标流量。

服务入口示例

下面示例的 mesh-external 服务入口将 ext-resource 外部依赖项添加到 Istio 的服务注册中心:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: svc-entry
spec:
  hosts:
  - ext-svc.example.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  location: MESH_EXTERNAL
  resolution: DNS

您指定的外部资源使用 hosts 字段。可以使用完全限定名或通配符作为前缀域名。

您可以配置虚拟服务和目标规则,以更细粒度的方式控制到服务入口的流量,这与网格中的任何其他服务配置流量的方式相同。例如,下面的目标规则配置流量路由以使用双向 TLS 来保护到 ext-svc.example.com 外部服务的连接,我们使用服务入口配置了该外部服务:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: ext-res-dr
spec:
  host: ext-svc.example.com
  trafficPolicy:
    tls:
      mode: MUTUAL
      clientCertificate: /etc/certs/myclientcert.pem
      privateKey: /etc/certs/client_private_key.pem
      caCertificates: /etc/certs/rootcacerts.pem

查看服务入口参考获取更多可能的配置项。

Sidecar

默认情况下,Istio 让每个 Envoy 代理都可以访问来自和它关联的工作负载的所有端口的请求,然后转发到对应的工作负载。您可以使用 sidecar 配置去做下面的事情:

  • 微调 Envoy 代理接受的端口和协议集。
  • 限制 Envoy 代理可以访问的服务集合。

您可能希望在较庞大的应用程序中限制这样的 sidecar 可达性,配置每个代理能访问网格中的任意服务可能会因为高内存使用量而影响网格的性能。

您可以指定将 sidecar 配置应用于特定命名空间中的所有工作负载,或者使用 workloadSelector 选择特定的工作负载。例如,下面的 sidecar 配置将 bookinfo 命名空间中的所有服务配置为仅能访问运行在相同命名空间和 Istio 控制平面中的服务(目前需要使用 Istio 的策略和遥测功能):

apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
  name: default
  namespace: bookinfo
spec:
  egress:
  - hosts:
    - "./*"
    - "istio-system/*"

查阅 Sidecar 参考获取详细信息。

网络弹性和测试

除了为您的网格导流之外,Istio 还提供了可选的故障恢复和故障注入功能,您可以在运行时动态配置这些功能。使用这些特性可以让您的应用程序运行稳定,确保服务网格能够容忍故障节点,并防止局部故障级联影响到其他节点。

超时

超时是 Envoy 代理等待来自给定服务的答复的时间量,以确保服务不会因为等待答复而无限期的挂起,并在可预测的时间范围内调用成功或失败。HTTP 请求的默认超时时间是 15 秒,这意味着如果服务在 15 秒内没有响应,调用将失败。

对于某些应用程序和服务,Istio 的缺省超时可能不合适。例如,超时太长可能会由于等待失败服务的回复而导致过度的延迟;而超时过短则可能在等待涉及多个服务返回的操作时触发不必要地失败。为了找到并使用最佳超时设置,Istio 允许您使用虚拟服务按服务轻松地动态调整超时,而不必修改您的业务代码。下面的示例是一个虚拟服务,它对 ratings 服务的 v1 子集的调用指定 10 秒超时:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    timeout: 10s

重试

重试设置指定如果初始调用失败,Envoy 代理尝试连接服务的最大次数。通过确保调用不会因为临时过载的服务或网络等问题而永久失败,重试可以提高服务可用性和应用程序的性能。重试之间的间隔(25ms+)是可变的,并由 Istio 自动确定,从而防止被调用服务被请求淹没。默认情况下,在第一次失败后,Envoy 代理不会重新尝试连接服务。

与超时一样,Istio 默认的重试行为在延迟方面可能不适合您的应用程序需求(对失败的服务进行过多的重试会降低速度)或可用性。您可以在虚拟服务中按服务调整重试设置,而不必修改业务代码。您还可以通过添加每次重试的超时来进一步细化重试行为,并指定每次重试都试图成功连接到服务所等待的时间量。下面的示例配置了在初始调用失败后最多重试 3 次来连接到服务子集,每个重试都有 2 秒的超时。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    retries:
      attempts: 3
      perTryTimeout: 2s

熔断器

熔断器是 Istio 为创建具有弹性的微服务应用提供的另一个有用的机制。在熔断器中,设置一个对服务中的单个主机调用的限制,例如并发连接的数量或对该主机调用失败的次数。一旦限制被触发,熔断器就会“跳闸”并停止连接到该主机。使用熔断模式可以快速失败而不必让客户端尝试连接到过载或有故障的主机。

熔断适用于在负载均衡池中的“真实”网格目标地址,您可以在目标规则中配置熔断器阈值,让配置适用于服务中的每个主机。下面的示例将 v1 子集的reviews服务工作负载的并发连接数限制为 100:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
    trafficPolicy:
      connectionPool:
        tcp:
          maxConnections: 100

您可以在熔断中查看更多相关信息。

故障注入

在配置了网络,包括故障恢复策略之后,可以使用 Istio 的故障注入机制来为整个应用程序测试故障恢复能力。故障注入是一种将错误引入系统以确保系统能够承受并从错误条件中恢复的测试方法。使用故障注入特别有用,能确保故障恢复策略不至于不兼容或者太严格,这会导致关键服务不可用。

与其他错误注入机制(如延迟数据包或在网络层杀掉 Pod)不同,Istio 允许在应用层注入错误。这使您可以注入更多相关的故障,例如 HTTP 错误码,以获得更多相关的结果。

您可以注入两种故障,它们都使用虚拟服务配置:

  • 延迟:延迟是时间故障。它们模拟增加的网络延迟或一个超载的上游服务。
  • 终止:终止是崩溃失败。他们模仿上游服务的失败。终止通常以 HTTP 错误码或 TCP 连接失败的形式出现。

例如,下面的虚拟服务为千分之一的访问 ratings 服务的请求配置了一个 5 秒的延迟:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        percentage:
          value: 0.1
        fixedDelay: 5s
    route:
    - destination:
        host: ratings
        subset: v1

有关如何配置延迟和终止的详细信息请参考故障注入

和您的应用程序一起运行

Istio 故障恢复功能对应用程序来说是完全透明的。在返回响应之前,应用程序不知道 Envoy sidecar 代理是否正在处理被调用服务的故障。这意味着,如果在应用程序代码中设置了故障恢复策略,那么您需要记住这两个策略都是独立工作的,否则会发生冲突。例如,假设您设置了两个超时,一个在虚拟服务中配置,另一个在应用程序中配置。应用程序为服务的 API 调用设置了 2 秒超时。而您在虚拟服务中配置了一个 3 秒超时和重试。在这种情况下,应用程序的超时会先生效,因此 Envoy 的超时和重试尝试会失效。

虽然 Istio 故障恢复特性提高了网格中服务的可靠性和可用性,但应用程序必须处理故障或错误并采取适当的回退操作。例如,当负载均衡中的所有实例都失败时,Envoy 返回一个HTTP 503代码。应用程序必须实现回退逻辑来处理HTTP 503错误代码。

6 扩展性

WebAssembly 是一种沙盒技术,可以用于扩展 Istio 代理(Envoy)的能力。Proxy-Wasm 沙盒 API 取代了 Mixer 作为 Istio 主要的扩展机制。在 Istio 1.6 中将会为 Proxy-Wasm 插件提供一种统一的配置 API。

WebAssembly 沙盒的目标:

  • 效率 - 这是一种低延迟,低 CPU 和内存开销的扩展机制。
  • 功能 - 这是一种可以执行策略,收集遥测数据和执行有效荷载变更的扩展机制。
  • 隔离 - 一个插件中程序的错误或是崩溃不会影响其它插件。
  • 配置 - 插件使用与其它 Istio API 一致的 API 进行配置。可以动态的配置扩展。
  • 运维 - 扩展可以以仅日志,故障打开或者故障关闭的方式进行访问和部署。
  • 扩展开发者 - 可以用多种编程语言编写。

这个演讲视频是关于 WebAssembly 集成架构的介绍。

高级架构

Istio 扩展(Proxy-Wasm 插件)有几个组成部分:

  • 过滤器服务提供商接口 用于为过滤器构建 Proxy-Wasm 插件。
  • 沙盒 在 Envoy 中嵌入 V8 Wasm 运行时。
  • 主机 API 用于处理请求头,尾和元数据。
  • 调出 API 针对 gRPC 和 HTTP 请求。
  • 统计和记录 API 用于度量统计和监控。

扩展 Istio/Envoy

扩展 Istio/Envoy

例子

这里是用 C++ 为过滤器实现 Proxy-Wasm 插件的例子。

为过滤器实现一个 Proxy-Wasm 插件需要:

SDK

C++ SDK 的详细说明见这里

生态

7 安全

将单一应用程序分解为微服务可提供各种好处,包括更好的灵活性、可伸缩性以及服务复用的能力。但是,微服务也有特殊的安全需求:

  • 为了抵御中间人攻击,需要流量加密。
  • 为了提供灵活的服务访问控制,需要双向 TLS 和细粒度的访问策略。
  • 要确定谁在什么时候做了什么,需要审计工具。

Istio Security 尝试提供全面的安全解决方案来解决所有这些问题。本页概述了如何使用 Istio 的安全功能来保护您的服务,无论您在何处运行它们。特别是 Istio 安全性可以缓解针对您的数据、端点、通信和平台的内部和外部威胁。

安全概述

安全概述

Istio 安全功能提供强大的身份,强大的策略,透明的 TLS 加密,认证,授权和审计(AAA)工具来保护你的服务和数据。Istio 安全的目标是:

  • 默认安全:应用程序代码和基础设施无需更改
  • 深度防御:与现有安全系统集成以提供多层防御
  • 零信任网络:在不受信任的网络上构建安全解决方案

请访问我们的双向 TLS 迁移相关文章,开始在已部署的服务中使用 Istio 安全功能。 请访问我们的安全任务,以获取有关使用安全功能的详细说明。

高级架构

Istio 中的安全性涉及多个组件:

控制面处理来自 API server 的配置,并且在数据面中配置 PEPs。PEPs 用 Envoy 实现。下图显示了架构。

安全架构

安全架构

在下面的部分中,我们将详细介绍 Istio 安全功能。

Istio 身份

身份是任何安全基础架构的基本概念。在工作负载间通信开始时,双方必须交换包含身份信息的凭证以进行双向验证。在客户端,根据安全命名信息检查服务器的标识,以查看它是否是该服务的授权运行程序。在服务器端,服务器可以根据授权策略确定客户端可以访问哪些信息,审计谁在什么时间访问了什么,根据他们使用的工作负载向客户收费,并拒绝任何未能支付账单的客户访问工作负载。

Istio 身份模型使用 service identity (服务身份)来确定一个请求源端的身份。这种模型有极好的灵活性和粒度,可以用服务身份来标识人类用户、单个工作负载或一组工作负载。在没有服务身份的平台上,Istio 可以使用其它可以对服务实例进行分组的身份,例如服务名称。

下面的列表展示了在不同平台上可以使用的服务身份:

  • Kubernetes: Kubernetes service account
  • GKE/GCE: GCP service account
  • GCP: GCP service account
  • AWS: AWS IAM user/role account
  • 本地(非 Kubernetes):用户帐户、自定义服务帐户、服务名称、Istio 服务帐户或 GCP 服务帐户。自定义服务帐户引用现有服务帐户,就像客户的身份目录管理的身份一样。

公钥基础设施 (PKI)

Istio PKI 使用 X.509 证书为每个工作负载都提供强大的身份标识。可以大规模进行自动化密钥和证书轮换,伴随每个 Envoy 代理都运行着一个 istio-agent 负责证书和密钥的供应。下图显示了这个机制的运行流程。

译者注:这里用 istio-agent 来表述,是因为下图及对图的相关解读中反复用到了 “Istio agent” 这个术语,这样的描述更容易理解。 另外,在实现层面,istio-agent 是指 sidecar 容器中的 pilot-agent 进程,它有很多功能,这里不表,只特别提一下:它通过 Unix socket 的方式在本地提供 SDS 服务供 Envoy 使用,这个信息对了解 Envoy 与 SDS 之间的交互有意义。

身份供应

身份供应

Istio 供应身份是通过 secret discovery service(SDS)来实现的,具体流程如下:

  1. CA 提供 gRPC 服务以接受证书签名请求(CSRs)。
  2. Envoy 通过 Envoy 秘密发现服务(SDS)API 发送证书和密钥请求。
  3. 在收到 SDS 请求后,istio-agent 创建私钥和 CSR,然后将 CSR 及其凭据发送到 Istio CA 进行签名。
  4. CA 验证 CSR 中携带的凭据并签署 CSR 以生成证书。
  5. Istio-agent 通过 Envoy SDS API 将私钥和从 Istio CA 收到的证书发送给 Envoy。
  6. 上述 CSR 过程会周期性地重复,以处理证书和密钥轮换。

认证

Istio 提供两种类型的认证:

  • Peer authentication:用于服务到服务的认证,以验证进行连接的客户端。Istio 提供双向 TLS 作为传输认证的全栈解决方案,无需更改服务代码就可以启用它。这个解决方案:
    • 为每个服务提供强大的身份,表示其角色,以实现跨群集和云的互操作性。
    • 保护服务到服务的通信。
    • 提供密钥管理系统,以自动进行密钥和证书的生成,分发和轮换。
  • Request authentication:用于最终用户认证,以验证附加到请求的凭据。 Istio 使用 JSON Web Token(JWT)验证启用请求级认证,并使用自定义认证实现或任何 OpenID Connect 的认证实现(例如下面列举的)来简化的开发人员体验。

在所有情况下,Istio 都通过自定义 Kubernetes API 将认证策略存储在 Istio config store。Istiod 使每个代理保持最新状态,并在适当时提供密钥。此外,Istio 的认证机制支持宽容模式(permissive mode),以帮助您了解策略更改在实施之前如何影响您的安全状况。

双向 TLS 认证

Istio 通过客户端和服务器端 PEPs 建立服务到服务的通信通道,PEPs 被实现为Envoy 代理。当一个工作负载使用双向 TLS 认证向另一个工作负载发送请求时,该请求的处理方式如下:

  1. Istio 将出站流量从客户端重新路由到客户端的本地 sidecar Envoy。
  2. 客户端 Envoy 与服务器端 Envoy 开始双向 TLS 握手。在握手期间,客户端 Envoy 还做了安全命名检查,以验证服务器证书中显示的服务帐户是否被授权运行目标服务。
  3. 客户端 Envoy 和服务器端 Envoy 建立了一个双向的 TLS 连接,Istio 将流量从客户端 Envoy 转发到服务器端 Envoy。
  4. 授权后,服务器端 Envoy 通过本地 TCP 连接将流量转发到服务器服务。

宽容模式

Istio 双向 TLS 具有一个宽容模式(permissive mode),允许服务同时接受纯文本流量和双向 TLS 流量。这个功能极大的提升了双向 TLS 的入门体验。

在运维人员希望将服务移植到启用了双向 TLS 的 Istio 上时,许多非 Istio 客户端和非 Istio 服务端通信时会产生问题。通常情况下,运维人员无法同时为所有客户端安装 Istio sidecar,甚至没有这样做的权限。即使在服务端上安装了 Istio sidecar,运维人员也无法在不中断现有连接的情况下启用双向 TLS。

启用宽容模式后,服务可以同时接受纯文本和双向 TLS 流量。这个模式为入门提供了极大的灵活性。服务中安装的 Istio sidecar 立即接受双向 TLS 流量而不会打断现有的纯文本流量。因此,运维人员可以逐步安装和配置客户端 Istio sidecar 发送双向 TLS 流量。一旦客户端配置完成,运维人员便可以将服务端配置为仅 TLS 模式。更多信息请访问双向 TLS 迁移向导

安全命名

服务器身份(Server identities)被编码在证书里,但服务名称(service names)通过服务发现或 DNS 被检索。安全命名信息将服务器身份映射到服务名称。身份 A 到服务名称 B 的映射表示“授权 A 运行服务 B“。控制平面监视 apiserver,生成安全命名映射,并将其安全地分发到 PEPs。 以下示例说明了为什么安全命名对身份验证至关重要。

假设运行服务 datastore 的合法服务器仅使用 infra-team 身份。恶意用户拥有 test-team 身份的证书和密钥。恶意用户打算模拟服务以检查从客户端发送的数据。恶意用户使用证书和 test-team 身份的密钥部署伪造服务器。假设恶意用户成功攻击了发现服务或 DNS,以将 datastore 服务名称映射到伪造服务器。

当客户端调用 datastore 服务时,它从服务器的证书中提取 test-team 身份,并用安全命名信息检查 test-team 是否被允许运行 datastore。客户端检测到 test-team 不允许运行 datastore 服务,认证失败。

安全命名能够防止 HTTPS 流量受到一般性网络劫持,除了 DNS 欺骗外,它还可以保护 TCP 流量免受一般网络劫持。如果攻击者劫持了 DNS 并修改了目的地的 IP 地址,它将无法用于 TCP 通信。这是因为 TCP 流量不包含主机名信息,我们只能依靠 IP 地址进行路由,而且甚至在客户端 Envoy 收到流量之前,也可能发生 DNS 劫持。

认证架构

您可以使用 peer 和 request 认证策略为在 Istio 网格中接收请求的工作负载指定认证要求。网格运维人员使用 .yaml 文件来指定策略。部署后,策略将保存在 Istio 配置存储中。Istio 控制器监视配置存储。

一有任何的策略变更,新策略都会转换为适当的配置,告知 PEP 如何执行所需的认证机制。控制平面可以获取公共密钥,并将其附加到配置中以进行 JWT 验证。或者,Istiod 提供了 Istio 系统管理的密钥和证书的路径,并将它们安装到应用程序 pod 用于双向 TLS。您可以在 PKI 部分中找到更多信息。

Istio 异步发送配置到目标端点。代理收到配置后,新的认证要求会立即生效。

发送请求的客户端服务负责遵循必要的认证机制。对于 peer authentication,应用程序负责获取 JWT 凭证并将其附加到请求。对于双向 TLS,Istio 会自动将两个 PEPs 之间的所有流量升级为双向 TLS。如果认证策略禁用了双向 TLS 模式,则 Istio 将继续在 PEPs 之间使用纯文本。要覆盖此行为,请使用 destination rules显式禁用双向 TLS 模式。您可以在双向 TLS 认证 中找到有关双向 TLS 如何工作的更多信息。

认证架构

认证架构

Istio 将两种类型的身份验证以及凭证中的其他声明(如果适用)输出到下一层:授权

认证策略

本节中提供了更多 Istio 认证策略方面的细节。正如认证架构中所说的,认证策略是对服务收到的请求生效的。要在双向 TLS 中指定客户端认证策略,需要在 DetinationRule 中设置 TLSSettingsTLS 设置参考文档中有更多这方面的信息。

和其他的 Istio 配置一样,可以用 .yaml 文件的形式来编写认证策略。部署策略使用 kubectl。 下面例子中的认证策略要求:与带有 app:reviews 标签的工作负载的传输层认证,必须使用双向 TLS:

apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "example-peer-policy"
  namespace: "foo"
spec:
  selector:
    matchLabels:
      app: reviews
  mtls:
    mode: STRICT

策略存储

Istio 将网格范围的策略存储在根命名空间。这些策略使用一个空的 selector 适用于网格中的所有工作负载。具有名称空间范围的策略存储在相应的名称空间中。它们仅适用于其命名空间内的工作负载。如果你配置了 selector 字段,则认证策略仅适用于与您配置的条件匹配的工作负载。

Peer 和 request 认证策略用 kind 字段区分,分别是 PeerAuthenticationRequestAuthentication

Selector 字段

Peer 和 request 认证策略使用 selector 字段来指定该策略适用的工作负载的标签。以下示例显示适用于带有 app:product-page 标签的工作负载的策略的 selector 字段:

selector:
  matchLabels:
    app: product-page

如果您没有为 selector 字段提供值,则 Istio 会将策略与策略存储范围内的所有工作负载进行匹配。因此,selector 字段可帮助您指定策略的范围:

  • 网格范围策略:为根名称空间指定的策略,不带或带有空的 selector 字段。
  • 命名空间范围的策略:为非root命名空间指定的策略,不带有或带有空的 selector 字段。
  • 特定于工作负载的策略:在常规名称空间中定义的策略,带有非空 selector 字段。

Peer 和 request 认证策略对 selector 字段遵循相同的层次结构原则,但是 Istio 以略有不同的方式组合和应用它们。

只能有一个网格范围的 Peer 认证策略,每个命名空间也只能有一个命名空间范围的 Peer 认证策略。当您为同一网格或命名空间配置多个网格范围或命名空间范围的 Peer 认证策略时,Istio 会忽略较新的策略。当多个特定于工作负载的 Peer 认证策略匹配时,Istio 将选择最旧的策略。

Istio 按照以下顺序为每个工作负载应用最窄的匹配策略:

  1. 特定于工作负载的
  2. 命名空间范围
  3. 网格范围

Istio 可以将所有匹配的 request 认证策略组合起来,就像它们来自单个 request 认证策略一样。因此,您可以在网格或名称空间中配置多个网格范围或命名空间范围的策略。但是,避免使用多个网格范围或命名空间范围的 request 认证策略仍然是一个好的实践。

Peer authentication

Peer 认证策略指定 Istio 对目标工作负载实施的双向 TLS 模式。支持以下模式:

  • PERMISSIVE:工作负载接受双向 TLS 和纯文本流量。此模式在迁移因为没有 sidecar 而无法使用双向 TLS 的工作负载的过程中非常有用。一旦工作负载完成 sidecar 注入的迁移,应将模式切换为 STRICT。
  • STRICT: 工作负载仅接收双向 TLS 流量。
  • DISABLE:禁用双向 TLS。 从安全角度来看,除非您提供自己的安全解决方案,否则请勿使用此模式。

如果未设置模式,将继承父作用域的模式。未设置模式的网格范围的 peer 认证策略默认使用 PERMISSIVE 模式。

下面的 peer 认证策略要求命名空间 foo 中的所有工作负载都使用双向 TLS:

apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "example-policy"
  namespace: "foo"
spec:
  mtls:
    mode: STRICT

对于特定于工作负载的 peer 认证策略,可以为不同的端口指定不同的双向 TLS 模式。您只能将工作负载声明过的端口用于端口范围的双向 TLS 配置。以下示例为 app:example-app 工作负载禁用了端口80上的双向TLS,并对所有其他端口使用名称空间范围的 peer 认证策略的双向 TLS 设置:

apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "example-workload-policy"
  namespace: "foo"
spec:
  selector:
     matchLabels:
       app: example-app
  portLevelMtls:
    80:
      mode: DISABLE

上面的 peer 认证策略仅在有如下 Service 定义时工作,将流向 example-service 服务的请求绑定到 example-app 工作负载的 80 端口

apiVersion: v1
kind: Service
metadata:
  name: example-service
  namespace: foo
spec:
  ports:
  - name: http
    port: 8000
    protocol: TCP
    targetPort: 80
  selector:
    app: example-app

Request authentication

Request 认证策略指定验证 JSON Web Token(JWT)所需的值。 这些值包括:

  • token 在请求中的位置
  • 请求的 issuer
  • 公共 JSON Web Key Set(JWKS)

Istio 会根据 request 认证策略中的规则检查提供的令牌(如果已提供),并拒绝令牌无效的请求。当请求不带有令牌时,默认情况下将接受它们。要拒绝没有令牌的请求,请提供授权规则,该规则指定对特定操作(例如,路径或操作)的限制。

如果 Request 认证策略使用唯一的位置,则它们可以指定多个JWT。当多个策略与工作负载匹配时,Istio 会将所有规则组合起来,就好像它们被指定为单个策略一样。此行为对于开发接受来自不同 JWT 提供者的工作负载时很有用。但是,不支持具有多个有效 JWT 的请求,因为此类请求的输出主体未定义。

Principals

使用 peer 认证策略和双向 TLS 时,Istio 将身份从 peer 认证提取到 source.principal 中。同样,当您使用 request 认证策略时,Istio 会将 JWT 中的身份赋值给 request.auth.principal。使用这些 principals 设置授权策略和作为遥测的输出。

更新认证策略

您可以随时更改认证策略,Istio 几乎实时将新策略推送到工作负载。但是,Istio 无法保证所有工作负载都同时收到新政策。以下建议有助于避免在更新认证策略时造成干扰:

  • 将 peer 认证策略的模式从 DISABLE 更改为 STRICT 时,请使用 PERMISSIVE 模式来过渡,反之亦然。当所有工作负载成功切换到所需模式时,您可以将策略应用于最终模式。您可以使用 Istio 遥测技术来验证工作负载已成功切换。
  • 将 request 认证策略从一个 JWT 迁移到另一个 JWT 时,将新 JWT 的规则添加到该策略中,而不删除旧规则。这样,工作负载接受两种类型的 JWT,当所有流量都切换到新的 JWT 时,您可以删除旧规则。但是,每个 JWT 必须使用不同的位置。

授权

Istio 的授权功能为网格中的工作负载提供网格、命名空间和工作负载级别的访问控制。这种控制层级提供了以下优点:

  • 工作负载间和最终用户到工作负载的授权。
  • 一个简单的 API:它包括一个单独的并且很容易使用和维护的 AuthorizationPolicy CRD
  • 灵活的语义:运维人员可以在 Istio 属性上定义自定义条件,并使用 DENY 和 ALLOW 动作。
  • 高性能:Istio 授权是在 Envoy 本地强制执行的。
  • 高兼容性:原生支持 HTTP、HTTPS 和 HTTP2,以及任意普通 TCP 协议。

授权架构

每个 Envoy 代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果 ALLOWDENY。 运维人员使用 .yaml 文件指定 Istio 授权策略。

授权架构

授权架构

隐式启用

您无需显式启用 Istio 的授权功能。只需将授权策略应用于工作负载即可实施访问控制。对于未应用授权策略的工作负载,Istio 不会执行访问控制,放行所有请求。

授权策略支持 ALLOWDENY 动作。 拒绝策略优先于允许策略。如果将任何允许策略应用于工作负载,则默认情况下将拒绝对该工作负载的访问,除非策略中的规则明确允许。当您将多个授权策略应用于相同的工作负载时,Istio 会累加地应用它们。

授权策略

要配置授权策略,请创建一个 AuthorizationPolicy 自定义资源。 一个授权策略包括选择器(selector),动作(action) 和一个规则(rules)列表:

  • selector 字段指定策略的目标

  • action 字段指定允许还是拒绝请求

  • rules
    

    指定何时触发动作

    • rules 下的 from 字段指定请求的来源
    • rules 下的 to 字段指定请求的操作
    • rules 下的 when 字段指定应用规则所需的条件

以下示例显示了一个授权策略,该策略允许两个源(服务帐号 cluster.local/ns/default/sa/sleep 和命名空间 dev),在使用有效的 JWT 令牌发送请求时,可以访问命名空间 foo 中的带有标签 app: httpbinversion: v1 的工作负载。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: ALLOW
 rules:
 - from:
   - source:
       principals: ["cluster.local/ns/default/sa/sleep"]
   - source:
       namespaces: ["dev"]
   to:
   - operation:
       methods: ["GET"]
   when:
   - key: request.auth.claims[iss]
     values: ["https://accounts.google.com"]

下例显示了一个授权策略,如果请求来源不是命名空间 foo,请求将被拒绝。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       notNamespaces: ["foo"]

拒绝策略优先于允许策略。如果请求同时匹配上允许策略和拒绝策略,请求将被拒绝。Istio 首先评估拒绝策略,以确保允许策略不能绕过拒绝策略

策略目标

您可以通过 metadata/namespace 字段和可选的 selector 字段来指定策略的范围或目标。metadata/namespace 告诉该策略适用于哪个命名空间。如果将其值设置为根名称空间,则该策略将应用于网格中的所有名称空间。根命名空间的值是可配置的,默认值为 istio-system。如果设置为任何其他名称空间,则该策略仅适用于指定的名称空间。

您可以使用 selector 字段来进一步限制策略以应用于特定工作负载。selector 使用标签选择目标工作负载。slector 包含 {key: value}对的列表,其中 key 是标签的名称。如果未设置,则授权策略将应用于与授权策略相同的命名空间中的所有工作负载。

以下示例策略 allow-read 允许对 default 命名空间中带有标签 app: products 的工作负载的 "GET""HEAD" 访问。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-read
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
         methods: ["GET", "HEAD"]

值匹配

授权策略中的大多数字段都支持以下所有匹配模式:

  • 完全匹配:即完整的字符串匹配。
  • 前缀匹配:"*" 结尾的字符串。例如,"test.abc.*" 匹配 "test.abc.com""test.abc.com.cn""test.abc.org" 等等。
  • 后缀匹配:"*" 开头的字符串。例如,"*.abc.com" 匹配 "eng.abc.com""test.eng.abc.com" 等等。
  • 存在匹配:* 用于指定非空的任意内容。您可以使用格式 fieldname: ["*"] 指定必须存在的字段。这意味着该字段可以匹配任意内容,但是不能为空。请注意这与不指定字段不同,后者意味着包括空的任意内容。

有一些例外。 例如,以下字段仅支持完全匹配:

  • when 部分下的 key 字段
  • source 部分下 的 ipBlocks
  • to 部分下的 ports 字段

以下示例策略允许访问前缀为 /test/* 或后缀为 */info 的路径。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tester
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        paths: ["/test/*", "*/info"]

排除匹配

为了匹配诸如 when 字段中的 notValuessource 字段中的 notIpBlocksto 字段中的 notPorts 之类的否定条件,Istio 支持排除匹配。

以下示例:如果请求路径不是 /healthz,则要求从请求的 JWT 认证中导出的主体是有效的。 因此,该策略从 JWT 身份验证中排除对 /healthz 路径的请求:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: disable-jwt-for-healthz
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        notPaths: ["/healthz"]
    from:
    - source:
        requestPrincipals: ["*"]

下面的示例拒绝到 /admin 路径且不带请求主体的请求:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: enable-jwt-for-admin
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: DENY
  rules:
  - to:
    - operation:
        paths: ["/admin"]
    from:
    - source:
        notRequestPrincipals: ["*"]

全部允许和默认全部拒绝授权策略

以下示例显示了一个简单的 allow-all 授权策略,该策略允许完全访问 default 命名空间中的所有工作负载。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all
  namespace: default
spec:
  action: ALLOW
  rules:
  - {}

以下示例显示了一个策略,该策略不允许任何对 admin 命名空间工作负载的访问。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: admin
spec:
  {}

自定义条件

您还可以使用 when 部分指定其他条件。 例如,下面的 AuthorizationPolicy 定义包括以下条件:request.headers [version]v1v2。 在这种情况下,key 是 request.headers [version],它是 Istio 属性 request.headers(是个字典)中的一项。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: ALLOW
 rules:
 - from:
   - source:
       principals: ["cluster.local/ns/default/sa/sleep"]
   to:
   - operation:
       methods: ["GET"]
   when:
   - key: request.headers[version]
     values: ["v1", "v2"]

条件页面中列出了支持的条件 key 值。

认证与未认证身份

如果要使工作负载可公开访问,则需要将 source 部分留空。这允许来自所有(经过认证和未经认证)的用户和工作负载的源,例如:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: ALLOW
 rules:
 - to:
   - operation:
       methods: ["GET", "POST"]

要仅允许经过认证的用户,请将 principal 设置为 "*",例如:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: ALLOW
 rules:
 - from:
   - source:
       principals: ["*"]
   to:
   - operation:
       methods: ["GET", "POST"]

在普通 TCP 协议上使用 Istio 授权

Istio 授权支持工作负载使用任意普通 TCP 协议,如 MongoDB。 在这种情况下,您可以按照与 HTTP 工作负载相同的方式配置授权策略。 不同之处在于某些字段和条件仅适用于 HTTP 工作负载。 这些字段包括:

  • 授权策略对象 source 部分中的 request_principals 字段
  • 授权策略对象 operation 部分中的 hostsmethodspaths 字段

条件页面中列出了支持的条件。

如果您在授权策略中对 TCP 工作负载使用了任何只适用于 HTTP 的字段,Istio 将会忽略它们。

假设您在端口 27017 上有一个 MongoDB 服务,下例配置了一个授权策略,只允许 Istio 网格中的 bookinfo-ratings-v2 服务访问该 MongoDB 工作负载。

apiVersion: "security.istio.io/v1beta1"
kind: AuthorizationPolicy
metadata:
  name: mongodb-policy
  namespace: default
spec:
 selector:
   matchLabels:
     app: mongodb
 action: ALLOW
 rules:
 - from:
   - source:
       principals: ["cluster.local/ns/default/sa/bookinfo-ratings-v2"]
   to:
   - operation:
       ports: ["27017"]

对双向 TLS 的依赖

Istio 使用双向 TLS 将某些信息从客户端安全地传递到服务器。在使用授权策略中的以下任何字段之前,必须先启用双向 TLS:

  • source 部分下的 principals 字段
  • source 部分下的 namespaces 字段
  • source.principal 自定义条件
  • source.namespace 自定义条件
  • connection.sni 自定义条件

如果您不使用授权策略中的上述任何字段,则双向 TLS 不是必须的。

8 可靠

Istio 为网格内所有的服务通信生成详细的遥测数据。这种遥测技术提供了服务行为的可观察性,使运维人员能够排查故障、维护和优化应用程序,而不会给服务的开发人员带来任何额外的负担。通过 Istio,运维人员可以全面了解到受监控的服务如何与其他服务以及 Istio 组件进行交互。

Istio 生成以下类型的遥测数据,以提供对整个服务网格的可观察性:

  • 指标。Istio 基于 4 个监控的黄金标识(延迟、流量、错误、饱和)生成了一系列服务指标。Istio 还为网格控制平面提供了更详细的指标。除此以外还提供了一组默认的基于这些指标的网格监控仪表板。
  • 分布式追踪。Istio 为每个服务生成分布式追踪 span,运维人员可以理解网格内服务的依赖和调用流程。
  • 访问日志。当流量流入网格中的服务时,Istio 可以生成每个请求的完整记录,包括源和目标的元数据。此信息使运维人员能够将服务行为的审查控制到单个工作负载实例的级别。

指标

指标(Metric)提供了一种以聚合的方式监控和理解行为的方法。

为了监控服务行为,Istio 为服务网格中所有出入的服务流量都生成了指标。这些指标提供了关于行为的信息,例如总流量数、错误率和请求响应时间。

除了监控网格中服务的行为外,监控网格本身的行为也很重要。Istio 组件可以导出自身内部行为的指标,以提供对网格控制平面的功能和健康情况的洞察能力。

Istio 指标收集由运维人员配置来驱动。运维人员决定如何以及何时收集指标,以及指标本身的详细程度。这使得它能够灵活地调整指标收集来满足个性化需求。

代理级别指标

Istio 指标收集从 sidecar 代理(Envoy)开始。每个代理为通过它的所有流量(入站和出站)生成一组丰富的指标。代理还提供关于它本身管理功能的详细统计信息,包括配置信息和健康信息。

Envoy 生成的指标提供了资源(例如监听器和集群)粒度上的网格监控。因此,为了监控 Envoy 指标,需要了解网格服务和 Envoy 资源之间的连接。

Istio 允许运维人员在每个工作负载实例上选择生成和收集哪个 Envoy 指标。默认情况下,Istio 只支持 Envoy 生成的统计数据的一小部分,以避免依赖过多的后端服务,还可以减少与指标收集相关的 CPU 开销。然而,运维人员可以在需要时轻松地扩展收集到的代理指标集。这支持有针对性地调试网络行为,同时降低了跨网格监控的总体成本。

Envoy 文档包括了 Envoy 统计信息收集的详细说明。Envoy 统计里的操作手册提供了有关控制代理级别指标生成的更多信息。

代理级别指标的例子:

envoy_cluster_internal_upstream_rq{response_code_class="2xx",cluster_name="xds-grpc"} 7163

envoy_cluster_upstream_rq_completed{cluster_name="xds-grpc"} 7164

envoy_cluster_ssl_connection_error{cluster_name="xds-grpc"} 0

envoy_cluster_lb_subsets_removed{cluster_name="xds-grpc"} 0

envoy_cluster_internal_upstream_rq{response_code="503",cluster_name="xds-grpc"} 1

服务级别指标

除了代理级别指标之外,Istio 还提供了一组用于监控服务通信的面向服务的指标。这些指标涵盖了四个基本的服务监控需求:延迟、流量、错误和饱和情况。Istio 带有一组默认的仪表板,用于监控基于这些指标的服务行为。

默认的 Istio 指标由 Istio 提供的配置集定义并默认导出到 Prometheus。运维人员可以自由地修改这些指标的形态和内容,更改它们的收集机制,以满足各自的监控需求。

收集指标任务为定制 Istio 指标生成提供了更详细的信息。

服务级别指标的使用完全是可选的。运维人员可以选择关闭指标的生成和收集来满足自身需要。

服务级别指标的例子:

istio_requests_total{
  connection_security_policy="mutual_tls",
  destination_app="details",
  destination_principal="cluster.local/ns/default/sa/default",
  destination_service="details.default.svc.cluster.local",
  destination_service_name="details",
  destination_service_namespace="default",
  destination_version="v1",
  destination_workload="details-v1",
  destination_workload_namespace="default",
  reporter="destination",
  request_protocol="http",
  response_code="200",
  response_flags="-",
  source_app="productpage",
  source_principal="cluster.local/ns/default/sa/default",
  source_version="v1",
  source_workload="productpage-v1",
  source_workload_namespace="default"
} 214

控制平面指标

每一个 Istio 的组件(Pilot、Galley、Mixer)都提供了对自身监控指标的集合。这些指标容许监控 Istio 自己的行为(这与网格内的服务有所不同)。

有关这些被维护指标的更多信息,请查看每个组件的参考文档:

分布式追踪

分布式追踪通过监控流经网格的单个请求,提供了一种监控和理解行为的方法。追踪使网格的运维人员能够理解服务的依赖关系以及在服务网格中的延迟源。

Istio 支持通过 Envoy 代理进行分布式追踪。代理自动为其应用程序生成追踪 span,只需要应用程序转发适当的请求上下文即可。

Istio 支持很多追踪系统,包括 ZipkinJaegerLightStepDatadog。运维人员控制生成追踪的采样率(每个请求生成跟踪数据的速率)。这允许运维人员控制网格生成追踪数据的数量和速率。

更多关于 Istio 分布式追踪的信息可以在分布式追踪 FAQ 中找到。

Istio 为一个请求生成的分布式追踪数据:
image.png

Distributed Trace for a single request

访问日志

访问日志提供了一种从单个工作负载实例的角度监控和理解行为的方法。

Istio 可以以一组可配置的格式集生成服务流量的访问日志,为运维人员提供日志记录的方式、内容、时间和位置的完全控制。Istio 向访问日志机制暴露了完整的源和目标元数据,允许对网络通信进行详细的审查。

访问日志可以在本地生成,或者导出到自定义的后端基础设施,包括 Fluentd

更多关于访问日志的内容在收集日志获取 Envoy 服务日志任务中提供。

Istio 访问日志例子(JSON 格式):

{"level":"info","time":"2019-06-11T20:57:35.424310Z","instance":"accesslog.instance.istio-control","connection_security_policy":"mutual_tls","destinationApp":"productpage","destinationIp":"10.44.2.15","destinationName":"productpage-v1-6db7564db8-pvsnd","destinationNamespace":"default","destinationOwner":"kubernetes://apis/apps/v1/namespaces/default/deployments/productpage-v1","destinationPrincipal":"cluster.local/ns/default/sa/default","destinationServiceHost":"productpage.default.svc.cluster.local","destinationWorkload":"productpage-v1","httpAuthority":"35.202.6.119","latency":"35.076236ms","method":"GET","protocol":"http","receivedBytes":917,"referer":"","reporter":"destination","requestId":"e3f7cffb-5642-434d-ae75-233a05b06158","requestSize":0,"requestedServerName":"outbound_.9080_._.productpage.default.svc.cluster.local","responseCode":200,"responseFlags":"-","responseSize":4183,"responseTimestamp":"2019-06-11T20:57:35.459150Z","sentBytes":4328,"sourceApp":"istio-ingressgateway","sourceIp":"10.44.0.8","sourceName":"ingressgateway-7748774cbf-bvf4j","sourceNamespace":"istio-control","sourceOwner":"kubernetes://apis/apps/v1/namespaces/istio-control/deployments/ingressgateway","sourcePrincipal":"cluster.local/ns/istio-control/sa/default","sourceWorkload":"ingressgateway","url":"/productpage","userAgent":"curl/7.54.0","xForwardedFor":"10.128.0.35"}

博文源站:https://istio.io/zh/docs/concepts