用户您好!请先登录!

Istio 基础知识

Istio 基础知识

一、Istio概念

使用云平台可以为组织提供丰富的好处。然而,不可否认的是,采用云可能会给 DevOps 团队带来压力。开发人员必须使用微服务以满足应用的可移植性,同时运营商管理了极其庞大的混合和多云部署。Istio 允许您连接、保护、控制和观测服务。

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

什么是服务网格?

在从单体应用程序向分布式微服务架构的转型过程中,开发人员和运维人员面临诸多挑战,使用 Istio 可以解决这些问题。

服务网格(Service Mesh)这个术语通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。随着规模和复杂性的增长,服务网格越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、指标收集和监控以及通常更加复杂的运维需求,例如 A/B 测试、金丝雀发布、限流、访问控制和端到端认证等。

Istio 提供了一个完整的解决方案,通过为整个服务网格提供行为洞察和操作控制来满足微服务应用程序的多样化需求。

为什么要使用 Istio?

Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,只需要对服务的代码进行一点或不需要做任何改动。想要让服务支持 Istio,只需要在您的环境中部署一个特殊的 sidecar 代理,使用 Istio 控制平面功能配置和管理代理,拦截微服务之间的所有网络通信:

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

Istio 旨在实现可扩展性,满足各种部署需求。

核心功能

Istio 在服务网络中统一提供了许多关键功能:

流量管理

通过简单的规则配置和流量路由,您可以控制服务之间的流量和 API 调用。Istio 简化了断路器、超时和重试等服务级别属性的配置,并且可以轻松设置 A/B测试、金丝雀部署和基于百分比的流量分割的分阶段部署等重要任务。

通过更好地了解您的流量和开箱即用的故障恢复功能,您可以在问题出现之前先发现问题,使调用更可靠,并且使您的网络更加强大——无论您面临什么条件。

安全

Istio 的安全功能使开发人员可以专注于应用程序级别的安全性。Istio 提供底层安全通信信道,并大规模管理服务通信的认证、授权和加密。使用Istio,服务通信在默认情况下是安全的,它允许您跨多种协议和运行时一致地实施策略——所有这些都很少或根本不需要应用程序更改。

虽然 Istio 与平台无关,但将其与 Kubernetes(或基础架构)网络策略结合使用,其优势会更大,包括在网络和应用层保护 pod 间或服务间通信的能力。

可观察性

Istio 强大的追踪、监控和日志记录可让您深入了解服务网格部署。通过 Istio 的监控功能,可以真正了解服务性能如何影响上游和下游的功能,而其自定义仪表板可以提供对所有服务性能的可视性,并让您了解该性能如何影响您的其他进程。

Istio 的 Mixer 组件负责策略控制和遥测收集。它提供后端抽象和中介,将 Istio 的其余部分与各个基础架构后端的实现细节隔离开来,并为运维提供对网格和基础架构后端之间所有交互的细粒度控制。

所有这些功能可以让您可以更有效地设置、监控和实施服务上的 SLO。当然,最重要的是,您可以快速有效地检测和修复问题。

平台支持

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

  • 在 Kubernetes 上部署的服务
  • 使用 Consul 注册的服务
  • 在虚拟机上部署的服务
集成和定制

策略执行组件可以扩展和定制,以便与现有的 ACL、日志、监控、配额、审计等方案集成。

架构

Istio 服务网格逻辑上分为数据平面控制平面

  • 数据平面由一组以 sidecar 方式部署的智能代理(Envoy)组成。这些代理可以调节和控制微服务及 Mixer 之间所有的网络通信。
  • 控制平面负责管理和配置代理来路由流量。此外控制平面配置 Mixer 以实施策略和收集遥测数据。

下图显示了构成每个面板的不同组件:

基于 Istio 的应用程序架构概览
Istio 架构
Envoy

Istio 使用 Envoy 代理的扩展版本,Envoy 是以 C++ 开发的高性能代理,用于调解服务网格中所有服务的所有入站和出站流量。Envoy 的许多内置功能被 Istio 发扬光大,例如:

  • 动态服务发现
  • 负载均衡
  • TLS 终止
  • HTTP/2 & gRPC 代理
  • 熔断器
  • 健康检查、基于百分比流量拆分的灰度发布
  • 故障注入
  • 丰富的度量指标

Envoy 被部署为 sidecar,和对应服务在同一个 Kubernetes pod 中。这允许 Istio 将大量关于流量行为的信号作为属性提取出来,而这些属性又可以在 Mixer 中用于执行策略决策,并发送给监控系统,以提供整个网格行为的信息。

Sidecar 代理模型还可以将 Istio 的功能添加到现有部署中,而无需重新构建或重写代码。可以阅读更多来了解为什么我们在设计目标中选择这种方式。

Mixer

Mixer 是一个独立于平台的组件,负责在服务网格上执行访问控制和使用策略,并从 Envoy 代理和其他服务收集遥测数据。代理提取请求级属性,发送到 Mixer 进行评估。有关属性提取和策略评估的更多信息,请参见 Mixer 配置

Mixer 中包括一个灵活的插件模型,使其能够接入到各种主机环境和基础设施后端,从这些细节中抽象出 Envoy 代理和 Istio 管理的服务。

Pilot

Pilot 为 Envoy sidecar 提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能。它将控制流量行为的高级路由规则转换为特定于 Envoy 的配置,并在运行时将它们传播到 sidecar。

Pilot 将平台特定的服务发现机制抽象化并将其合成为符合 Envoy 数据平面 API 的任何 sidecar 都可以使用的标准格式。这种松散耦合使得 Istio 能够在多种环境下运行(例如,Kubernetes、Consul、Nomad),同时保持用于流量管理的相同操作界面。

Citadel

Citadel 通过内置身份和凭证管理赋能强大的服务间和最终用户身份验证。可用于升级服务网格中未加密的流量,并为运维人员提供基于服务标识而不是网络控制的强制执行策略的能力。从 0.5 版本开始,Istio 支持基于角色的访问控制,以控制谁可以访问您的服务,而不是基于不稳定的三层或四层网络标识。

Galley

Galley 代表其他的 Istio 控制平面组件,用来验证用户编写的 Istio API 配置。随着时间的推移,Galley 将接管 Istio 获取配置、 处理和分配组件的顶级责任。它将负责将其他的 Istio 组件与从底层平台(例如 Kubernetes)获取用户配置的细节中隔离开来。

设计目标

Istio 的架构设计中有几个关键目标,这些目标对于使系统能够应对大规模流量和高性能地服务处理至关重要。

  • 最大化透明度:若想 Istio 被采纳,应该让运维和开发人员只需付出很少的代价就可以从中受益。为此,Istio 将自身自动注入到服务间所有的网络路径中。Istio 使用 sidecar 代理来捕获流量,并且在尽可能的地方自动编程网络层,以路由流量通过这些代理,而无需对已部署的应用程序代码进行任何改动。在 Kubernetes中,代理被注入到 pod 中,通过编写 iptables 规则来捕获流量。注入 sidecar 代理到 pod 中并且修改路由规则后,Istio 就能够调解所有流量。这个原则也适用于性能。当将 Istio 应用于部署时,运维人员可以发现,为提供这些功能而增加的资源开销是很小的。所有组件和 API 在设计时都必须考虑性能和规模。
  • 可扩展性:随着运维人员和开发人员越来越依赖 Istio 提供的功能,系统必然和他们的需求一起成长。虽然我们期望继续自己添加新功能,但是我们预计最大的需求是扩展策略系统,集成其他策略和控制来源,并将网格行为信号传播到其他系统进行分析。策略运行时支持标准扩展机制以便插入到其他服务中。此外,它允许扩展词汇表,以允许基于网格生成的新信号来执行策略。
  • 可移植性:使用 Istio 的生态系统将在很多维度上有差异。Istio 必须能够以最少的代价运行在任何云或预置环境中。将基于 Istio 的服务移植到新环境应该是轻而易举的,而使用 Istio 将一个服务同时部署到多个环境中也是可行的(例如,在多个云上进行冗余部署)。
  • 策略一致性:在服务间的 API 调用中,策略的应用使得可以对网格间行为进行全面的控制,但对于无需在 API 级别表达的资源来说,对资源应用策略也同样重要。例如,将配额应用到 ML 训练任务消耗的 CPU 数量上,比将配额应用到启动这个工作的调用上更为有用。因此,策略系统作为独特的服务来维护,具有自己的 API,而不是将其放到代理/sidecar 中,这容许服务根据需要直接与其集成。

二、流量管理

使用 Istio 的流量管理模型,本质上是将流量与基础设施扩容解耦,让运维人员可以通过 Pilot 指定流量遵循什么规则,而不是指定哪些 pod/VM 应该接收流量——Pilot 和智能 Envoy 代理会帮我们搞定。因此,例如,您可以通过 Pilot 指定特定服务的 5% 流量可以转到金丝雀版本,而不必考虑金丝雀部署的大小,或根据请求的内容将流量发送到特定版本。

Istio 流量管理
Istio 流量管理

将流量从基础设施扩展中解耦,这样就可以让 Istio 提供各种独立于应用程序代码之外的流量管理功能。 除了 A/B 测试的动态请求路由,逐步推出和金丝雀发布之外, 它还使用超时、重试和熔断器来处理故障恢复, 最后还可以通过故障注入来测试服务之间故障恢复策略的兼容性。 这些功能都是通过在服务网格中部署的 Envoy sidecar/代理来实现的。

Pilot 和 Envoy

Istio 流量管理的核心组件是 Pilot,它管理和配置部署在特定 Istio 服务网格中的所有 Envoy 代理实例。它允许您指定在 Envoy 代理之间使用什么样的路由流量规则,并配置故障恢复功能,如超时、重试和熔断器。它还维护了网格中所有服务的规范模型,并使用这个模型通过发现服务让 Envoy 了解网格中的其他实例。

每个 Envoy 实例都会维护负载均衡信息信息,这些信息来自 Pilot 以及对负载均衡池中其他实例的定期健康检查。从而允许其在目标实例之间智能分配流量,同时遵循其指定的路由规则。

Pilot 负责管理通过 Istio 服务网格发布的 Envoy 实例的生命周期。

Pilot 架构
Pilot 架构

如上图所示,在网格中 Pilot 维护了一个服务的规则表示并独立于底层平台。Pilot中的特定于平台的适配器负责适当地填充这个规范模型。例如,在 Pilot 中的 Kubernetes 适配器实现了必要的控制器,来观察 Kubernetes API 服务器,用于更改 pod 的注册信息、入口资源以及存储流量管理规则的第三方资源。这些数据被转换为规范表示。然后根据规范表示生成特定的 Envoy 的配置。

Pilot 公开了用于服务发现 、负载均衡池和路由表的动态更新的 API。

运维人员可以通过 Pilot 的 Rules API 指定高级流量管理规则。这些规则被翻译成低级配置,并通过 discovery API 分发到 Envoy 实例。

请求路由

如 Pilot 所述,特定网格中服务的规范表示由 Pilot 维护。服务的 Istio 模型和在底层平台(Kubernetes、Mesos 以及 Cloud Foundry 等)中的表达无关。特定平台的适配器负责从各自平台中获取元数据的各种字段,然后对服务模型进行填充。

Istio 引入了服务版本的概念,可以通过版本(v1v2)或环境(stagingprod)对服务进行进一步的细分。这些版本不一定是不同的 API 版本:它们可能是部署在不同环境(prod、staging 或者 dev 等)中的同一服务的不同迭代。使用这种方式的常见场景包括 A/B 测试或金丝雀部署。Istio 的流量路由规则可以根据服务版本来对服务之间流量进行附加控制。

服务之间的通讯

服务版本的处理。
服务版本

如上图所示,服务的客户端不知道服务不同版本间的差异。它们可以使用服务的主机名或者 IP 地址继续访问服务。Envoy sidecar/代理拦截并转发客户端和服务器之间的所有请求和响应。

运维人员使用 Pilot 指定路由规则,Envoy 根据这些规则动态地确定其服务版本的实际选择。该模型使应用程序代码能够将它从其依赖服务的演进中解耦出来,同时提供其他好处(参见 Mixer)。路由规则让 Envoy 能够根据诸如 header、与源/目的地相关联的标签和/或分配给每个版本的权重等标准来进行版本选择。

Istio 还为同一服务版本的多个实例提供流量负载均衡。可以在服务发现和负载均衡中找到更多信息。

Istio 不提供 DNS。应用程序可以尝试使用底层平台(kube-dnsmesos-dns 等)中存在的 DNS 服务来解析 FQDN。

Ingress 和 Egress

Istio 假定进入和离开服务网络的所有流量都会通过 Envoy 代理进行传输。通过将 Envoy 代理部署在服务之前,运维人员可以针对面向用户的服务进行 A/B 测试、部署金丝雀服务等。类似地,通过使用 Envoy 将流量路由到外部 Web 服务(例如,访问 Maps API 或视频服务 API)的方式,运维人员可以为这些服务添加超时控制、重试、断路器等功能,同时还能从服务连接中获取各种细节指标。

通过 Envoy 的 Ingress 和 Egress。
请求流

服务发现和负载均衡

Istio 负载均衡服务网格中实例之间的通信。

Istio 假定存在服务注册表,以追踪应用程序中服务的 pod/VM。它还假设服务的新实例自动注册到服务注册表,并且不健康的实例将被自动删除。诸如 Kubernetes、Mesos 等平台已经为基于容器的应用程序提供了这样的功能。为基于虚拟机的应用程序提供的解决方案就更多了。

Pilot 使用来自服务注册的信息,并提供与平台无关的服务发现接口。网格中的 Envoy 实例执行服务发现,并相应地动态更新其负载均衡池。

发现与负载均衡
发现与负载均衡

如上图所示,网格中的服务使用其 DNS 名称访问彼此。服务的所有 HTTP 流量都会通过 Envoy 自动重新路由。Envoy 在负载均衡池中的实例之间分发流量。虽然 Envoy 支持多种复杂的负载均衡算法,但 Istio 目前仅允许三种负载均衡模式:轮询、随机和带权重的最少请求。

除了负载均衡外,Envoy 还会定期检查池中每个实例的运行状况。Envoy 遵循熔断器风格模式,根据健康检查 API 调用的失败率将实例分类为不健康和健康两种。换句话说,当给定实例的健康检查失败次数超过预定阈值时,将会被从负载均衡池中弹出。类似地,当通过的健康检查数超过预定阈值时,该实例将被添加回负载均衡池。您可以在处理故障中了解更多有关 Envoy 的故障处理功能。

服务可以通过使用 HTTP 503 响应健康检查来主动减轻负担。在这种情况下,服务实例将立即从调用者的负载均衡池中删除。

故障处理

Envoy 提供了一套开箱即用,可选的的故障恢复功能,对应用中的服务大有裨益。这些功能包括:

  1. 超时
  2. 具备超时预算,并能够在重试之间进行可变抖动(间隔)的有限重试功能
  3. 并发连接数和上游服务请求数限制
  4. 对负载均衡池中的每个成员主动(定期)运行健康检查
  5. 细粒度熔断器(被动健康检查)——适用于负载均衡池中的每个实例

这些功能可以使用 Istio 的流量管理规则在运行时进行动态配置。

对超载的上游服务来说,重试之间的抖动极大的降低了重试造成的影响,而超时预算确保调用方服务在可预测的时间范围内获得响应(成功/失败)。

主动和被动健康检查(上述 4 和 5 )的组合最大限度地减少了在负载均衡池中访问不健康实例的机会。当将其与平台级健康检查(例如由 Kubernetes 或 Mesos 支持的检查)相结合时, 可以确保应用程序将不健康的 Pod/容器/虚拟机快速地从服务网格中去除,从而最小化请求失败和延迟产生影响。

总之,这些功能使得服务网格能够耐受故障节点,并防止本地故障导致的其他节点的稳定性下降。

微调

Istio 的流量管理规则允许运维人员为每个服务/版本设置故障恢复的全局默认值。然而,服务的消费者也可以通过特殊的 HTTP 头提供的请求级别值覆盖超时重试的默认值。在 Envoy 代理的实现中,对应的 Header 分别是 x-envoy-upstream-rq-timeout-ms 和 x-envoy-max-retries

FAQ

Q: 在 Istio 中运行的应用程序是否仍需要处理故障?

是的。Istio可以提高网格中服务的可靠性和可用性。但是,应用程序仍然需要处理故障(错误)并采取适当的回退操作。例如,当负载均衡池中的所有实例都失败时,Envoy 将返回 HTTP 503。应用程序有责任实现必要的逻辑,对这种来自上游服务的 HTTP 503 错误做出合适的响应。

Q: 已经使用容错库(例如 Hystrix)的应用程序,是否会因为 Envoy 的故障恢复功能受到破坏?

不会。Envoy对应用程序是完全透明的。在进行服务调用时,由 Envoy 返回的故障响应与上游服务返回的故障响应不会被区分开来。

Q: 同时使用应用级库和 Envoy 时,怎样处理故障?

假如对同一个目的服务给出两个故障恢复策略(例如,两次超时设置——一个在 Envoy 中设置,另一个在应用程序库中设置),当故障发生时,将触发两者中更严格的那个。例如,如果应用程序为服务的 API 调用设置了 5 秒的超时时间,而运维人员给 Envoy 配置了 10 秒的超时时间,那么应用程序的超时将会首先启动。同样,如果 Envoy 的熔断器在应用熔断器之前触发,对该服务的 API 调用将从 Envoy 收到 503 错误。

故障注入

虽然 Envoy sidecar/proxy 为在 Istio 上运行的服务提供了大量的故障恢复机制,但测试整个应用程序端到端的故障恢复能力依然是必须的。错误配置的故障恢复策略(例如,跨服务调用的不兼容/限制性超时)可能导致应用程序中的关键服务持续不可用,从而破坏用户体验。

Istio 能在不杀死 Pod 的情况下,将特定协议的故障注入到网络中,在 TCP 层制造数据包的延迟或损坏。我们的理由是,无论网络级别的故障如何,应用层观察到的故障都是一样的,并且可以在应用层注入更有意义的故障(例如,HTTP 错误代码),以检验和改善应用的弹性。

运维人员可以为符合特定条件的请求配置故障,还可以进一步限制遭受故障的请求的百分比。可以注入两种类型的故障:延迟和中断。延迟是计时故障,模拟网络延迟上升或上游服务超载的情况。中断是模拟上游服务的崩溃故障。中断通常以 HTTP 错误代码或 TCP 连接失败的形式表现。

规则配置

Istio 提供了一个简单的配置模型,用来控制 API 调用以及应用部署内多个服务之间的四层通信。运维人员可以使用这个模型来配置服务级别的属性,这些属性可以是断路器、超时、重试,以及一些普通的持续发布任务,例如金丝雀发布、A/B 测试、使用百分比对流量进行控制,从而完成应用的逐步发布等。

Istio 中包含有四种流量管理配置资源,分别是 VirtualServiceDestinationRuleServiceEntry 以及 Gateway。下面会讲一下这几个资源的一些重点。在网络参考中可以获得更多这方面的信息。

  • VirtualService 在 Istio 服务网格中定义路由规则,控制路由如何路由到服务上。
  • DestinationRule 是 VirtualService 路由生效后,配置应用与请求的策略集。
  • ServiceEntry 是通常用于在 Istio 服务网格之外启用对服务的请求。
  • Gateway 为 HTTP/TCP 流量配置负载均衡器,最常见的是在网格的边缘的操作,以启用应用程序的入口流量。

例如,将 reviews 服务接收到的流量 100% 地发送到 v1 版本,这一需求可以用下面的规则来实现:

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

 

这个配置的用意是,发送到 reviews 服务(在 hosts 字段中标识)的流量应该被路由到 reviews 服务实例的 v1 子集中。路由中的 subset 制定了一个预定义的子集名称,子集的定义来自于目标规则配置:

子集指定了一个或多个特定版本的实例标签。例如,在 Kubernetes 中部署 Istio 时,“version: v1” 表示只有包含 “version: v1” 标签版本的 pod 才会接收流量。

在 DestinationRule 中,你可以添加其他策略,例如:下面的定义指定使用随机负载均衡模式:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

 

可以使用 kubectl 命令配置规则。在配置请求路由任务中包含有配置示例。

以下部分提供了流量管理配置资源的基本概述。详细信息请查看网络参考

Virtual Service

VirtualService 定义了控制在 Istio 服务网格中如何路由服务请求的规则。例如一个 Virtual Service 可以把请求路由到不同版本,甚至是可以路由到一个完全不同于请求要求的服务上去。路由可以用很多条件进行判断,例如请求的源和目的地、HTTP 路径和 Header 以及各个服务版本的权重等。

规则的目标描述

路由规则对应着一或多个用 VirtualService 配置指定的请求目的主机。这些主机可以是也可以不是实际的目标负载,甚至可以不是同一网格内可路由的服务。例如要给到 reviews 服务的请求定义路由规则,可以使用内部的名称 reviews,也可以用域名 bookinfo.comVirtualService 可以定义这样的 hosts 字段:

hosts:
  - reviews
  - bookinfo.com

 

hosts 字段用显示或者隐式的方式定义了一或多个完全限定名(FQDN)。上面的 reviews,会隐式的扩展成为特定的 FQDN,例如在 Kubernetes 环境中,全名会从 VirtualService 所在的集群和命名空间中继承而来(比如说 reviews.default.svc.cluster.local)。

在服务之间分拆流量

每个路由规则都需要对一或多个有权重的后端进行甄别并调用合适的后端。每个后端都对应一个特定版本的目标服务,服务的版本是依靠标签来区分的。如果一个服务版本包含多个注册实例,那么会根据为该服务定义的负载均衡策略进行路由,缺省策略是 round-robin

例如下面的规则会把 25% 的 reviews 服务流量分配给 v2 标签;其余的 75% 流量分配给 v1

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 75
    - destination:
        host: reviews
        subset: v2
      weight: 25

 

超时和重试

缺省情况下,HTTP 请求的超时设置为 15 秒,可以使用路由规则来覆盖这个限制:

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

 

还可以用路由规则来指定某些 http 请求的重试次数。下面的代码可以用来设置最大重试次数,或者在规定时间内一直重试,时间长度同样可以进行覆盖:

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

 

注意请求的重试和超时还可以针对每个请求分别设置

请求超时任务中展示了超时控制的相关示例。

错误注入

在根据路由规则向选中目标转发 http 请求的时候,可以向其中注入一或多个错误。错误可以是延迟,也可以是退出。

下面的例子在目标为 ratings:v1 服务的流量中,对其中的 10% 注入 5 秒钟的延迟。

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

 

可以使用其他类型的故障,终止、提前终止请求。例如,模拟失败。

接下来,在目标为 ratings:v1 服务的流量中,对其中的 10% 注入 HTTP 400 错误。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      abort:
        percent: 10
        httpStatus: 400
    route:
    - destination:
        host: ratings
        subset: v1

 

有时会把延迟和退出同时使用。例如下面的规则对从 reviews:v2 到 ratings:v1 的流量生效,会让所有的请求延迟 5 秒钟,接下来把其中的 10% 退出:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
    fault:
      delay:
        fixedDelay: 5s
      abort:
        percent: 10
        httpStatus: 400
    route:
    - destination:
        host: ratings
        subset: v1

 

可以参考错误注入任务,进行这方面的实际体验。

条件规则

可以选择让规则只对符合某些要求的请求生效:

1. 使用工作负载 label 限制特定客户端工作负载。例如,规则可以指示它仅适用于实现 reviews 服务的工作负载实例(pod)的调用:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
      sourceLabels:
        app: reviews
    ...

 

sourceLabels 的值取决于服务的实现。例如,在 Kubernetes 中,它可能与相应 Kubernetes 服务的 pod 选择器中使用的 label 相同。

以上示例还可以进一步细化为仅适用于 reviews 服务版本 v2 负载均衡实例的调用:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
    ...

 

2. 根据 HTTP Header 选择规则。下面的规则只会对包含了 end-user 标头的来源请求,且值为 jason 的请求生效:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    ...

 

如果规则中指定了多个标头,则所有相应的标头必须匹配才能应用规则。

3. 根据请求URI选择规则。例如,如果 URI 路径以 /api/v1 开头,则以下规则仅适用于请求:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
spec:
  hosts:
    - productpage
  http:
  - match:
    - uri:
        prefix: /api/v1
    ...

 

多重匹配条件

可以同时设置多个匹配条件。在这种情况下,根据嵌套,应用 AND 或 OR 语义。

如果多个条件嵌套在单个匹配子句中,则条件为 AND。例如,以下规则仅适用于客户端工作负载为 reviews:v2 且请求中包含 jason 的自定义 end-user 标头:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
      headers:
        end-user:
          exact: jason
    ...

 

相反,如果条件出现在单独的匹配子句中,则只应用其中一个条件(OR 语义):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
    - headers:
        end-user:
          exact: jason
    ...

 

如果客户端工作负载是 reviews:v2,或者请求中包含 jason 的自定义 end-user 标头,则适用此规则。

优先级

当对同一目标有多个规则时,会按照在 VirtualService 中的顺序进行应用,换句话说,列表中的第一条规则具有最高优先级。

为什么优先级很重要:当对某个服务的路由是完全基于权重的时候,就可以在单一规则中完成。另一方面,如果有多重条件(例如来自特定用户的请求)用来进行路由,就会需要不止一条规则。这样就出现了优先级问题,需要通过优先级来保证根据正确的顺序来执行规则。

常见的路由模式是提供一或多个高优先级规则,这些优先规则使用源服务以及 Header 来进行路由判断,然后才提供一条单独的基于权重的规则,这些低优先级规则不设置匹配规则,仅根据权重对所有剩余流量进行分流。

例如下面的 VirtualService 包含了两个规则,所有对 reviews 服务发起的请求,如果 Header 包含 Foo=bar,就会被路由到 v2 实例,而其他请求则会发送给 v1 :

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        Foo:
          exact: bar
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1

 

注意,基于 Header 的规则具有更高优先级。如果降低它的优先级,那么这一规则就无法生效了,这是因为那些没有限制的权重规则会首先被执行,也就是说所有请求即使包含了符合条件的 Foo 头,也都会被路由到 v1。流量特征被判断为符合一条规则的条件的时候,就会结束规则的选择过程,这就是在存在多条规则时,需要慎重考虑优先级问题的原因。

目标规则

在请求被 VirtualService 路由之后,DestinationRule 配置的一系列策略就生效了。这些策略由服务属主编写,包含断路器、负载均衡以及 TLS 等的配置内容。

DestinationRule 还定义了对应目标主机的可路由 subset(例如有命名的版本)。VirtualService 在向特定服务版本发送请求时会用到这些子集。

下面是 reviews 服务的 DestinationRule 配置策略以及子集:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  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

 

注意在单个 DestinationRule 配置中可以包含多条策略(比如 default 和 v2)。

断路器

可以用一系列的标准,例如连接数和请求数限制来定义简单的断路器。

例如下面的 DestinationRule 给 reviews 服务的 v1 版本设置了 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

 

查看断路器演示请查看 断路器任务

规则评估

和路由规则类似,DestinationRule 中定义的策略也是和特定的 host 相关联的,如果指定了 subset,那么具体生效的 subset 的决策是由路由规则来决定的。

规则评估的第一步,是确认 VirtualService 中所请求的主机相对应的路由规则(如果有的话),这一步骤决定了将请求发往目标服务的哪一个 subset(就是特定版本)。下一步,被选中的 subset 如果定义了策略,就会开始是否生效的评估。

注意:这一算法需要留心是,为特定 subset 定义的策略,只有在该 subset 被显式的路由时候才能生效。例如下面的配置,只为 review 服务定义了规则(没有对应的 VirtualService 路由规则)。

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

 

既然没有为 reviews 服务定义路由规则,那么就会使用缺省的 round-robin 策略,偶尔会请求到 v1 实例,如果只有一个 v1 实例,那么所有请求都会发送给它。然而上面的策略是永远不会生效的,这是因为,缺省路由是在更底层完成的任务,策略引擎无法获知最终目的,也无法为请求选择匹配的 subset 策略。

有两种方法来解决这个问题。可以把路由策略提高一级,要求他对所有版本生效:

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

 

还有一个更好的方法,就是为服务定义路由规则,例如给 reviews:v1 加入一个简单的路由规则:

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

 

虽然 Istio 在没有定义任何规则的情况下,能将所有来源的流量发送给所有版本的目标服务。然而一旦需要对版本有所区别,就需要制定规则了。从一开始就给每个服务设置缺省规则,是 Istio 世界里推荐的最佳实践。

Service Entry

Istio 内部会维护一个服务注册表,可以用 ServiceEntry 向其中加入额外的条目。通常这个对象用来启用对 Istio 服务网格之外的服务发出请求。例如下面的 ServiceEntry 可以用来允许外部对 *.foo.com 域名上的服务主机的调用。

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: foo-ext-svc
spec:
  hosts:
  - "*.foo.com"
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS

 

ServiceEntry 中使用 hosts 字段来指定目标,字段值可以是一个完全限定名,也可以是个通配符域名。其中包含的白名单,包含一或多个允许网格中服务访问的服务。

ServiceEntry 的配置不仅限于外部服务,它有两种类型:网格内部和网格外部。网格内的条目和其他的内部服务类似,用于显式的将服务加入网格。可以用来把服务作为服务网格扩展的一部分加入不受管理的基础设置(例如加入到基于 Kubernetes 的服务网格中的虚拟机)中。网格外的条目用于表达网格外的服务。对这种条目来说,双向 TLS 认证被禁用,策略实现需要在客户端执行,而不像内部服务请求那样在服务端执行。

只要 ServiceEntry 涉及到了匹配 hosts 的服务,就可以和 VirtualService 以及 DestinationRule 配合工作。例如下面的规则可以和上面的 ServiceEntry 同时使用,在访问 bar.foo.com 的外部服务时,设置一个 10 秒钟的超时。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bar-foo-ext-svc
spec:
  hosts:
    - bar.foo.com
  http:
  - route:
    - destination:
        host: bar.foo.com
    timeout: 10s

 

流量的重定向和转发、定义重试和超时以及错误注入策略都支持外部目标。然而由于外部服务没有多版本的概念,因此权重(基于版本)路由就无法实现了。

参照 egress 任务可以了解更多的访问外部服务方面的知识。

Gateway

Gateway 为 HTTP/TCP 流量配置了一个负载均衡,多数情况下在网格边缘进行操作,用于启用一个服务的入口(ingress)流量。

和 Kubernetes Ingress 不同,Istio Gateway 只配置四层到六层的功能(例如开放端口或者 TLS 配置)。绑定一个 VirtualService 到 Gateway 上,用户就可以使用标准的 Istio 规则来控制进入的 HTTP 和 TCP 流量。

例如下面提供一个简单的 Gateway 代码,配合一个负载均衡,允许外部针对主机 bookinfo.com 的 https 流量:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - bookinfo.com
    tls:
      mode: SIMPLE
      serverCertificate: /tmp/tls.crt
      privateKey: /tmp/tls.key

 

要为 Gateway 配置对应的路由,必须为定义一个同样 hosts 定义的 VirtualService,其中用 gateways 字段来绑定到定义好的 Gateway 上:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  gateways:
  - bookinfo-gateway # <---- 绑定到 Gateway
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    ...

 

在 Ingress 任务 中有完整的 Ingress Gateway 例子。

虽然主要用于管理入口(Ingress)流量,Gateway 还可以用在纯粹的内部服务之间或者出口(Egress)场景下使用。不管处于什么位置,所有的网关都可以以同样的方式进行配置和控制。Gateway 参考 中包含更多细节描述。

三、安全

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

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

Istio Security 尝试提供全面的安全解决方案来解决所有这些问题。

本页概述了如何使用 Istio 的安全功能来保护您的服务,无论您在何处运行它们。特别是 Istio 安全性可以缓解针对您的数据,端点,通信和平台的内部和外部威胁。

Istio 安全模型的组件构成。
Istio 安全概述

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

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

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

如图所示,Istio 的 Citadel 用加载 Secret 卷的方式在 Kubernetes 容器中完成证书和密钥的分发。如果服务运行在虚拟机或物理机上,则会使用运行在本地的 Node agent,它负责在本地生成私钥和 CSR(证书签发申请),把 CSR 发送给 Citadel 进行签署,并把生成的证书和私钥分发给 Envoy。

高级架构

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

  • Citadel 用于密钥和证书管理
  • Sidecar 和周边代理 实现客户端和服务器之间的安全通信
  • Pilot 将授权策略安全命名信息分发给代理
  • Mixer 管理授权和审计
Istio 安全架构
Istio 安全架构

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

Istio 身份

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

在 Istio 身份模型中,Istio 使用一流的服务标识来确定服务的身份。 这为表示人类用户,单个服务或一组服务提供了极大的灵活性和粒度。 在没有此类身份的平台上,Istio 可以使用可以对服务实例进行分组的其他身份,例如服务名称。

不同平台上的 Istio 服务标识:

  • Kubernetes: Kubernetes 服务帐户
  • GKE/GCE: 可以使用 GCP 服务帐户
  • GCP: GCP 服务帐户
  • AWS: AWS IAM 用户/角色 帐户
  • On-premises (非 Kubernetes): 用户帐户、自定义服务帐户、服务名称、Istio 服务帐户或 GCP 服务帐户。

自定义服务帐户引用现有服务帐户,就像客户的身份目录管理的身份一样。

Istio 安全与 SPIFFE

SPIFFE 标准提供了一个框架规范,该框架能够跨异构环境引导和向服务发布身份。

Istio 和 SPIFFE 共享相同的身份文件:SVID(SPIFFE 可验证身份证件)。 例如,在 Kubernetes 中,X.509 证书的 URI 字段格式为 spiffe://<domain>/ns/<namespace>/sa/<serviceaccount>。 这使 Istio 服务能够建立和接受与其他 SPIFFE 兼容系统的连接。

Istio 安全性和 SPIRE,它是 SPIFFE 的实现,在 PKI 实现细节上有所不同。Istio 提供更全面的安全解决方案,包括身份验证、授权和审计。

PKI

Istio PKI 建立在 Istio Citadel 之上,可为每个工作负载安全地提供强大的工作负载标识。 Istio 使用 X.509 证书来携带 SPIFFE 格式的身份。 PKI 还可以大规模自动化密钥和证书轮换。

Istio 支持在 Kubernetes pod 和本地计算机上运行的服务。 目前,我们为每个方案使用不同的证书密钥配置机制。

Kubernetes 方案
  1. Citadel 监视 Kubernetes apiserver,为每个现有和新的服务帐户创建 SPIFFE 证书和密钥对。Citadel 将证书和密钥对存储为 Kubernetes secret
  2. 创建 pod 时,Kubernetes 会根据其服务帐户通过 Kubernetes secret volume 将证书和密钥对挂载到 pod。
  3. Citadel 监视每个证书的生命周期,并通过重写 Kubernetes 秘密自动轮换证书。
  4. Pilot 生成安全命名信息,该信息定义了哪些 Service Account 可以运行哪些服务。Pilot 然后将安全命名信息传递给 envoy sidecar。
本地机器方案
  1. Citadel 创建 gRPC 服务来接受证书签名请求(CSR)。
  2. 节点代理生成私钥和 CSR,并将 CSR 及其凭据发送给 Citadel 进行签名。
  3. Citadel 验证 CSR 承载的凭证,并签署 CSR 以生成证书。
  4. 节点代理将从 Citadel 接收的证书和私钥发送给 Envoy。
  5. 上述 CSR 过程会定期重复进行证书和密钥轮换。
Kubernetes 中的代理节点

Istio 提供了在 Kubernetes 中使用节点代理进行证书和密钥分配的选项,如下图所示。请注意,本地计算机的标识提供流程是相同的,因此我们仅描述 Kubernetes 方案。

PKI 与 Kubernetes 中的节点代理
PKI 与 Kubernetes 中的节点代理

流程如下:

  1. Citadel 创建一个 gRPC 服务来接受 CSR 请求。
  2. Envoy 通过 Envoy secret 发现服务(SDS)API 发送证书和密钥请求。
  3. 收到 SDS 请求后,节点代理会创建私钥和 CSR,并将 CSR 及其凭据发送给 Citadel 进行签名。
  4. Citadel 验证 CSR 中携带的凭证,并签署 CSR 以生成证书。
  5. 节点代理通过 Envoy SDS API 将从 Citadel 接收的证书和私钥发送给 Envoy。
  6. 上述 CSR 过程会定期重复进行证书和密钥轮换。

最佳实践

在本节中,我们提供了一些部署指南并讨论了一个真实的场景。

部署指南

如果有多个服务运维团队(又名 SREs)在中型或大型集群中部署不同的服务,我们建议创建一个单独的 Kubernetes 命名空间让每个 SRE 团队隔离他们的访问权限。例如,您可以为 team1 创建 team1-ns 命名空间,为 team2 创建 team2-ns 命名空间,这样两个团队都无法访问彼此的服务。

示例

让我们考虑一个带有三种服务的三层应用程序:photo-frontendphoto-backend 和 datastore。照片 SRE 团队管理 photo-frontend 和 photo-backend服务,而数据存储 SRE 团队管理 datastore 服务。 photo-frontend 服务可以访问 photo-backendphoto-backend 服务可以访问 datastore。但是,photo-frontend 服务无法访问 datastore

在这种情况下,集群管理员创建三个命名空间:istio-citadel-nsphoto-ns 和 datastore-ns。管理员可以访问所有命名空间,每个团队只能访问自己的命名空间。照片 SRE 团队创建了两个服务帐户,分别在 photo-ns 命名空间中运行 photo-frontend 和 photo-backend。数据存储区 SRE 团队创建一个服务帐户,以在 datastore-ns 命名空间中运行 datastore 服务。此外,我们需要在 Istio Mixer 中强制执行服务访问控制,使得 photo-frontend 无法访问数据存储区。

在此设置中,Kubernetes 可以隔离运营商管理服务的权限。 Istio 管理所有命名空间中的证书和密钥,并对服务实施不同的访问控制规则。

认证

Istio 提供两种类型的身份验证:

  • 传输身份验证,也称为服务到服务身份验证:验证建立连接的直接客户端。 Istio 提供 双向 TLS 作为传输身份验证的完整堆栈解决方案。 您可以轻松打开此功能,而无需更改服务代码。这个解决方案:
    • 为每个服务提供强大的身份,表示其角色,以实现跨群集和云的互操作性。
    • 保护服务到服务通信和最终用户到服务通信。
    • 提供密钥管理系统,以自动执行密钥和证书生成,分发和轮换。
  • 来源身份认证,也称为最终用户身份验证:验证作为最终用户或设备发出请求的原始客户端。Istio 通过 JSON Web Token(JWT)验证和 Auth0Firebase Auth 、Google Auth 和自定义身份验证来简化开发人员体验,并且轻松实现请求级别的身份验证。

在这两种情况下,Istio 都通过自定义 Kubernetes API 将身份认证策略存储在 Istio 配置存储中。 Pilot 会在适当的时候为每个代理保持最新状态以及密钥。此外,Istio 支持在宽容模式下进行身份验证,以帮助您了解策略更改在其生效之前如何影响您的安全状态。

双向 TLS 认证

Istio 隧道通过客户端和服务器端进行服务到服务通信 Envoy 代理。对于客户端调用服务器,遵循的步骤是:

  1. Istio 将出站流量从客户端重新路由到客户端的本地 sidecar Envoy。
  2. 客户端 Envoy 和服务器端 Envoy 建立了一个双向的 TLS 连接,Istio 将流量从客户端 Envoy 转发到服务器端 Envoy。
  3. 授权后,服务器端 Envoy 通过本地 TCP 连接将流量转发到服务器服务。

宽容模式

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

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

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

安全命名

安全命名信息包含从编码在证书中的服务器标识到被发现服务或 DNS 引用的服务名称的 N-到-N 映射。从身份 A 到服务名称 B 的映射意味着“允许 A 并授权其运行服务 B ”。Pilot 监视 Kubernetes apiserver,生成安全的命名信息,并将其安全地分发给 sidecar Envoy。以下示例说明了为什么安全命名在身份验证中至关重要。

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

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

认证架构

您可以使用身份认证策略为在 Istio 网格中接收请求的服务指定身份验证要求。网格操作者使用 .yaml 文件来指定策略。部署后,策略将保存在 Istio Config Store。 Pilot、Istio 控制器监视配置存储。一有任何的策略变更,Pilot 会将新策略转换为适当的配置,告知 Envoy sidecar 代理如何执行所需的身份验证机制。Pilot 可以获取公钥并将其附加到 JWT 验证配置。或者,Pilot 提供 Istio 系统管理的密钥和证书的路径,并将它们挂载到应用程序 pod 以进行双向 TLS。您可以在 PKI 部分中找到更多信息。Istio 异步发送配置到目标端点。代理收到配置后,新的身份验证要求会立即生效。

发送请求的客户端服务负责遵循必要的身份验证机制。对于源身份验证(JWT),应用程序负责获取 JWT 凭据并将其附加到请求。对于双向 TLS,Istio 提供目标规则。运维人员可以使用目标规则来指示客户端代理使用 TLS 与服务器端预期的证书进行初始连接。您可以在 双向 TLS 认证中找到有关双向 TLS 如何在 Istio 中工作的更多信息。

认证架构
认证架构

Istio 将两种类型的身份验证以及凭证中的其他声明(如果适用)输出到下一层:授权。此外,运维人员可以指定将传输或原始身份验证中的哪个身份作为委托人使用。

认证策略

本节中提供了更多 Istio 认证策略方面的细节。正如认证架构中所说的,认证策略是对服务收到的请求生效的。要在双向 TLS 中指定客户端认证策略,需要在 DetinationRule 中设置 TLSSettingsTLS 设置参考文档中有更多这方面的信息。和其他的 Istio 配置一样,可以用 .yaml 文件的形式来编写认证策略,然后使用 istioctl 进行部署。

下面例子中的认证策略要求 reviews 服务必须使用双向 TLS:

apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
  name: "reviews"
spec:
  targets:
  - name: reviews
    peers:
  - mtls: {}

 

策略存储范围

Istio 可以在命名空间范围或网络范围存储中存储身份认证策略:

  • 为 kind 字段指定了网格范围策略,其值为 MeshPolicy,名称为 default。例如:
    apiVersion: "authentication.istio.io/v1alpha1"
    kind: "MeshPolicy"
    metadata:
      name: "default"
    spec:
      peers:
      - mtls: {}
    

     

  • 为 kind 字段和指定的命名空间指定命名空间范围策略,其值为 Policy。如果未指定,则使用默认命名空间。例如,命名空间 ns1
    apiVersion: "authentication.istio.io/v1alpha1"
    kind: "Policy"
    metadata:
      name: "default"
      namespace: "ns1"
    spec:
      peers:
      - mtls: {}
    

     

命名空间范围存储中的策略只能影响同一命名空间中的服务。网格范围内的策略可以影响网格中的所有服务。为防止冲突和滥用,只能在网状范围存储中定义一个策略。该策略必须命名为 default 并且有一个空的 targets: 部分。您可以在我们的目标选择器部分中找到更多信息。

目标选择器

身份认证策略的目标指定策略适用的服务。以下示例展示的是一个 targets: 部分,指定该策略适用于:

  • 任何端口上的 product-page 服务。
  • 端口 9000 上的评论服务。
targets:

 - name: product-page
 - name: reviews
   ports:
   - number: 9000

 

如果您未提供 targets: 部分,则 Istio 将策略与策略存储范围内的所有服务匹配。因此,targets: 部分可以帮助您指定策略的范围:

  • 网格范围策略:在网格范围存储中定义的策略,没有目标选择器部分。网格中最多只能有一个网格范围的策略。
  • 命名空间范围的策略:在命名空间范围存储中定义的策略,名称为 default 且没有目标选择器部分。每个命名空间最多只能有一个命名空间范围的策略。
  • 特定于服务的策略:在命名空间范围存储中定义的策略,具有非空目标选择器部分。命名空间可以具有零个,一个或多个特定于服务的策略。

对于每项服务,Istio 都应用最窄的匹配策略。顺序是:特定服务>命名空间范围>网格范围。如果多个特定于服务的策略与服务匹配,则 Istio 随机选择其中一个。运维人员在配置其策略时必须避免此类冲突。

为了强制网格范围和命名空间范围的策略的唯一性,Istio 每个网格只接受一个身份认证策略,每个命名空间只接受一个身份认证策略。Istio 还要求网格范围和命名空间范围的策略具有特定名称 default

传输认证

peers: 部分定义了策略中传输身份验证支持的身份验证方法和相关参数。该部分可以列出多个方法,并且只有一个方法必须满足认证才能通过。但是,从 Istio 0.7 版本开始,当前支持的唯一传输身份验证方法是双向 TLS。如果您不需要传输身份验证,请完全跳过此部分。

以下示例显示了使用双向 TLS 启用传输身份验证的 peers: 部分。

peers:
  - mtls: {}

 

目前,双向 TLS 设置不需要任何参数。因此,-mtls: {}- mtls: 或 - mtls: null 声明被视为相同。将来,双向 TLS 设置可以携带参数以提供不同的双向 TLS 实现。

来源身份认证

origins: 部分定义了原始身份验证支持的身份验证方法和相关参数。Istio 仅支持 JWT 原始身份验证。但是,策略可以列出不同发行者的多个 JWT。与传输身份验证类似,只有一种列出的方法必须满足身份验证才能通过。

以下示例策略为原始身份验证指定了一个 origin: 部分,该部分接受 Google 发布的 JWT:

origins:
- jwt:
    issuer: "https://accounts.google.com"
    jwksUri: "https://www.googleapis.com/oauth2/v3/certs"

 

主认证绑定

主认证关系用键值对的方式存储绑定关系。默认情况下,Istio 使用 peers: 部分中配置的身份验证。如果在 peers: 部分中未配置身份验证,则 Istio 将保留身份验证。策略编写者可以使用 USE_ORIGIN 值覆盖此行为。此值将 Istio 配置为使用 origin 的身份验证作为主体身份验证。将来,我们将支持条件绑定,例如:当传输体为 X 时为 USE_PEER,否则为 USE_ORIGIN 。

以下示例显示了 principalBinding 键,其值为 USE_ORIGIN

principalBinding: USE_ORIGIN

 

更新认证策略

您可以随时更改身份认证策略,Istio 几乎实时地将更改推送到端点。但是,Istio 无法保证所有端点同时收到新策略。以下是在更新身份认证策略时避免中断的建议:

  • 启用或禁用双向 TLS:使用带有 mode: 键和 PERMISSIVE 值的临时策略。这会将接收服务配置为接受两种类型的流量:纯文本和 TLS。因此,不会丢弃任何请求。一旦所有客户端切换到预期协议,无论是否有双向 TLS,您都可以将 PERMISSIVE 策略替换为最终策略。有关更多信息,请访问双向 TLS 的迁移
peers:
- mtls:
    mode: PERMISSIVE

 

  • 对于 JWT 身份验证迁移:在更改策略之前,请求应包含新的 JWT。一旦服务器端完全切换到新策略,旧 JWT(如果有的话)可以被删除。需要更改客户端应用程序才能使这些更改生效。

授权

Istio 的授权功能也称为基于角色的访问控制(RBAC)——为 Istio 网格中的服务提供命名空间级别、服务级别和方法级别的访问控制。它的特点是:

  • 基于角色的语义,简单易用。
  • 服务间和最终用户对服务的授权
  • 通过自定义属性支持的灵活性,例如条件、角色和角色绑定。
  • 高性能,因为 Istio 授权是在 Envoy 本地强制执行的。
  • 高兼容性,原生支持 HTTP、HTTPS 和 HTTP2,以及任意普通 TCP 协议。
授权架构
Istio Authorization
Istio 授权架构

上图显示了基本的 Istio 授权架构。运维人员使用 .yaml 文件指定 Istio 授权策略。部署后,Istio 将策略保存在 Istio Config Store 中。

Pilot 监督 Istio 授权策略的变更。如果发现任何更改,它将获取更新的授权策略。 Pilot 将 Istio 授权策略分发给与服务实例位于同一位置的 Envoy 代理。

每个 Envoy 代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果 ALLOW 或 DENY

启用授权

您可以使用 RbacConfig 对象启用 Istio Authorization。RbacConfig 对象是一个网格范围的单例,其固定名称值为 default。您只能在网格中使用一个 RbacConfig 实例。与其他 Istio 配置对象一样,RbacConfig 被定义为Kubernetes CustomResourceDefinition (CRD) 对象。

在 RbacConfig 对象中,运算符可以指定 mode 值,它可以是:

  • OFF:禁用 Istio 授权。
  • ON:为网格中的所有服务启用了 Istio 授权。
  • ON_WITH_INCLUSION:仅对包含字段中指定的服务和命名空间启用 Istio 授权。
  • ON_WITH_EXCLUSION:除了排除字段中指定的服务和命名空间外,网格中的所有服务都启用了 Istio 授权。

在以下示例中,为 default 命名空间启用了 Istio 授权。

apiVersion: "rbac.istio.io/v1alpha1"
kind: RbacConfig
metadata:
  name: default
  namespace: istio-system
spec:
  mode: 'ON_WITH_INCLUSION'
  inclusion:
    namespaces: ["default"]

 

授权策略

要配置 Istio 授权策略,请指定 ServiceRole 和 ServiceRoleBinding。与其他 Istio 配置对象一样,它们被定义为 Kubernetes CustomResourceDefinition( CRD)对象。

  • ServiceRole 定义了一组访问服务的权限。
  • ServiceRoleBinding 向特定主题授予 ServiceRole,例如用户、组或服务。

ServiceRole 和 ServiceRoleBinding 的组合规定: 允许哪些条件做什么 。明确地说:

  • 指的是 ServiceRoleBinding 中的 subject 部分。
  • 做什么指的是 ServiceRole 中的 permissions 部分。
  • 哪些条件指的是你可以在 ServiceRole 或 ServiceRoleBinding 中使用 Istio 属性指定的 conditions 部分。
ServiceRole

ServiceRole 规范包括规则、所谓的权限列表。每条规则都有以下标准字段:

  • services:服务名称列表。您可以将值设置为 * 以包括指定命名空间中的所有服务。
  • methods:HTTP 方法名称列表,对于 gRPC 请求的权限,HTTP 动词始终是 POST 。您可以将值设置为 * 以包含所有 HTTP 方法。
  • paths:HTTP 路径或 gRPC 方法。 gRPC 方法必须采用 /packageName.serviceName/methodName 的形式,并且区分大小写。

ServiceRole 规范仅适用于 metadata 部分中指定的命名空间。规则中需要 services 和 methods 字段。 paths 是可选的。如果未指定规则或将其设置为 *,则它适用于任何实例。

下面的示例显示了一个简单的角色:service-admin,它可以完全访问 default 命名空间中的所有服务。

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: service-admin
  namespace: default
spec:
  rules:
  - services: ["*"]
    methods: ["*"]

 

这是另一个角色:products-viewer,它有读取权限,包括 GET 和 HEAD,能够访问 default 命名空间中的 products.default.svc.cluster.local 服务。

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: products-viewer
  namespace: default
spec:
  rules:
  - services: ["products.default.svc.cluster.local"]
    methods: ["GET", "HEAD"]

 

此外,我们支持规则中所有字段的前缀匹配和后缀匹配。例如,您可以在 default命名空间中定义具有以下权限的 tester 角色:

  • 完全访问前缀为 test-* 的所有服务,例如:test-bookstoretest-performancetest-api.default.svc.cluster.local
  • 读取(GET)使用 */reviews 后缀访问的所有路径,例如:在 bookstore .default.svc.cluster.local 服务中的 /books/reviews/events/booksale/reviews/reviews
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: tester
  namespace: default
spec:
  rules:
  - services: ["test-*"]
    methods: ["*"]
  - services: ["bookstore.default.svc.cluster.local"]
    paths: ["*/reviews"]
    methods: ["GET"]

 

在 ServiceRole 中,namespace + services + paths + methods 的组合定义了如何访问服务。在某些情况下,您可能需要为规则指定其他条件。例如,规则可能仅适用于服务的某个版本,或仅适用于具有特定标签的服务,如 foo。您可以使用 constraints 轻松指定这些条件。

例如,下面的 ServiceRole 定义在以前的 products-viewer 角色基础之上添加了一个约束:request.headers[version] 为 v1 或 v2 。在约束和属性页面中列出了约束支持的 key 值。在属性值是 map 类型的情况下,例如 request.headerskey 是 map 中的一个条目,例如 request.headers[version]

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: products-viewer-version
  namespace: default
spec:
  rules:
  - services: ["products.default.svc.cluster.local"]
    methods: ["GET", "HEAD"]
    constraints:
    - key: request.headers[version]
      values: ["v1", "v2"]

 

ServiceRoleBinding

ServiceRoleBinding 规范包括两部分:

  • roleRef 指的是同一命名空间中的 ServiceRole 资源。
  • subjects 分配给角色的列表。

您可以使用 user 或一组 properties 显式指定 subjectServiceRoleBinding subject 中的 property 类似于 ServiceRole 规范中的 constraint。 property 还允许您使用条件指定分配给此角色的一组帐户。它包含一个 key 及其允许的。约束支持的 key 值列在约束和属性页面中。

下面的例子显示了一个名为 test-binding-products 的 ServiceRoleBinding,它将两个 subject 绑定到名为 product-viewer 的 ServiceRole 并具有以下 subject

  • 代表服务 a 的服务帐户,service-account-a
  • 代表 Ingress 服务的服务帐户 istio-ingress-service-account 并且 它的 JWT 中的 mail 项声明为 a@foo.com
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: test-binding-products
  namespace: default
spec:
  subjects:
  - user: "service-account-a"
  - user: "istio-ingress-service-account"
    properties:
      request.auth.claims[email]: "a@foo.com"
    roleRef:
    kind: ServiceRole
    name: "products-viewer"

 

如果您想要公开访问服务,可以将 subject 设置为 user:"*" 。此值将 ServiceRole 分配给所有(经过身份验证和未经身份验证的)用户和服务,例如:

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: binding-products-allusers
  namespace: default
spec:
  subjects:
  - user: "*"
    roleRef:
    kind: ServiceRole
    name: "products-viewer"

 

要将 ServiceRole 分配给经过身份验证的用户和服务,请使用 source.principal:"*" 代替,例如:

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
kind: ServiceRoleBinding
metadata:
  name: binding-products-all-authenticated-users
  namespace: default
spec:
  subjects:
  - properties:
      source.principal: "*"
    roleRef:
    kind: ServiceRole
    name: "products-viewer"

 

在普通 TCP 协议上使用 Istio 认证

Service role 和 Service role binding 中的例子展示了在使用 HTTP 协议的 service 上使用 Istio 认证的典型方法。在那些例子中,service role 和 service role binding 里的所有字段都可以支持。

Istio 授权支持使用任何普通 TCP 协议的 service,例如 MongoDB。在这种情况下,您可以像配置 HTTP 服务一样配置 service role 和 service role binding。不同之处在于某些字段,约束和属性仅适用于 HTTP 服务。这些字段包括:

  • service role 配置对象中的 paths 和 methods 字段。
  • service role binding 配置对象中的 group 字段。

支持的约束和属性在约束和属性页面中列出。

如果您在 TCP service 中使用了任意 HTTP 独有的字段,Istio 将会完全忽略 service role 或 service role binding 自定义资源,以及里面设置的策略。

假设您有一个 MongoDB service 在 27017 端口上监听,下面的示例配置了一个 service role 和一个 service role binding,仅允许 Istio 网格中的 `bookinfo-ratings-v2 访问 MongoDB service。

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: mongodb-viewer
  namespace: default
spec:
  rules:
  - services: ["mongodb.default.svc.cluster.local"]
    constraints:
    - key: "destination.port"
      values: ["27017"]
---
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: bind-mongodb-viewer
  namespace: default
spec:
  subjects:
  - user: "cluster.local/ns/default/sa/bookinfo-ratings-v2"
  roleRef:
    kind: ServiceRole
    name: "mongodb-viewer"

 

授权宽容模式

授权宽容模式(authorization permissive mode)是 Istio 1.1 发布版中的实验特性。其接口可能在未来的发布中发生变化。

授权宽容模式允许您在将授权策略提交到生产环境部署之前对其进行验证。

您可以在全局授权配置和单个独立策略中启用授权宽容模式。如果在全局授权配置中设置,所有策略都将切换至授权宽容模式,不管其本身的模式。如果您设置全局授权模式为 ENFORCED,单个策略设置的强制模式将起作用。如果您没有设置任何模式,全局授权配置和单个策略都将默认被设置为 ENFORCED。

要全局启用宽容模式,请将全局 Istio RBAC 授权配置中的 enforcement_mode: 设置为 PERMISSIVE,如下面的示例所示。

apiVersion: "rbac.istio.io/v1alpha1"
kind: ClusterRbacConfig
metadata:
  name: default
spec:
  mode: 'ON_WITH_INCLUSION'
  inclusion:
    namespaces: ["default"]
  enforcement_mode: PERMISSIVE

 

如要为特定策略启用宽容模式,请将策略配置文件中的 mode: 设置为 PERMISSIVE,如下面的示例所示。

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: bind-details-reviews
  namespace: default
spec:
  subjects:
    - user: "cluster.local/ns/default/sa/bookinfo-productpage"
  roleRef:
    kind: ServiceRole
    name: "details-reviews-viewer"
  mode: PERMISSIVE

 

使用其他授权机制

虽然我们强烈建议使用 Istio 授权机制,但 Istio 足够灵活,允许您通过 Mixer 组件插入自己的身份验证和授权机制。 要在 Mixer 中使用和配置插件,请访问我们的策略和遥测适配器文档

四、策略与遥测

Istio 提供灵活的模型来执行授权策略,并为网格中的服务收集遥测数据。

基础设施后端旨在提供用于构建服务的支持功能。它们包括访问控制系统、遥测捕获系统、配额执行系统以及计费系统等等。服务传统上直接与这些后端系统集成,创建硬耦合,还有沾染特定的语义和使用选项。

Istio 提供统一抽象,使得 Istio 可以与一组开放式基础设施后端进行交互。这样做是为了给运维提供丰富而深入的控制,同时不给服务开发人员带来负担。Istio 旨在改变层与层之间的边界,以减少系统复杂性,消除服务代码中的策略逻辑并将控制权交给运维。

Mixer 是负责提供策略控制和遥测收集的 Istio 组件:

Mixer 拓扑
Mixer 拓扑

在每次请求执行先决条件检查之前以及在每次报告遥测请求之后,Envoy sidecar 在逻辑上调用 Mixer。 该 Sidecar 具有本地缓存​,从而可以在缓存中执行相对较大比例的前提条件检查。此外,sidecar 缓冲出站遥测,使其实际上不需要经常调用 Mixer。

在高层上,Mixer 提供:

  • 后端抽象。Mixer 隔离 Istio 的其余部分和各个基础设施后端的实现细节。
  • 中介。Mixer 允许运维对网格和基础设施后端之间的所有交互进行细化控制。

除了这些纯粹的功能方面,Mixer 还具有如下所述的可靠性和可扩展性方面的优势。

策略执行和遥测收集完全由配置驱动。可以完全禁用这些功能,并免除在 Istio 部署中运行 Mixer 组件的必要性。

适配器

Mixer 是高度模块化和可扩展的组件。它的一个关键功能就是把不同后端的策略和遥测收集系统的细节进行抽象,完成 Istio 其余部分和这些后端的隔离。

Mixer 处理不同基础设施后端的灵活性是通过使用通用插件模型实现的。每个插件都被称为 Adapter,Mixer 通过它们与不同的基础设施后端连接,这些后端可提供核心功能,例如日志、监控、配额、ACL 检查等。通过配置能够决定在运行时使用的确切的适配器套件,并且可以轻松扩展到新的或定制的基础设施后端。

显示 Mixer 及其适配器
Mixer 及其适配器

获取更多适配器支持范围方面的内容。

可靠性和延迟

Mixer 是一个高可用的组件,其设计有助于提高整体可用性并减少网格中服务的平均延迟。其设计的关键方面带来以下好处:

  • 无状态。Mixer 是无状态的,因为它不管理任何自己的持久化存储。
  • 加固。Mixer 本身被设计成高度可靠的组件。设计目标是为任何单独的 Mixer 实例实现 > 99.999% 的正常运行时间。
  • 缓存和缓冲。Mixer 被设计为累积大量瞬态短暂状态。

网格中每个服务都会有对应的 Sidecar 代理在运行,因此在内存消耗方面,Sidecar 必须厉行节约,这就限制了本地缓存和缓冲的可能数量。然而,独立运行 的 Mixer 可以使用相当大的缓存和输出缓冲区。因此,Mixer 可用作 Sidecar 的高度扩展且高度可用的二级缓存。

Mixer 拓扑
Mixer 拓扑

由于 Mixer 的预期可用性远高于大多数基础设施后端(通常这些可用性可能达到 99.9%)。Mixer 的本地缓存和缓冲不仅有助于减少延迟,而且即使在后端无响应时也能继续运行,从而有助于屏蔽基础设施后端故障。

最后,Mixer 的缓存和缓冲有助于减少对后端的调用频率,并且有时可以减少发送到后端的数据量(通过本地聚合)。这些都可以减少某些情况下的运维费用。

属性

属性是 Istio 策略和遥测功能中的基本概念。属性是用于描述特定服务请求或请求环境的属性的一小段数据。例如,属性可以被赋值为特定请求的大小、操作的响应代码、请求来自的 IP 地址等。

每个属性都有一个名称和一个类型。该类型定义了该属性所持有的数据的种类。例如,属性可以是 STRING 类型,这意味着它的值是文本类型;或者可以是 INT64 类型,指示它的值是 64 位整数。

以下是一些具有相关值的示例属性:

request.path: xyz/abc
request.size: 234
request.time: 12:34:56.789 04/17/2017
source.ip: 192.168.0.1
destination.service: example

 

Mixer 本质上是一个属性处理机。每个经过 Envoy sidecar 的请求都会调用 Mixer,为 Mixer 提供一组描述请求和请求周围环境的属性。基于 Envoy sidecar 的配置和给定的特定属性集,Mixer 会调用各种基础设施后端。

属性机
属性机
属性词汇

给定的 Istio 部署中具有其可理解的一组固定的属性词汇表。具体词汇表由部署中使用的一组属性生成器确定。Istio 中的主要属性生产者是 Envoy,但专用的 Mixer 适配器也可以生成属性。

这里定义了大多数 Istio 部署中可用的通用基准属性集。

属性表达式

配置 Instance 时要使用属性表达式。下面是一些简单的属性表达式示例:

destination_service: destination.service
response_code: response.code
destination_version: destination.labels["version"] | "unknown"

 

冒号右侧的序列是属性表达式的最简单形式。前两行只包括了属性名称。response_code 标签的内容来自于 response.code 属性。

以下是条件表达式的示例:

destination_version: destination.labels["version"] | "unknown"

 

上面的表达式里,destination_version 标签被赋值为 destination.labels["version"],如果 destination.labels["version"] 为空,则使用 "unknown" 代替。

有关详细信息,请阅读属性表达式参考

配置模型

Istio 通过一个通用模型进行策略和遥测功能的配置,目的是让运维人员能够控制授权策略和遥测收集的方方面面。在保持模型简单的同时,还提供了足以控制 Istio 各项功能的强大能力。

策略和遥控功能的控制能力包含了三种类型资源的配置:

  • 配置一组处理器(Handler),用于确定正在使用的适配器组及其操作方式。处理器配置的一个例子如:为 Statsd 后端提供带有 IP 地址的 statsd 适配器。
  • 配置一组实例(Instance),描述如何将请求属性映射到适配器输入。实例表示一个或多个适配器将操作的各种数据。例如,运维人员可能决定从诸如 destination.service 和 response.code 之类的属性中生成 requestcount 指标的实例。
  • 配置一组规则(Rule),这些规则描述了何时调用特定适配器及哪些实例。规则包含 match 表达式和 actionmatch 表达式控制何时调用适配器,而 action 决定了要提供给适配器的一组实例。例如,规则可能会将生成的 requestcount 实例发送到 statsd 适配器。

配置基于适配器模板(Template) :

  • 适配器 封装了 Mixer 和特定基础设施后端之间的接口。
  • 模板 定义了从特定请求的属性到适配器输入的映射关系。一个适配器可以支持任意数量的模板。

处理器(Handler)

适配器封装了 Mixer 和特定外部基础设施后端进行交互的必要接口,例如 Prometheus 或者 Stackdriver。各种适配器都需要参数配置才能工作。例如日志适配器可能需要 IP 地址和端口来进行日志的输出。

这里的例子配置了一个类型为 listchecker 的适配器。listchecker 适配器使用一个列表来检查输入。如果配置的是白名单模式且输入值存在于列表之中,就会返回成功的结果。

apiVersion: config.istio.io/v1alpha2
kind: listchecker
metadata:
  name: staticversion
  namespace: istio-system
spec:
  providerUrl: http://white_list_registry/
  blacklist: false

 

{metadata.name}.{kind}.{metadata.namespace} 是 Handler 的完全限定名。上面定义的对象的 FQDN 就是 staticversion.listchecker.istio-system,他必须是唯一的。spec 中的数据结构则依赖于对应的适配器的要求。

有些适配器实现的功能就不仅仅是把 Mixer 和后端连接起来。例如 prometheus 适配器采集指标并以可配置的方式将它们聚合成分布或计数器。

apiVersion: config.istio.io/v1alpha2
kind: prometheus
metadata:
  name: handler
  namespace: istio-system
spec:
  metrics:
  - name: request_count
    instance_name: requestcount.metric.istio-system
    kind: COUNTER
    label_names:
    - destination_service
    - destination_version
    - response_code
  - name: request_duration
    instance_name: requestduration.metric.istio-system
    kind: DISTRIBUTION
    label_names:
    - destination_service
    - destination_version
    - response_code
      buckets:
      explicit_buckets:
        bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]

 

每个适配器都定义了自己格式的配置数据。适配器及其配置的详尽列表可以在这里找到。

实例(Instance)

配置实例将请求中的属性映射成为适配器的输入。下面的例子,是一个 metric 实例的配置,用于生成 requestduration 指标。

apiVersion: config.istio.io/v1alpha2
kind: metric
metadata:
  name: requestduration
  namespace: istio-system
spec:
  value: response.duration | "0ms"
  dimensions:
    destination_service: destination.service | "unknown"
    destination_version: destination.labels["version"] | "unknown"
    response_code: response.code | 200
  monitored_resource_type: '"UNSPECIFIED"'

 

注意 Handler 配置中需要的所有维度都定义在这一映射之中。每个模板都有自己格式的配置数据。完整的模板及其特定配置格式可以在这里查阅。

规则(Rule)

规则用于指定使用特定实例配置调用某一 Handler 的时机。比如我们想要把 service1 服务中,请求头中带有 x-user 的请求的 requestduration 指标发送给 Prometheus Handler。

apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
  name: promhttp
  namespace: istio-system
spec:
  match: destination.service == "service1.ns.svc.cluster.local" && request.headers["x-user"] == "user1"
  actions:
  - handler: handler.prometheus
    instances:
    - requestduration.metric.istio-system

 

规则中包含有一个 match 元素,用于前置检查,如果检查通过则会执行 action 列表。action 中包含了一个实例列表,这个列表将会分发给 Handler。规则必须使用 Handler 和实例的完全限定名。如果规则、Handler 以及实例全都在同一个命名空间,命名空间后缀就可以在 FQDN 中省略,例如 handler.prometheus

五、性能与可伸缩性

【略,具体描述,可参见官方文档。】

六、多群集部署

Istio 是一个服务网格,其基本属性是监控和管理单个管理域下协作微服务网格的能力。服务网格本质上是将一组单独的微服务组合成单个可控的复合应用程序。

对于特定大小的应用,组成应用程序的所有的微服务都可以在单个编排平台上运行(例如 Kubernetes 集群)。然而,由于诸如规模、冗余等许多原因,大多数应用程序最终将需要分布式设计并使其中的一些服务能够运行在任何地方。

Istio 支持将一个应用程序的服务以多种拓扑分布,而不仅仅是分布在单一集群,例如:

  • 集群内部的服务可以使用 service entry 访问独立的外部服务,或访问其余松散耦合服务网格(或者说是*网格联邦*)公开的服务。
  • 您可以扩展服务网格以包含运行在虚拟机或裸金属主机上的服务。
  • 您可以将多个集群中的服务组合成一个单一复合服务网格,也即*多集群网格*。

多集群服务网格

多集群服务网格是由在多个底层集群中运行的 service 组成的网格,但所有 service 都在单一管控机制下运行。在一个多集群网格中,集群 1 里 namespace ns1 下名为 foo 的 service 与集群 2 里 ns1 下的 foo 是同一个 service。与松散耦合的服务网格联邦不同,在联邦中,两个集群对相同 service 的定义可能不同,在集成集群时需要对其进行协调。

多集群网格的好处是所有 service 对客户端看起来都一样,不管工作负载实际上运行在哪里。无论是部署在单个还是多个网格中,它对应用程序都是透明的。要实现此行为,需要使用单个逻辑控制平面管理所有 service。但是,单个逻辑控制平面不一定需要是单个物理 Istio 控制平面。存在两种可能的部署方法:

  1. 多个同步的 Istio 控制平面,具有复制的 service 和路由配置。
  2. 单个 Istio 控制平面,可以访问和配置网格中的所有 service。

即使在这两种拓扑中,也有多种配置多集群网格的方法。使用哪种方法,以及如何配置取决于应用程序的要求, 以及底层云平台的功能和限制。

多控制平面拓扑

在多控制平面配置中,每个集群具有相同的 Istio 控制平面安装方式,每个控制平面管理自己的 endpoint。 使用 Istio gateway、公共根证书颁发机构(CA)和 service entry,您可以配置由参与集群组成的单个逻辑服务网格。这种方法没有特殊的网络要求,因此通常被认为是在集群之间没有通用连接时最简单的方法。

Istio 网格跨越多个 Kubernetes 集群,使用多个 Istio 控制平面和 Gateway 到达远程 pod
Istio 网格跨越多个 Kubernetes 集群,使用多个 Istio 控制平面和 Gateway 到达远程 pod

要在集群中实现单个 Istio 服务网格,您需要配置一个公共根 CA 并复制所有集群中共享的 service 和 namespace。跨集群通信发生在各个集群的 Istio 网关上。所有集群都共享策略实施和安全性的控制。

在这个配置中,每个集群中的工作负载都可以像平常一样使用 Kubernetes DNS 后缀们访问其他本地 service,例如foo.ns1.svc.cluster.local。为了给远程集群中的 service 提供DNS解析,Istio 包含了 一个 CoreDNS 服务器,此服务器被配置为可以处理 <name>。<namespace> .global 形式的 service 名称。例如,从任何集群到 foo.ns1.global 的调用将解析到任意集群 namespace ns1 中运行的 foo service。要进行这种多集群配置,请访问我们提供的带网关指令的多控制平面页面。

单一控制平面拓扑

这种多集群配置使用运行在某个集群上的单个 Istio 控制平面。控制平面的 Pilot 管理本地和远程集群上的 service,并为所有集群配置 Envoy sidecar。这种方法在所有参与集群都具有 VPN 连接的环境中效果最佳,从其他任何地方都可以通过相同的 IP 地址访问网格中的每个 pod。

Istio 网格跨越多个 Kubernetes 集群,通过 VPN 直接访问远程 pod
Istio 网格跨越多个 Kubernetes 集群,通过 VPN 直接访问远程 pod

在此配置中,Istio 控制平面部署在其中一个集群上,而所有其他集群上运行一个更简单的远程 Istio 配置,以将它们连接到单个 Istio 控制平面,该平面将所有 Envoy 作为单个网格进行管理。各个集群上的 IP 地址不得重叠,且需注意远程集群上的 service 的 DNS 解析不是自动的。用户需要在每个参与集群上复制 service。您可以在我们提供的使用 VPN 指令的单一控制平面中找到设置这种多集群拓扑的详细步骤。

如果设置具有全局 pod-to-pod 连接的环境很困难或不可能,您仍然可以使用 Istio 网关并和启用 Istio Pilot 的位置感知服务路由功能(也即水平分割 EDS(Endpoint Discovery Service,终端发现服务))来配置单个控制平面拓扑。此方法仍需要从所有集群到 Kubernetes API server 的连接,例如在一个托管的 Kubernetes 平台上,其 API server 运行的网络可以被所有租户集群访问。如果无法做到这一点,那么多控制平面拓扑可能是更好的选择

Istio 网格使用单个控制平面和 Gateway 跨越多个 Kubernetes 集群到达远程 pod
Istio 网格使用单个控制平面和 Gateway 跨越多个 Kubernetes 集群到达远程 pod

在此配置中,从一个集群中的 sidecar 到同一集群中的 service 的请求仍然被转发到本地 service IP。如果目标工作负载在其他集群中运行,远程集群网关 IP 会替代 service 用于连接。访问我们的单一控制平面页面,并使用网关示例来试验此功能。

X-Eyes Admin
X-Eyes Admin

要发表评论,您必须先登录