文章目录
1. Istio是什么?
1.1 读音
[iːst’ iəʊ]
1.2 简介
云平台令使用它们的公司受益匪浅。但不可否认的是,上云会给 DevOps 团队带来压力。为了可移植性,开发人员必须使用微服务来构建应用,同时运维人员也正在管理着极端庞大的混合云和多云的部署环境。 Istio 允许您连接、保护、控制和观察服务
。
从较高的层面来说,Istio 有助于降低这些部署的复杂性,并减轻开发团队的压力。它是一个完全开源的服务网格,作为透明的一层接入到现有的分布式应用程序里。它也是一个平台,拥有可以集成任何日志、遥测和策略系统的 API 接口。Istio 多样化的特性使您能够成功且高效地运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法
。
1.3 服务网格是什么?
术语服务网格用来描述组成这些应用程序的微服务网络以及它们之间的交互。随着服务网格的规模和复杂性不断的增长,它将会变得越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、度量和监控等。服务网格通常还有更复杂的运维需求,比如 A/B 测试、金丝雀发布(灰度发布)、速率限制、访问控制和端到端认证。
Istio 提供了对整个服务网格的行为洞察和操作控制的能力,以及一个完整的满足微服务应用各种需求的解决方案。
1.4 为什么使用Isito?
通过负载均衡、服务间的身份验证、监控等方法,Istio 可以轻松地创建一个已经部署了服务的网络,而服务的代码只需很少更改甚至无需更改。通过在整个环境中部署一个特殊的 sidecar 代理为服务添加 Istio 的支持,而代理会拦截微服务之间的所有网络通信,然后使用其控制平面的功能来配置和管理 Istio,这包括:
- 为 HTTP、gRPC、WebSocket 和 TCP 流量自动负载均衡。
- 通过丰富的路由规则、重试、故障转移和故障注入对流量行为进行细粒度控制。
- 可插拔的策略层和配置 API,支持访问控制、速率限制和配额。
- 集群内(包括集群的入口和出口)所有流量的自动化度量、日志记录和追踪。
- 在具有强大的基于身份验证和授权的集群中实现安全的服务间通信。
Istio 为可扩展性而设计,可以满足不同的部署需求。
1.5 Istio 是如何诞生的?
Istio 项目由 Google 和 IBM 的团队与 Lyft 的 Envoy 团队合作启动。它已经完全在 GitHub 上公开开发。
1.6 为什么我想用 ISTIO?
按照传统做法,Istio 处理的大多数逻辑都是直接构建到应用程序中的。在一组服务中,要管理更新这块通信逻辑是一个繁重的任务。Istio 提供了一个基础架构级的方案来解决管理服务通信问题。
应用开发者 :利用 Istio 管理服务间的流量,开发者就可以专注于业务逻辑开发和快速迭代新特性。
服务运维者 :Istio 可以从一个中心控制点进行策略控制和网格监控,而不依赖应用程序的发展。因此,运维者可以通过简化的管理平面确保持续的策略控制。
1.7 目前Istio支持哪些部署环境?
Istio 是设计和构建为平台无关的。对于 1.8 版本,Istio 支持运行容器编排的平台环境,比如 Kubernetes (1.16, 1.17, 1.18, 1.19) 和 有 Consul 的 Nomad。
1.8 架构
Istio 服务网格从逻辑上分为数据平面和控制平面。
- 数据平面 由一组智能代理(Envoy)组成,被部署为 sidecar。这些代理负责协调和控制微服务之间的所有网络通信。他们还收集和报告所有网格流量的遥测数据。
- 控制平面 管理并配置代理来进行流量路由。
下图展示了组成每个平面的不同组件:
Istio 中的流量分为数据平面流量和控制平面流量。
- 数据平面流量:是指工作负载的业务逻辑发送和接收的消息。
- 控制平面流量:是指在 Istio 组件之间发送的配置和控制消息用来编排网格的行为。Istio 中的流量管理特指数据平面流量。
1.8.1 组件
1.8.1.1 Envoy
Istio 使用 Envoy 代理的扩展版本。Envoy 是用 C++ 开发的高性能代理,用于协调服务网格中所有服务的入站和出站流量。Envoy 代理是唯一与数据平面流量交互的 Istio 组件。
Envoy 代理被部署为服务的 sidecar,在逻辑上为服务增加了 Envoy 的许多内置特性,例如:
- 动态服务发现
- 负载均衡
- TLS 终端
- HTTP/2 与 gRPC 代理
- 熔断器
- 健康检查
- 基于百分比流量分割的分阶段发布
- 故障注入
- 丰富的指标
这种 sidecar 部署允许 Istio 提取大量关于流量行为的信号作为属性。Istio 可以使用这些属性来实施策略决策,并将其发送到监视系统以提供有关整个网格行为的信息。
sidecar 代理模型还允许您向现有的部署添加 Istio 功能,而不需要重新设计架构或重写代码。
由 Envoy 代理启用的一些 Istio 的功能和任务包括:
- 流量控制功能:通过丰富的 HTTP、gRPC、WebSocket 和 TCP 流量路由规则来执行细粒度的流量控制。
- 网络弹性特性:重试设置、故障转移、熔断器和故障注入。
- 安全性和身份验证特性:执行安全性策略以及通过配置 API 定义的访问控制和速率限制。
- 基于 WebAssembly 的可插拔扩展模型,允许通过自定义策略实施和生成网格流量的遥测。
1.8.1.2 Pilot
Pilot 为 Envoy sidecar 提供服务发现、用于智能路由的流量管理功能(例如,A/B 测试、金丝雀发布等)以及弹性功能(超时、重试、熔断器等)。
Pilot 将控制流量行为的高级路由规则转换为特定于环境的配置,并在运行时将它们传播到 sidecar。Pilot 将特定于平台的服务发现机制抽象出来,并将它们合成为任何符合 Envoy API 的 sidecar 都可以使用的标准格式。
下图展示了平台适配器和 Envoy 代理如何交互。
- 平台启动一个服务的新实例,该实例通知其平台适配器。
- 平台适配器使用 Pilot 抽象模型注册实例。
- Pilot 将流量规则和配置派发给 Envoy 代理,来传达此次更改。
这种松耦合允许 Istio 在 Kubernetes、Consul 或 Nomad 等多种环境中运行,同时维护相同的 operator 接口来进行流量管理。
1.8.1.3 Citadel
Citadel 通过内置的身份和证书管理,可以支持强大的服务到服务以及最终用户的身份验证。您可以使用 Citadel 来升级服务网格中的未加密流量。使用 Citadel,operator 可以执行基于服务身份的策略,而不是相对不稳定的 3 层或 4 层网络标识。
1.8.1.4 Galley
Galley 是 Istio 的配置验证、提取、处理和分发组件。它负责将其余的 Istio 组件与从底层平台(例如 Kubernetes)获取用户配置的细节隔离开来。
1.8.2 设计目标
几个关键的设计目标形成了 Istio 的架构。这些目标对于使系统能够大规模和高性能地处理服务是至关重要的。
- 透明度最大化:为了采用 Istio,运维人员或开发人员需要做尽可能少的工作,才能从系统中获得真正的价值。为此,Istio 可以自动将自己注入到服务之间的所有网络路径中。Istio 使用 sidecar 代理来捕获流量,并在可能的情况下,在不更改已部署的应用程序代码的情况下,自动对网络层进行配置,以实现通过这些代理来路由流量。在 Kubernetes 中,代理被注入到pods中,通过编写‘iptables’规则来捕获流量。一旦 sidecar 代理被注入以及流量路由被编程,Istio 就可以协调所有的流量。这个原则也适用于性能。当将 Istio 应用于部署时,运维人员会看到所提供功能的资源成本增加地最小。组件和 API 的设计必须考虑到性能和可伸缩性。
- 可扩展性:随着运维人员和开发人员越来越依赖于 Istio 提供的功能,系统必须随着他们的需求而增长。当我们继续添加新特性时,最大的需求是扩展策略系统的能力,与其他策略和控制源的集成,以及将关于网格行为的信号传播到其他系统进行分析的能力。策略运行时支持用于接入其他服务的标准扩展机制。此外,它允许扩展其词汇表,允许根据网格生成的新信号执行策略。
- 可移植性:使用 Istio 的生态系统在许多方面都有所不同。Istio 必须在任何云环境或本地环境中通过最小的努力就能运行起来。将基于 Istio 的服务移植到新环境的任务必须是容易实现的。使用 Istio,您可以操作部署到多个环境中的单个服务。例如,可以在多个云上部署来实现冗余。
- 策略一致性:将策略应用于服务之间的 API 调用提供了对网格行为的大量控制。然而,将策略应用在区别于 API 层上的资源也同样重要。例如,在机器学习训练任务消耗的 CPU 数量上应用配额比在发起任务的请求调用上应用配额更有用。为此,Istio 使用自己的 API 将策略系统维护为一个独立的服务,而不是将策略系统集成到 sidecar 代理中,从而允许服务根据需要直接与之集成。
2. 核心特性
Istio 以统一的方式提供了许多跨服务网络的关键功能:
2.1 流量管理
Istio 简单的规则配置和流量路由允许您控制服务之间的流量和 API 调用过程。Istio 简化了服务级属性(如熔断器、超时和重试)的配置,并且让它轻而易举的执行重要的任务(如 A/B 测试、金丝雀发布和按流量百分比划分的分阶段发布)。
有了更好的对流量的可视性和开箱即用的故障恢复特性,您就可以在问题产生之前捕获它们,无论面对什么情况都可以使调用更可靠,网络更健壮。
Istio 的流量管理模型源于和服务一起部署的 Envoy 代理。网格内服务发送和接收的所有流量(data plane流量)都经由 Envoy 代理,这让控制网格内的流量变得异常简单,而且不需要对服务做任何的更改。
Envoy 是在 Istio 里使用的高性能代理,用于为所有服务网格里的服务调度进出的流量。
data plane(数据平面)是网格的一部分,直接控制工作负载实例之间的通信。 Istio 的数据平面使用智能 Envoy 代理部署成 sidecar 去调节和控制服务网格中发送和接受的流量。
2.1.1 Istio 流量管理介绍
为了在网格中导流,Istio 需要知道所有的 endpoint 在哪和属于哪个服务。为了定位到service registry(服务注册中心),Istio 会连接到一个服务发现系统。例如,如果您在 Kubernetes 集群上安装了 Istio,那么它将自动检测该集群中的服务和 endpoint。
使用此服务注册中心,Envoy 代理可以将流量定向到相关服务。大多数基于微服务的应用程序,每个服务的工作负载都有多个实例来处理流量,称为负载均衡池。默认情况下,Envoy 代理基于轮询调度模型在服务的负载均衡池内分发流量,按顺序将请求发送给池中每个成员,一旦所有服务实例均接收过一次请求后,重新回到第一个池成员。
Istio 基本的服务发现和负载均衡能力为您提供了一个可用的服务网格,但它能做到的远比这多的多。在许多情况下,您可能希望对网格的流量情况进行更细粒度的控制。作为 A/B 测试的一部分,您可能想将特定百分比的流量定向到新版本的服务,或者为特定的服务实例子集应用不同的负载均衡策略。您可能还想对进出网格的流量应用特殊的规则,或者将网格的外部依赖项添加到服务注册中心。通过使用 Istio 的流量管理 API 将流量配置添加到 Istio,就可以完成所有这些甚至更多的工作。
和其他 Istio 配置一样,这些 API 也使用 Kubernetes 的自定义资源定义(CRDs)来声明,您可以像示例中看到的那样使用 YAML 进行配置。
Service registry:Istio 维护了一个内部服务注册表 (service registry),它包含在服务网格中运行的一组服务及其相应的服务 endpoints。Istio 使用服务注册表生成 Envoy 配置。
Istio 不提供服务发现,尽管大多数服务都是通过 Pilot adapter 自动加入到服务注册表里的,而且这反映了底层平台(Kubernetes、Consul、plain DNS)的已发现的服务。还有就是,可以使用
ServiceEntry
配置手动进行注册。自定义资源定义 (CRD) 是默认的 Kubernetes API 扩展。Istio 使用 Kubernetes CRD API 来配置,即使是非 Kubernetes 环境下部署的 Istio。
2.1.2 虚拟服务
虚拟服务(Virtual Service) 和目标规则(Destination Rule) 是 Istio 流量路由功能的关键拼图。虚拟服务让您配置如何在服务网格内将请求路由到服务,这基于 Istio 和平台提供的基本的连通性和服务发现能力。每个虚拟服务包含一组路由规则,Istio 按顺序评估它们,Istio 将每个给定的请求匹配到虚拟服务指定的实际目标地址。您的网格可以有多个虚拟服务,也可以没有,取决于您的使用场景。
2.1.2.1 为什么使用虚拟服务?
虚拟服务在增强 Istio 流量管理的灵活性和有效性方面,发挥着至关重要的作用,通过对客户端请求的目标地址与真实响应请求的目标工作负载进行解耦来实现。虚拟服务同时提供了丰富的方式,为发送至这些工作负载的流量指定不同的路由规则。
为什么这如此有用?就像在介绍中所说,如果没有虚拟服务,Envoy 会在所有的服务实例中使用轮询的负载均衡策略分发请求。您可以用您对工作负载的了解来改善这种行为。例如,有些可能代表不同的版本。这在 A/B 测试中可能有用,您可能希望在其中配置基于不同服务版本的流量百分比路由,或指引从内部用户到特定实例集的流量。
使用虚拟服务,您可以为一个或多个主机名指定流量行为。在虚拟服务中使用路由规则,告诉 Envoy 如何发送虚拟服务的流量到适当的目标。路由目标地址可以是同一服务的不同版本,也可以是完全不同的服务。
一个典型的用例是将流量发送到被指定为服务子集的服务的不同版本。客户端将虚拟服务视为一个单一实体,将请求发送至虚拟服务主机,然后 Envoy 根据虚拟服务规则把流量路由到不同的版本。例如,“20% 的调用转到新版本”或“将这些用户的调用转到版本 2”。这允许您创建一个金丝雀发布,逐步增加发送到新版本服务的流量百分比。流量路由完全独立于实例部署,这意味着实现新版本服务的实例可以根据流量的负载来伸缩,完全不影响流量路由。相比之下,像 Kubernetes 这样的容器编排平台只支持基于实例缩放的流量分发,这会让情况变得复杂。
2.1.2.1.1 小结
虚拟服务可以让您:
- 通过单个虚拟服务处理多个应用程序服务。如果您的网格使用 Kubernetes,可以配置一个虚拟服务处理特定命名空间中的所有服务。映射单一的虚拟服务到多个“真实”服务特别有用,可以在不需要客户适应转换的情况下,将单体应用转换为微服务构建的复合应用系统。您的路由规则可以指定为“对这些
monolith.com
的 URI 调用转到microservice A
”等等。 - 和网关整合并配置流量规则来控制出入流量。
在某些情况下,您还需要配置目标规则来使用这些特性,因为这是指定服务子集的地方。在一个单独的对象中指定服务子集和其它特定目标策略,有利于在虚拟服务之间更简洁地重用这些规则。
2.1.2.2 虚拟服务示例
下面的虚拟服务根据请求是否来自特定的用户,把它们路由到服务的不同版本。
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
2.1.2.2.1 hosts 字段
使用 hosts
字段列举虚拟服务的主机——即用户指定的目标或是路由规则设定的目标。这是客户端向服务发送请求时使用的一个或多个地址。
hosts:
- reviews
虚拟服务主机名可以是 IP 地址、DNS 名称,或者依赖于平台的一个简称(例如 Kubernetes 服务的短名称),隐式或显式地指向一个完全限定域名(FQDN)。您也可以使用通配符(“*”)前缀,让您创建一组匹配所有服务的路由规则。虚拟服务的 hosts
字段实际上不必是 Istio 服务注册的一部分,它只是虚拟的目标地址。这让您可以为没有路由到网格内部的虚拟主机建模。
2.1.2.2.2 路由规则
在 http
字段包含了虚拟服务的路由规则,用来描述匹配条件和路由行为,它们把 HTTP/1.1、HTTP2 和 gRPC 等流量发送到 hosts 字段指定的目标(您也可以用 tcp
和 tls
片段为 TCP 和未终止的 TLS 流量设置路由规则)。一个路由规则包含了指定的请求要流向哪个目标地址,具有 0 或多个匹配条件,取决于您的使用场景。
2.1.2.2.2.1 匹配条件
示例中的第一个路由规则有一个条件,因此以 match
字段开始。在本例中,您希望此路由应用于来自 ”jason“ 用户的所有请求,所以使用 headers
、end-user
和 exact
字段选择适当的请求。
- match:
- headers:
end-user:
exact: jason
2.1.2.2.2.2 Destination
route 部分的 destination
字段指定了符合此条件的流量的实际目标地址。与虚拟服务的 hosts
不同,destination 的 host 必须是存在于 Istio 服务注册中心的实际目标地址,否则 Envoy 不知道该将请求发送到哪里。可以是一个有代理的服务网格,或者是一个通过服务入口被添加进来的非网格服务。本示例运行在 Kubernetes 环境中,host 名为一个 Kubernetes 服务名:
route:
- destination:
host: reviews
subset: v2
destination 片段还指定了 Kubernetes 服务的子集,将符合此规则条件的请求转入其中。在本例中子集名称是 v2。您可以在目标规则章节中看到如何定义服务子集。
2.1.2.2.3 路由规则优先级
路由规则按从上到下的顺序选择,虚拟服务中定义的第一条规则有最高优先级。本示例中,不满足第一个路由规则的流量均流向一个默认的目标,该目标在第二条规则中指定。因此,第二条规则没有 match 条件,直接将流量导向 v3 子集。
- route:
- destination:
host: reviews
subset: v3
我们建议提供一个默认的“无条件”或基于权重的规则(见下文)作为每一个虚拟服务的最后一条规则,如案例所示,从而确保流经虚拟服务的流量至少能够匹配一条路由规则。
2.1.2.3 路由规则的更多内容
正如上面所看到的,路由规则是将特定流量子集路由到指定目标地址的强大工具。您可以在流量端口、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
参考。
2.1.3 目标规则
与虚拟服务一样,目标规则也是 Istio 流量路由功能的关键部分。您可以将虚拟服务视为将流量如何路由到给定目标地址,然后使用目标规则来配置该目标的流量。在评估虚拟服务路由规则之后,目标规则将应用于流量的“真实”目标地址。
特别是,您可以使用目标规则来指定命名的服务子集,例如按版本为所有给定服务的实例分组。然后可以在虚拟服务的路由规则中使用这些服务子集来控制到服务不同实例的流量。
目标规则还允许您在调用整个目的地服务或特定服务子集时定制 Envoy 的流量策略,比如您喜欢的负载均衡模型、TLS 安全模式或熔断器设置。在目标规则参考中可以看到目标规则选项的完整列表。
2.1.3.1 负载均衡选项
默认情况下,Istio 使用轮询的负载均衡策略,实例池中的每个实例依次获取请求。Istio 同时支持如下的负载均衡模型,可以在 DestinationRule
中为流向某个特定服务或服务子集的流量指定这些模型。
- 随机:请求以随机的方式转到池中的实例。
- 权重:请求根据指定的百分比转到实例。
- 最少请求:请求被转到最少被访问的实例。
2.1.3.2 目标规则示例
在下面的示例中,目标规则为 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
上的默认策略,为 v1
和 v3
子集设置了一个简单的随机负载均衡器。在 v2
策略中,轮询负载均衡器被指定在相应的子集字段上。
2.1.4 网关
使用网关为网格来管理入站和出站流量,可以让您指定要进入或离开网格的流量。网关配置被用于运行在网格边界的独立 Envoy 代理,而不是服务工作负载的 sidecar 代理。
与 Kubernetes Ingress API 这种控制进入系统流量的其他机制不同,Istio 网关让您充分利用流量路由的强大能力和灵活性。您可以这么做的原因是 Istio 的网关资源可以配置 4-6 层的负载均衡属性,如对外暴露的端口、TLS 设置等。作为替代应用层流量路由(L7)到相同的 API 资源,您绑定了一个常规的 Istio 虚拟服务到网关。这让您可以像管理网格中其他数据平面的流量一样去管理网关流量。
网关主要用于管理进入的流量,但您也可以配置出口网关。出口网关让您为离开网格的流量配置一个专用的出口节点,这可以限制哪些服务可以或应该访问外部网络,或者启用出口流量安全控制为您的网格添加安全性。您也可以使用网关配置一个纯粹的内部代理。
Istio 提供了一些预先配置好的网关代理部署(istio-ingressgateway
和 istio-egressgateway
)供您使用——如果使用我们的演示安装它们都已经部署好了;如果使用默认或 sds 配置文件则只部署了入口网关。可以将您自己的网关配置应用到这些部署或配置您自己的网关代理。
2.1.4.1 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
然后就可以为出口流量配置带有路由规则的虚拟服务。
2.1.5 服务入口
使用服务入口(Service Entry) 来添加一个入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样。配置服务入口允许您管理运行在网格外的服务的流量,它包括以下几种能力:
- 为外部目标 redirect 和转发请求,例如来自 web 端的 API 调用,或者流向遗留老系统的服务。
- 为外部目标定义重试、超时和故障注入策略。
- 添加一个运行在虚拟机的服务来扩展您的网格。
- 从逻辑上添加来自不同集群的服务到网格,在 Kubernetes 上实现一个多集群 Istio 网格。
您不需要为网格服务要使用的每个外部服务都添加服务入口。默认情况下,Istio 配置 Envoy 代理将请求传递给未知服务。但是,您不能使用 Istio 的特性来控制没有在网格中注册的目标流量。
2.1.5.1 服务入口示例
下面示例的 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
2.1.6 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/*"
2.1.7 网络弹性和测试
除了为您的网格导流之外,Istio 还提供了可选的故障恢复和故障注入功能,您可以在运行时动态配置这些功能。使用这些特性可以让您的应用程序运行稳定,确保服务网格能够容忍故障节点,并防止局部故障级联影响到其他节点。
2.1.7.1 超时
超时是 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
2.1.7.2 重试
重试设置指定如果初始调用失败,Envoy 代理尝试连接服务的最大次数。通过确保调用不会因为临时过载的服务或网络等问题而永久失败,重试可以提高服务可用性和应用程序的性能。重试之间的间隔(25ms+)是可变的,并由 Istio 自动确定,从而防止被调用服务被请求淹没。HTTP 请求的默认重试行为是在返回错误之前重试两次。
与超时一样,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
2.1.7.3 熔断器
熔断器是 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
2.1.7.4 故障注入
在配置了网络,包括故障恢复策略之后,可以使用 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
2.1.7.5 故障恢复
Istio 故障恢复功能对应用程序来说是完全透明的。在返回响应之前,应用程序不知道 Envoy sidecar 代理是否正在处理被调用服务的故障。这意味着,如果在应用程序代码中设置了故障恢复策略,那么您需要记住这两个策略都是独立工作的,否则会发生冲突。例如,假设您设置了两个超时,一个在虚拟服务中配置,另一个在应用程序中配置。应用程序为服务的 API 调用设置了 2 秒超时。而您在虚拟服务中配置了一个 3 秒超时和重试。在这种情况下,应用程序的超时会先生效,因此 Envoy 的超时和重试尝试会失效。
虽然 Istio 故障恢复特性提高了网格中服务的可靠性和可用性,但应用程序必须处理故障或错误并采取适当的回退操作。例如,当负载均衡中的所有实例都失败时,Envoy 返回一个HTTP 503
代码。应用程序必须实现回退逻辑来处理HTTP 503
错误代码。
2.2 扩展性
WebAssembly 是一种沙盒技术,可以用于扩展 Istio 代理(Envoy)的能力。Proxy-Wasm 沙盒 API 取代了 Mixer 作为 Istio 主要的扩展机制。在 Istio 1.6 中将会为 Proxy-Wasm 插件提供一种统一的配置 API。
WebAssembly 沙盒的目标:
- 效率 - 这是一种低延迟,低 CPU 和内存开销的扩展机制。
- 功能 - 这是一种可以执行策略,收集遥测数据和执行有效荷载变更的扩展机制。
- 隔离 - 一个插件中程序的错误或是崩溃不会影响其它插件。
- 配置 - 插件使用与其它 Istio API 一致的 API 进行配置。可以动态的配置扩展。
- 运维 - 扩展可以以仅日志,故障打开或者故障关闭的方式进行访问和部署。
- 扩展开发者 - 可以用多种编程语言编写。
2.2.1 高级架构
Istio 扩展(Proxy-Wasm 插件)有几个组成部分:
- 过滤器服务提供商接口 用于为过滤器构建 Proxy-Wasm 插件。
- 沙盒 在 Envoy 中嵌入 V8 Wasm 运行时。
- 主机 API 用于处理请求头,尾和元数据。
- 调出 API 针对 gRPC 和 HTTP 请求。
- 统计和记录 API 用于度量统计和监控。
2.3 安全
Istio 的安全特性解放了开发人员,使其只需要专注于应用程序级别的安全。Istio 提供了底层的安全通信通道,并为大规模的服务通信管理认证、授权和加密。有了 Istio,服务通信在默认情况下就是受保护的,可以让您在跨不同协议和运行时的情况下实施一致的策略——而所有这些都只需要很少甚至不需要修改应用程序。
Istio 是独立于平台的,可以与 Kubernetes(或基础设施)的网络策略一起使用。但它更强大,能够在网络和应用层面保护 pod 到 pod 或者服务到服务之间的通信。
Pod 中包含了一个或多个共享存储和网络的容器 (例如 Docker 容器), 以及如何运行容器的规范。 Pod 是 Istio 的 Kubernetes 部署中的一个工作负载实例。
将单一应用程序分解为微服务可提供各种好处,包括更好的灵活性、可伸缩性以及服务复用的能力。但是,微服务也有特殊的安全需求:
- 为了抵御中间人攻击,需要流量加密。
- 为了提供灵活的服务访问控制,需要双向 TLS 和细粒度的访问策略。
- 要确定谁在什么时候做了什么,需要审计工具。
Istio Security 尝试提供全面的安全解决方案来解决所有这些问题。本页概述了如何使用 Istio 的安全功能来保护您的服务,无论您在何处运行它们。特别是 Istio 安全性可以缓解针对您的数据、端点、通信和平台的内部和外部威胁。
Istio 安全功能提供强大的身份,强大的策略,透明的 TLS 加密,认证,授权和审计(AAA)工具来保护你的服务和数据。Istio 安全的目标是:
- 默认安全:应用程序代码和基础设施无需更改
- 深度防御:与现有安全系统集成以提供多层防御
- 零信任网络:在不受信任的网络上构建安全解决方案
2.3.1 高级架构
Istio 中的安全性涉及多个组件:
- 用于密钥和证书管理的证书颁发机构(CA)
- 配置 API 服务器分发给代理:
- Sidecar 和边缘代理作为 Policy Enforcement Points(PEPs) 以保护客户端和服务器之间的通信安全
- 一组 Envoy 代理扩展,用于管理遥测和审计
控制面处理来自 API server 的配置,并且在数据面中配置 PEPs。PEPs 用 Envoy 实现。下图显示了架构。
2.3.2 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 服务帐户。自定义服务帐户引用现有服务帐户,就像客户的身份目录管理的身份一样。
2.3.3 公钥基础设施 (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)**来实现的,具体流程如下:
- CA 提供 gRPC 服务以接受证书签名请求(CSRs)。
- Envoy 通过 Envoy 秘密发现服务(SDS)API 发送证书和密钥请求。
- 在收到 SDS 请求后,
istio-agent
创建私钥和 CSR,然后将 CSR 及其凭据发送到 Istio CA 进行签名。 - CA 验证 CSR 中携带的凭据并签署 CSR 以生成证书。
Istio-agent
通过 Envoy SDS API 将私钥和从 Istio CA 收到的证书发送给 Envoy。- 上述 CSR 过程会周期性地重复,以处理证书和密钥轮换。
2.3.4 认证
Istio 提供两种类型的认证:
- Peer authentication:用于服务到服务的认证,以验证进行连接的客户端。Istio 提供双向 TLS 作为传输认证的全栈解决方案,无需更改服务代码就可以启用它。这个解决方案:
- 为每个服务提供强大的身份,表示其角色,以实现跨群集和云的互操作性。
- 保护服务到服务的通信。
- 提供密钥管理系统,以自动进行密钥和证书的生成,分发和轮换。
- Request authentication:用于最终用户认证,以验证附加到请求的凭据。 Istio 使用 JSON Web Token(JWT)验证启用请求级认证,并使用自定义认证实现或任何 OpenID Connect 的认证实现(例如下面列举的)来简化的开发人员体验。
在所有情况下,Istio 都通过自定义 Kubernetes API 将认证策略存储在 Istio config store
。Istiod 使每个代理保持最新状态,并在适当时提供密钥。此外,Istio 的认证机制支持宽容模式(permissive mode),以帮助您了解策略更改在实施之前如何影响您的安全状况。
Istiod : The Istiod component is the consolidated monolithic control plane binary that encapsulates the functions of Pilot, Citadel, Mixer, and Galley.
2.3.4.1 双向 TLS 认证
Istio 通过客户端和服务器端 PEPs 建立服务到服务的通信通道,PEPs 被实现为Envoy 代理。当一个工作负载使用双向 TLS 认证向另一个工作负载发送请求时,该请求的处理方式如下:
- Istio 将出站流量从客户端重新路由到客户端的本地 sidecar Envoy。
- 客户端 Envoy 与服务器端 Envoy 开始双向 TLS 握手。在握手期间,客户端 Envoy 还做了安全命名检查,以验证服务器证书中显示的服务帐户是否被授权运行目标服务。
- 客户端 Envoy 和服务器端 Envoy 建立了一个双向的 TLS 连接,Istio 将流量从客户端 Envoy 转发到服务器端 Envoy。
- 授权后,服务器端 Envoy 通过本地 TCP 连接将流量转发到服务器服务。
2.3.4.1.1 宽容模式
Istio 双向 TLS 具有一个宽容模式(permissive mode),允许服务同时接受纯文本流量和双向 TLS 流量。这个功能极大的提升了双向 TLS 的入门体验。
启用宽容模式后,服务可以同时接受纯文本和双向 TLS 流量。这个模式为入门提供了极大的灵活性。服务中安装的 Istio sidecar 立即接受双向 TLS 流量而不会打断现有的纯文本流量。因此,运维人员可以逐步安装和配置客户端 Istio sidecar 发送双向 TLS 流量。一旦客户端配置完成,运维人员便可以将服务端配置为仅 TLS 模式。更多信息请访问双向 TLS 迁移向导。
2.3.4.1.2 安全命名
服务器身份(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 劫持。
2.3.4.2 认证架构
您可以使用 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 将两种类型的身份验证以及凭证中的其他声明(如果适用)输出到下一层:授权。
2.3.4.3 认证策略
本节中提供了更多 Istio 认证策略方面的细节。正如认证架构中所说的,认证策略是对服务收到的请求生效的。要在双向 TLS 中指定客户端认证策略,需要在 DetinationRule
中设置 TLSSettings
。TLS 设置参考文档中有更多这方面的信息。
和其他的 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
2.3.4.3.1 策略存储
Istio 将网格范围的策略存储在根命名空间。这些策略使用一个空的 selector 适用于网格中的所有工作负载。具有名称空间范围的策略存储在相应的名称空间中。它们仅适用于其命名空间内的工作负载。如果你配置了 selector
字段,则认证策略仅适用于与您配置的条件匹配的工作负载。
Peer 和 request 认证策略用 kind 字段区分,分别是 PeerAuthentication
和 RequestAuthentication
。
2.3.4.3.2 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 按照以下顺序为每个工作负载应用最窄的匹配策略:
- 特定于工作负载的
- 命名空间范围
- 网格范围
Istio 可以将所有匹配的 request 认证策略组合起来,就像它们来自单个 request 认证策略一样。因此,您可以在网格或名称空间中配置多个网格范围或命名空间范围的策略。但是,避免使用多个网格范围或命名空间范围的 request 认证策略仍然是一个好的实践。
2.3.4.3.3 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
2.3.4.3.4 Request authentication
Request 认证策略指定验证 JSON Web Token(JWT)所需的值。 这些值包括:
- token 在请求中的位置
- 请求的 issuer
- 公共 JSON Web Key Set(JWKS)
Istio 会根据 request 认证策略中的规则检查提供的令牌(如果已提供),并拒绝令牌无效的请求。当请求不带有令牌时,默认情况下将接受它们。要拒绝没有令牌的请求,请提供授权规则,该规则指定对特定操作(例如,路径或操作)的限制。
如果 Request 认证策略使用唯一的位置,则它们可以指定多个JWT。当多个策略与工作负载匹配时,Istio 会将所有规则组合起来,就好像它们被指定为单个策略一样。此行为对于开发接受来自不同 JWT 提供者的工作负载时很有用。但是,不支持具有多个有效 JWT 的请求,因为此类请求的输出主体未定义。
2.3.4.3.5 Principals
使用 peer 认证策略和双向 TLS 时,Istio 将身份从 peer 认证提取到 source.principal
中。同样,当您使用 request 认证策略时,Istio 会将 JWT 中的身份赋值给 request.auth.principal
。使用这些 principals 设置授权策略和作为遥测的输出。
2.3.4.4 更新认证策略
您可以随时更改认证策略,Istio 几乎实时将新策略推送到工作负载。但是,Istio 无法保证所有工作负载都同时收到新政策。以下建议有助于避免在更新认证策略时造成干扰:
- 将 peer 认证策略的模式从
DISABLE
更改为STRICT
时,请使用PERMISSIVE
模式来过渡,反之亦然。当所有工作负载成功切换到所需模式时,您可以将策略应用于最终模式。您可以使用 Istio 遥测技术来验证工作负载已成功切换。 - 将 request 认证策略从一个 JWT 迁移到另一个 JWT 时,将新 JWT 的规则添加到该策略中,而不删除旧规则。这样,工作负载接受两种类型的 JWT,当所有流量都切换到新的 JWT 时,您可以删除旧规则。但是,每个 JWT 必须使用不同的位置。
2.3.5 授权
Istio 的授权功能为网格中的工作负载提供网格、命名空间和工作负载级别的访问控制。这种控制层级提供了以下优点:
- 工作负载间和最终用户到工作负载的授权。
- 一个简单的 API:它包括一个单独的并且很容易使用和维护的
AuthorizationPolicy
CRD。 - 灵活的语义:运维人员可以在 Istio 属性上定义自定义条件,并使用 DENY 和 ALLOW 动作。
- 高性能:Istio 授权是在 Envoy 本地强制执行的。
- 高兼容性:原生支持 HTTP、HTTPS 和 HTTP2,以及任意普通 TCP 协议。
2.3.5.1 授权架构
每个 Envoy 代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果 ALLOW
或 DENY
。 运维人员使用 .yaml
文件指定 Istio 授权策略。
2.3.5.2 隐式启用
您无需显式启用 Istio 的授权功能。只需将授权策略应用于工作负载即可实施访问控制。对于未应用授权策略的工作负载,Istio 不会执行访问控制,放行所有请求。
授权策略支持 ALLOW
和 DENY
动作。 拒绝策略优先于允许策略。如果将任何允许策略应用于工作负载,则默认情况下将拒绝对该工作负载的访问,除非策略中的规则明确允许。当您将多个授权策略应用于相同的工作负载时,Istio 会累加地应用它们。
2.3.5.3 授权策略
要配置授权策略,请创建一个 AuthorizationPolicy
自定义资源。 一个授权策略包括选择器(selector),动作(action) 和一个规则(rules)列表:
selector
字段指定策略的目标action
字段指定允许还是拒绝请求rules
指定何时触发动作rules
下的from
字段指定请求的来源rules
下的to
字段指定请求的操作rules
下的when
字段指定应用规则所需的条件
以下示例显示了一个授权策略,该策略允许两个源(服务帐号 cluster.local/ns/default/sa/sleep
和命名空间 dev
),在使用有效的 JWT 令牌发送请求时,可以访问命名空间 foo 中的带有标签 app: httpbin
和 version: 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 首先评估拒绝策略,以确保允许策略不能绕过拒绝策略
2.3.5.3.1 策略目标
您可以通过 metadata/namespace
字段和可选的 selector
字段来指定策略的范围或目标。metadata/namespace
告诉该策略适用于哪个命名空间。如果将其值设置为根名称空间,则该策略将应用于网格中的所有名称空间。根命名空间的值是可配置的,默认值为 istio-system
。如果设置为任何其他名称空间,则该策略仅适用于指定的名称空间。
您可以使用 selector
字段来进一步限制策略以应用于特定工作负载。selector
使用标签选择目标工作负载。selector
包含 {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"]
2.3.5.3.2 值匹配
授权策略中的大多数字段都支持以下所有匹配模式:
- 完全匹配:即完整的字符串匹配。
- 前缀匹配:
"*"
结尾的字符串。例如,"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"]
2.3.5.3.3 排除匹配
为了匹配诸如 when
字段中的 notValues
,source
字段中的 notIpBlocks
,to
字段中的 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: ["*"]
2.3.5.3.4 全部允许和默认全部拒绝授权策略
以下示例显示了一个简单的 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:
{}
2.3.5.3.5 自定义条件
您还可以使用 when
部分指定其他条件。 例如,下面的 AuthorizationPolicy
定义包括以下条件:request.headers [version]
是 v1
或 v2
。 在这种情况下,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
值。
2.3.5.3.6 认证与未认证身份
如果要使工作负载可公开访问,则需要将 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"]
2.3.5.4 在普通 TCP 协议上使用 Istio 授权
Istio 授权支持工作负载使用任意普通 TCP 协议,如 MongoDB。 在这种情况下,您可以按照与 HTTP 工作负载相同的方式配置授权策略。 不同之处在于某些字段和条件仅适用于 HTTP 工作负载。 这些字段包括:
- 授权策略对象
source
部分中的request_principals
字段 - 授权策略对象
operation
部分中的hosts
、methods
和paths
字段
条件页面中列出了支持的条件。
如果您在授权策略中对 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"]
2.3.5.5 对双向 TLS 的依赖
Istio 使用双向 TLS 将某些信息从客户端安全地传递到服务器。在使用授权策略中的以下任何字段之前,必须先启用双向 TLS:
source
部分下的principals
字段source
部分下的namespaces
字段source.principal
自定义条件source.namespace
自定义条件connection.sni
自定义条件
如果您不使用授权策略中的上述任何字段,则双向 TLS 不是必须的。
2.4 可观察性
Istio 健壮的追踪、监控和日志特性让您能够深入的了解服务网格部署。通过 Istio 的监控能力,可以真正的了解到服务的性能是如何影响上游和下游的;而它的定制 Dashboard 提供了对所有服务性能的可视化能力,并让您看到它如何影响其他进程。
Istio 的 Mixer 组件负责策略控制和遥测数据收集。它提供了后端抽象和中介,将一部分 Istio 与后端的基础设施实现细节隔离开来,并为运维人员提供了对网格与后端基础实施之间交互的细粒度控制。
所有这些特性都使您能够更有效地设置、监控和加强服务的 SLO(服务等级目标)。当然,底线是您可以快速有效地检测到并修复出现的问题。
Istio 为网格内所有的服务通信生成详细的遥测数据。这种遥测技术提供了服务行为的可观察性,使运维人员能够排查故障、维护和优化应用程序,而不会给服务的开发人员带来任何额外的负担。通过 Istio,运维人员可以全面了解到受监控的服务如何与其他服务以及 Istio 组件进行交互。
Istio 生成以下类型的遥测数据,以提供对整个服务网格的可观察性:
- 指标。Istio 基于 4 个监控的黄金标识(延迟、流量、错误、饱和)生成了一系列服务指标。Istio 还为网格控制平面提供了更详细的指标。除此以外还提供了一组默认的基于这些指标的网格监控仪表板。
- 分布式追踪。Istio 为每个服务生成分布式追踪 span,运维人员可以理解网格内服务的依赖和调用流程。
- 访问日志。当流量流入网格中的服务时,Istio 可以生成每个请求的完整记录,包括源和目标的元数据。此信息使运维人员能够将服务行为的审查控制到单个工作负载实例的级别。
2.4.1 指标
指标(Metric)提供了一种以聚合的方式监控和理解行为的方法。
为了监控服务行为,Istio 为服务网格中所有出入的服务流量都生成了指标。这些指标提供了关于行为的信息,例如总流量数、错误率和请求响应时间。
除了监控网格中服务的行为外,监控网格本身的行为也很重要。Istio 组件可以导出自身内部行为的指标,以提供对网格控制平面的功能和健康情况的洞察能力。
Istio 指标收集由运维人员配置来驱动。运维人员决定如何以及何时收集指标,以及指标本身的详细程度。这使得它能够灵活地调整指标收集来满足个性化需求。
2.4.1.1 代理级别指标
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
2.4.1.2 服务级别指标
除了代理级别指标之外,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
2.4.1.3 控制平面指标
每一个 Istio 的组件(Pilot、Galley、Mixer)都提供了对自身监控指标的集合。这些指标容许监控 Istio 自己的行为(这与网格内的服务有所不同)。
有关这些被维护指标的更多信息,请查看每个组件的参考文档:
2.4.2 分布式追踪
分布式追踪通过监控流经网格的单个请求,提供了一种监控和理解行为的方法。追踪使网格的运维人员能够理解服务的依赖关系以及在服务网格中的延迟源。
Istio 支持通过 Envoy 代理进行分布式追踪。代理自动为其应用程序生成追踪 span,只需要应用程序转发适当的请求上下文即可。
Istio 支持很多追踪系统,包括 Zipkin、Jaeger、LightStep、Datadog。运维人员控制生成追踪的采样率(每个请求生成跟踪数据的速率)。这允许运维人员控制网格生成追踪数据的数量和速率。
更多关于 Istio 分布式追踪的信息可以在分布式追踪 FAQ 中找到。
Istio 为一个请求生成的分布式追踪数据:
2.4.3 访问日志
访问日志提供了一种从单个工作负载实例的角度监控和理解行为的方法。
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"
}
2.5 平台支持
Istio 独立于平台,被设计为可以在各种环境中运行,包括跨云、内部环境、Kubernetes、Mesos 等等。您可以在 Kubernetes 或是装有 Consul 的 Nomad 环境上部署 Istio。Istio 目前支持:
- Kubernetes 上的服务部署
- 基于 Consul 的服务注册
- 服务运行在独立的虚拟机上
2.6 整合和定制
Istio 的策略实施组件可以扩展和定制,与现有的 ACL、日志、监控、配额、审查等解决方案集成。