0%

【Service Mesh】Istio 入门

Istio 是一个完全开源的服务网格,以透明的方式构建在现有的分布式应用中。它也是一个平台,拥有可以集成任何日志、遥测和策略系统的 API 接口。Istio 多样化的特性使你能够成功且高效地运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法。

核心功能

流量控制

微服务应用最大的痛点就是处理服务间的通信,而这一问题的核心其实就是流量管理。首先我们来看看传统的微服务应用在没有 Service Mesh 介入的情况下,是如何完成诸如金丝雀发布这样的路由功能的。我们假设不借助任何现成的第三方框架,一个最简单的实现方法,就是在服务间添加一个负载均衡(比如 Nginx)做代理,通过修改配置的权重来分配流量。这种方式使得对流量的管理和基础设施绑定在了一起,难以维护。

而使用 Istio 就可以轻松的实现各种维度的流量控制。下图是典型的金丝雀发布策略:根据权重把 5% 的流量路由给新版本,如果服务正常,再逐渐转移更多的流量到新版本。

Istio 中的流量控制功能主要分为三个方面:

  • 请求路由和流量转移
  • 弹性功能,包括熔断、超时、重试
  • 调试能力,包括故障注入和流量镜像

关于流量控制的更多内容,参考 Istio流量控制

安全管理

安全对于微服务这样的分布式系统来说至关重要。与单体应用在进程内进行通信不同,网络成为了服务间通信的纽带,这使得它对安全有了更迫切的需求。比如为了抵御外来攻击,我们需要对流量进行加密;为保证服务间通信的可靠性,需要使用mTLS的方式进行交互;为控制不同身份的访问,需要设置不同粒度的授权策略。作为一个服务网格,Istio 提供了一整套完整的安全解决方案。它可以以透明的方式,为我们的微服务应用添加安全策略。

Istio 中的安全架构是由多个组件协同完成的。Citadel 是负责安全的主要组件,用于密钥和证书的管理;Pilot 会将安全策略配置分发给 Envoy 代理;Envoy 执行安全策略来实现访问控制。下图展示了 Istio 的安全架构和运作流程。

关于安全管理的更多内容,参考 Istio安全管理

可观测性

面对复杂的应用环境和不断扩展的业务需求,即使再完备的测试也难以覆盖所有场景,无法保证服务不会出现故障。正因为如此,才需要“可观察性”来对服务的运行时状态进行监控、上报、分析,以提高服务可靠性。具有可观察性的系统,可以在服务出现故障时大大降低问题定位的难度,甚至可以在出现问题之前及时发现问题以降低风险。具体来说,可观察性可以:

  • 及时反馈异常或者风险使得开发人员可以及时关注、修复和解决问题(告警);
  • 出现问题时,能够帮助快速定位问题根源并解决问题,以减少服务损失(减损);
  • 收集并分析数据,以帮助开发人员不断调整和改善服务(持续优化)。

而在微服务治理之中,随着服务数量大大增加,服务拓扑不断复杂化,可观察性更是至关重要。Istio 自然也不可能缺少对可观察性的支持。它会为所有的服务间通信生成详细的遥测数据,使得网格中每个服务请求都可以被观察和跟踪。开发人员可以凭此定位故障,维护和优化相关服务。而且,这一特性的引入无需侵入被观察的服务。

Istio 一共提供了三种不同类型的数据从不同的角度支撑起其可观察性:

  • 指标(Metrics)
  • 日志(Access Logs)
  • 分布式追踪(Distributed Traces)

关于可观测行的更多内容,参考 Istio可观测性

架构解析

Istio的架构由控制平面数据平面两个部分组成。

  • 数据平面:由整个网格内的sidecar代理组成,每个sidecar代理会接管流入和流出服务的流量,并配合控制平面完成流量控制等方面的内容。
  • 控制平面:负责控制和管理数据平面的sidecar代理,完成配置的分发、服务发现和授权鉴权等功能。

控制平面是 Istio 在原有服务网格产品上,首次提出的架构,实现了对于数据平面的统一管理。

Istio Arch

控制平面

Pilot

Pilot 组件的主要功能是将路由规则等配置信息转换为 sidecar 可以识别的信息,并下发给数据平面。可以把它简单的理解为是一个配置分发器(dispatcher),并辅助 sidecar 完成流量控制相关的功能。它管理sidecar代理之间的路由流量规则,并配置故障恢复功能,如超时、重试和熔断。

Istio Pilot Arch

上图显示了Pilot的基本架构,它主要由以下几个部分组成:

Abstract Model

为了实现对不同服务注册中心 (Kubernetes、consul) 的支持,Pilot 需要对不同的输入来源的数据有一个统一的存储格式,也就是抽象模型。抽象模型中定义的关键成员包括 HostName(Service名称)、Ports(Service端口)、Address(Service ClusterIP)、Resolution (负载均衡策略) 等。

Platform Adapters

借助平台适配器 Pilot 可以实现服务注册中心数据到抽象模型之间的数据转换。例如 Pilot 中的 Kubernetes 适配器通过 Kubernetes API 服务器得到 Kubernetes 中 Service 和 Pod 的相关信息,然后翻译为抽象模型提供给 Pilot 使用。通过平台适配器模式,Pilot 还可以从 Consul 等平台中获取服务信息,还可以开发适配器将其他提供服务发现的组件集成到 Pilot 中。

xDS API

Pilot 使用了一套起源于 Envoy 项目的标准数据面 API 来将服务信息和流量规则下发到数据面的 sidecar 中。这套标准数据面 API,也叫 xDS。Sidecar 通过 xDS API 可以动态获取 Listener (监听器)、Route (路由)、Cluster (集群)及 Endpoint (集群成员)配置:

  • LDS,Listener 发现服务:Listener 监听器控制 sidecar 启动端口监听(目前只支持 TCP 协议),并配置 L3/L4 层过滤器,当网络连接达到后,配置好的网络过滤器堆栈开始处理后续事件。
  • RDS,Router 发现服务:用于 HTTP 连接管理过滤器动态获取路由配置,路由配置包含 HTTP 头部修改(增加、删除 HTTP 头部键值),virtual hosts (虚拟主机),以及 virtual hosts 定义的各个路由条目。
  • CDS,Cluster发现服务:用于动态获取 Cluster 信息。
  • EDS,Endpoint 发现服务:用于动态维护端点信息,端点信息中还包括负载均衡权重、金丝雀状态等,基于这些信息,Sidecar 可以做出智能的负载均衡决策。
User API

Pilot 还定义了一套用户 API, 用户 API 提供了面向业务的高层抽象,可以被运维人员理解和使用。

运维人员使用该 API 定义流量规则并下发到 Pilot,这些规则被 Pilot 翻译成数据面的配置,再通过标准数据面 API 分发到 sidecar 实例,可以在运行期对微服务的流量进行控制和调整。

通过运用不同的流量规则,可以对网格中微服务进行精细化的流量控制,如按版本分流、断路器、故障注入、灰度发布等。

关于 Pilot 的具体实现,可以参考 Istio Pilot 模块分析

Citadel

Citadel 是 Istio 中专门负责安全的组件,内置有身份和证书管理功能,可以实现较为强大的授权和认证等操作,在1.5 版本之后取消了独立进程,作为一个模块被整合在 istiod 中。

总体来说,Istio 在安全架构方面主要包括以下内容:

  • 证书签发机构(CA)负责密钥和证书管理
  • API 服务器将安全配置分发给数据平面
  • 客户端、服务端通过代理安全通信
  • Envoy 代理管理遥测和审计

Istio 的身份标识模型使用一级服务标识来确定请求的来源,它可以灵活的标识终端用户、工作负载等。在平台层面,Istio 可以使用类似于服务名称来标识身份,或直接使用平台提供的服务标识。比如 Kubernetes 的 ServiceAccount,AWS IAM 用户、角色账户等。

在身份和证书管理方面,Istio 使用 X.509 证书,并支持密钥和证书的自动轮换。从 1.1 版本开始,Istio 开始支持安全发现服务器(SDS),随着不断的完善和增强,1.5 版本 SDS 已经成为默认开启的组件。Citadel 以前有两个功能:将证书以 Secret 的方式挂载到命名空间里;通过 SDS gRPC 接口与 nodeagent(已废弃)通信。目前 Citadel 只需要完成与 SDS 相关的工作,其他功能被移动到了 istiod 中。

关于Citadel的更多内容,参考 Istio安全管理

Galley

Galley 是 Istio 1.1 版本中新增加的组件,其目的是将 Pilot 和底层平台(如 Kubernetes)进行解耦。它分担了原本 Pilot 的一部分功能,主要负责配置的验证、提取和处理等功能。

数据平面

Istio 数据平面核心是以 sidecar 模式运行的智能代理。Sidecar 模式将数据平面核心组件部署到单独的流程或容器中,以提供隔离和封装。Sidecar 应用与父应用程序共享相同的生命周期,与父应用程序一起创建和退出。Sidecar 应用附加到父应用程序,并为应用程序提供额外的特性支持。

如下图所示,数据平面的 sidecar 代理可以调节和控制微服务之间所有的网络通信,每个服务 Pod 启动时会伴随启动 istio-init 和 proxy 容器。

  • istio-init 容器主要功能是初始化 Pod 网络和对 Pod设置 iptable 规则,设置完成后自动结束。
  • Proxy 容器会启动两个服务:istio-agent 以及网络代理组件
    • istio-agent 的作用是同步管理数据,启动并管理网络代理服务进程,上报遥测数据
    • 网络代理组件则根据管理策略完成流量管控、生成遥测数据。

数据平面真正触及到对网络数据包的相关操作,是上层控制平面策略的具体执行者。

Envoy 是 Istio 中默认的数据平面 Sidecar 代理,关于 Sidecar 是如何实现自动注入和流量劫持,以及Sidecar的流量路由机制如何实现,更多可参考 Envoy系列文章

安装部署

下载安装

这里介绍在 Kubernetes 环境下安装 Istio,在开始之前,你需要有一个 Kubernetes 运行环境。

从 Istio v1.7 版本开始,Istio官方推荐使用 istioctl 安装。下面是安装步骤:

  • Istio release 页面下载与操作系统匹配的安装包,并将其解压。这里可以直接用Istio提供的脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ curl -L https://raw.githubusercontent.com/istio/istio/release-1.7/release/downloadIstioCandidate.sh | sh -
$ [root@VM-1-28-centos istio]# ls
istio-1.7.0 istio-1.7.0-linux-amd64.tar.gz
$ [root@VM-1-28-centos istio]cd istio-1.7.0
$ [root@VM-1-28-centos istio-1.7.0]# tree -L 2
.
├── bin
│   └── istioctl
├── LICENSE
├── manifests
│   ├── charts
│   ├── deploy
│   ├── examples
│   └── profiles
├── manifest.yaml
├── README.md
├── samples
│   ├── addons
│   ├── bookinfo
│   ├── certs
│   ├── cross-network-gateway
│   ├── custom-bootstrap
│   ├── external
│   ├── fortio
│   ├── health-check
│   ├── helloworld
│   ├── httpbin
│   ├── https
│   ├── kubernetes-blog
│   ├── operator
│   ├── rawvm
│   ├── README.md
│   ├── security
│   ├── sleep
│   ├── tcp-echo
│   └── websockets
└── tools
├── certs
├── convert_RbacConfig_to_ClusterRbacConfig.sh
├── dump_kubernetes.sh
├── _istioctl
└── istioctl.bash

27 directories, 9 files

安装目录内容:

目录 包含内容
bin 包含 istioctl 的客户端文件
manifests 包含 各种部署的 manifests
samples 包含示例应用程序
tools 包含用于性能测试和在本地机器上进行测试的脚本
  • istioctl客户端路径加入 $PATH 中,从而可以使用 istioctl 命令行工具
1
$ export PATH=$PATH:$(pwd)/bin
  • 安装 demo 配置
1
2
3
4
5
6
$ istioctl install --set profile=demo
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
  • 添加一个Namespace Label,使得之后在部署你的应用的时候,istio会自动注入Envoy sidecar 代理
1
$ kubectl label namespace default istio-injection=enabled

部署 Bookinfo

Bookinfo 是 Istio 社区官方推荐的示例应用之一。它可以用来演示多种 Istio 的特性,并且它是一个异构的微服务应用。该应用由四个单独的微服务构成。 这个应用模仿了在线书店,可以展示书店中书籍的信息。例如页面上会显示一本书的描述,书籍的细节( ISBN、页数等),以及关于这本书的一些评论。

Bookinfo 应用分为四个单独的微服务, 这些服务对 Istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个不同语言编写的服务构成,并且其中有一个应用会包含多个版本。

  • productpage 会调用 detailsreviews 两个微服务,用来生成页面。
  • details 中包含了书籍的信息。
  • reviews 中包含了书籍相关的评论。它还会调用 ratings 微服务。
  • ratings 中包含了由书籍评价组成的评级信息。

reviews 微服务有 3 个版本,可用来展示各服务之间的不同的调用链路:

  • v1 版本不会调用 ratings 服务。
  • v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
  • v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。

下图展示了这个应用的端到端架构:

Bookinfo Application without Istio

  • 部署示例应用程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
service/details created
serviceaccount/bookinfo-details unchanged
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings unchanged
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews unchanged
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage unchanged
deployment.apps/productpage-v1 created
  • 之后应用起来,当每个Pod状态变为Ready的时候,sidecar也部署成功。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 172.18.252.45 <none> 9080/TCP 97s
kubernetes ClusterIP 172.18.252.1 <none> 443/TCP 51d
productpage ClusterIP 172.18.253.238 <none> 9080/TCP 97s
ratings ClusterIP 172.18.254.131 <none> 9080/TCP 97s
reviews ClusterIP 172.18.255.63 <none> 9080/TCP 97s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-5974b67c8-z67st 2/2 Running 0 2m8s
productpage-v1-797898bc54-frzdz 2/2 Running 0 2m8s
ratings-v1-c6cdf8d98-xmhz8 2/2 Running 0 2m8s
reviews-v1-8bdc65f7b-mjktx 2/2 Running 0 2m8s
reviews-v2-868d77d678-4dzmn 2/2 Running 0 2m8s
reviews-v3-6c9b646cb4-5tp9q 2/2 Running 0 2m8s
  • 查看应用是否成功运行,通过给productpage发送请求,查看其返回
1
2
$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -s productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

集群外部访问应用

到现在,Bookinfo 应用已经成功部署,我们在集群内部也已经可以访问,但是在集群外部还不能够访问。为了使得外部能够访问应用程序,我们需要创建一个Istio Ingress Gateway

  • 将应用于istio gateway关联
1
2
3
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
  • 确保配置上没有问题
1
2
$ istioctl analyze
✔ No validation issues found when analyzing namespace: default.
  • 确定Ingress的IP和Ports

通过下面的命令来设置 INGRESS_HOSTINGRESS_PORT环境变量。

1
2
3
kubectl get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 172.18.252.12 49.233.242.233 15021:32663/TCP,80:31968/TCP,443:31588/TCP,31400:32002/TCP,15443:30652/TCP 18m

这里显示 EXTERNAL_IP 已经变设置,表明当前环境下有一个可以使用的外部负载均衡器。

1
2
3
$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
  • 设定GATEWAY_URL
1
2
3
$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
$ echo $GATEWAY_URL
49.233.242.233:80
  • 确认外部访问是否成功:在浏览器直接访问 http://<GATE_WAYURL>/productpage 来访问Bookinfo应用

查看Dashboard

Istio集成了 一些 遥测应用,他们可以帮助你对你的服务网格有直观的认识、展示网格的拓扑、分析网格的健康状态

  • 安装Kiali
1
2
$ kubectl apply -f samples/addons
$ while ! kubectl wait --for=condition=available --timeout=600s deployment/kiali -n istio-system; do sleep 1; done
  • 访问Kiali

官方教程指示使用 istioctl dashboard kiali 命令来打开浏览器访问 Kiali服务,但是我的 Kubernetes 集群在服务器上,这样显然不行,不要将 Kiali 服务暴露给外部。因为之前集群已经安装了 Traefik ,所以可以使用 Ingress来暴露。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kiali
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- http:
paths:
- path: /kiali
backend:
serviceName: kiali
servicePort: 20001

在命令行创建Ingress,打开浏览器访问 http://<NodeIP>:<TraefikWebNodePort>/kiali 即可访问Kiali

在左侧导航栏点击Graph,选择default的命名空间,可以看到 Bookinfo 应用中各个服务间的关系:

到此为止,你的Istio和相关的服务已经在集群中完好的部署,关于其具体功能演示,参照 Istio流量控制

参考资料