本文转载自:zhongfox.github.io/2019/01/30/…html
今天分享的内容主要包括如下4个话题:java
1 Service Mesh: 下一代微服务node
2 Istio: 第二代 Service Meshnginx
3 Istio 数据面git
4 Istio 控制面github
首先我会和你们一块儿过一下 Service Mesh的发展历程, 并看看Istio 为 Service Mesh 带来了什么, 这部分相对比较轻松. 接下来我将和你们分析一下Istio的主要架构, 重点是数据面和控制面的实现, 包括sidecar的注入, 流量拦截, xDS介绍, Istio流量模型, 分布式跟踪, Mixer 的适配器模型等等, 中间也会穿插着 istio的现场使用demo.golang
应用通讯模式演进算法
Service Mesh(服务网格)的出现docker
第二代 Service Meshexpress
Service Mesh 的定义
Service Mesh 产品简史
国内Service Mesh 发展状况
在计算机网络发展的初期, 开发人员须要在本身的代码中处理服务器之间的网络链接问题, 包括流量控制, 缓存队列, 数据加密等. 在这段时间内底层网络逻辑和业务逻辑是混杂在一块儿.
随着技术的发展,TCP/IP 等网络标准的出现解决了流量控制等问题。尽管网络逻辑代码依然存在,但已经从应用程序里抽离出来,成为操做系统网络层的一部分, 造成了经典的网络分层模式.
微服务架构是更为复杂的分布式系统,它给运维带来了更多挑战, 这些挑战主要包括资源的有效管理和服务之间的治理, 如:
服务注册, 服务发现
服务伸缩
健康检查
快速部署
服务容错: 断路器, 限流, 隔离舱, 熔断保护, 服务降级等等
认证和受权
灰度发布方案
服务调用可观测性, 指标收集
配置管理
在微服务架构的实现中,为提高效率和下降门槛,应用开发者会基于微服务框架来实现微服务。微服务框架必定程度上为使用者屏蔽了底层网络的复杂性及分布式场景下的不肯定性。经过API/SDK的方式提供服务注册发现、服务RPC通讯、服务配置管理、服务负载均衡、路由限流、容错、服务监控及治理、服务发布及升级等通用能力, 比较典型的产品有:
分布式RPC通讯框架: COBRA, WebServices, Thrift, GRPC 等
服务治理特定领域的类库和解决方案: Hystrix, Zookeeper, Zipkin, Sentinel 等
对多种方案进行整合的微服务框架: SpringCloud、Finagle、Dubbox 等
实施微服务的成本每每会超出企业的预期(内容多, 门槛高), 花在服务治理上的时间成本甚至可能高过进行产品研发的时间. 另外上述的方案会限制可用的工具、运行时和编程语言。微服务软件库通常专一于某个平台, 这使得异构系统难以兼容, 存在重复的工做, 系统缺少可移植性.
Docker 和Kubernetes 技术的流行, 为Pass资源的分配管理和服务的部署提供了新的解决方案, 可是微服务领域的其余服务治理问题仍然存在.
Sidecar(有时会叫作agent) 在原有的客户端和服务端之间加多了一个代理, 为应用程序提供的额外的功能, 如服务发现, 路由代理, 认证受权, 链路跟踪 等等.
业界使用Sidecar 的一些先例:
2013 年,Airbnb 开发了Synapse 和 Nerve,是sidecar的一种开源实现
2014 年, Netflix 发布了Prana,它也是一个sidecar,可让非 JVM 应用接入他们的 NetflixOSS 生态系统
直观地看, Sidecar 到 Service Mesh 是一个规模的升级, 不过Service Mesh更强调的是:
再也不将Sidecar(代理)视为单独的组件,而是强调由这些代理链接而造成的网络
基础设施, 对应用程序透明
如下是Linkerd的CEO Willian Morgan给出的Service Mesh的定义:
A Service Mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the Service Mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware.
服务网格(Service Mesh)是致力于解决服务间通信的基础设施层。它负责在现代云原生应用程序的复杂服务拓扑来可靠地传递请求。实际上,Service Mesh 一般是经过一组轻量级网络代理(Sidecar proxy),与应用程序代码部署在一块儿来实现,且对应用程序透明。
控制面板对每个代理实例了如指掌,经过控制面板能够实现代理的访问控制和度量指标收集, 提高了服务网格的可观测性和管控能力, Istio 正是这类系统最为突出的表明.
2016 年 1 月 15 日,前 Twitter 的基础设施工程师 William Morgan 和 Oliver Gould,在 GitHub 上发布了 Linkerd 0.0.7 版本,采用Scala编写, 他们同时组建了一个创业小公司 Buoyant,这是业界公认的第一个Service Mesh
2016 年,Matt Klein在 Lyft 默默地进行 Envoy 的开发。Envoy 诞生的时间其实要比 Linkerd 更早一些,只是在 Lyft 内部不为人所知
2016 年 9 月 29 日在 SF Microservices 上,“Service Mesh”这个词汇第一次在公开场合被使用。这标志着“Service Mesh”这个词,从 Buoyant 公司走向社区.
2016 年 9 月 13 日,Matt Klein 宣布 Envoy 在 GitHub 开源,直接发布 1.0.0 版本。
2016 年下半年,Linkerd 陆续发布了 0.8 和 0.9 版本,开始支持 HTTP/2 和 gRPC,1.0 发布在即;同时,借助 Service Mesh 在社区的承认度,Linkerd 在年末开始申请加入 CNCF
2017 年 1 月 23 日,Linkerd 加入 CNCF。
2017 年 3 月 7 日,Linkerd 宣布完成千亿次产品请求
2017 年 4 月 25 日,Linkerd 1.0 版本发布
2017 年 7 月 11 日,Linkerd 发布版本 1.1.1,宣布和 Istio 项目集成
2017 年 9 月, nginx忽然宣布要搞出一个Servicemesh来, Nginmesh: github.com/nginxinc/ng…, 能够做为istio的数据面, 不过这个项目目前处于不活跃开发(This project is no longer under active development)
2017 年 12 月 5 日,Conduit 0.1.0 版本发布
Envoy 和 Linkerd 都是在数据面上的实现, 属于同一个层面的竞争, 是用 C++ 语言实现的,在性能和资源消耗上要比采用 Scala 语言实现的 Linkerd 小,这一点对于延迟敏感型和资源敏的服务尤其重要.
Envoy 对 做为 Istio 的标准数据面实现, 其最主要的贡献是提供了一套标准数据面API, 将服务信息和流量规则下发到数据面的sidecar中, 另外Envoy还支持热重启. Istio早期采用了Envoy v1 API,目前的版本中则使用V2 API,V1已被废弃.
经过采用该标准API,Istio将控制面和数据面进行了解耦,为多种数据面sidecar实现提供了可能性。事实上基于该标准API已经实现了多种Sidecar代理和Istio的集成,除Istio目前集成的Envoy外,还能够和Linkerd, Nginmesh等第三方通讯代理进行集成,也能够基于该API本身编写Sidecar实现.
将控制面和数据面解耦是Istio后来居上,风头超过Service mesh鼻祖Linkerd的一招妙棋。Istio站在了控制面的高度上,而Linkerd则成为了可选的一种sidecar实现.
Conduit 的总体架构和 Istio 一致,借鉴了 Istio 数据平面 + 控制平面的设计,并且选择了 Rust 编程语言来实现数据平面,以达成 Conduit 宣称的更轻、更快和超低资源占用.
Kubernetes | Istio | |
---|---|---|
领域 | 容器编排 | 服务网格 |
主要竞品 | Swarm, Mesos | Linkerd, Conduit |
主要盟友 | RedHat, CoreOS | IBM, Lyft |
主要竞争对手 | Docker 公司 | Buoyant 公司 |
标准化 | OCI: runtime spec, image spec | XDS |
插件化 | CNI, CRI | Istio CNI, Mixer Adapter |
结果 | Kubernetes 成为容器编排事实标准 | ? |
google 主导的Kubernetes 在容器编排领域取得了完胜, 目前在服务网格领域的打法一模一样, 社区对Istio前景也比较看好.
Istio CNI 计划在1.1 做为实验特性, 用户能够经过扩展方式定制sidecar的网络.
蚂蚁金服开源SOFAMesh:
从istio fork
使用Golang语言开发全新的Sidecar,替代Envoy
为了不Mixer带来的性能瓶颈,合并Mixer部分功能进入Sidecar
Pilot和Citadel模块进行了大幅的扩展和加强
扩展RPC协议: SOFARPC/HSF/Dubbo
华为:
go-chassis: github.com/go-chassis/… golang 微服务框架, 支持istio平台
mesher: github.com/go-mesh/mes… mesh 数据面解决方案
国内首家提供Service Mesh公共服务的云厂商
目前(2019年1月)公有云Istio 产品线上已经支持申请公测, 产品形态比较完善
腾讯云 TSF:
基于 Istio、envoy 进行改造
支持 Kubernetes、虚拟机以及裸金属的服务
对 Istio 的能力进行了扩展和加强, 对 Consul 的完整适配
对于其余二进制协议进行扩展支持
惟品会
OSP (Open Service Platform)
新浪:
Motan: 是一套基于java开发的RPC框架, Weibo Mesh 是基于Motan
Istio来自希腊语,英文意思是「sail」, 意为「启航」
2.1 Istio 架构
2.2 核心功能
2.3 Istio 演示: BookInfo
Istio Architecture(图片来自Isio官网文档)
数据面
Sidecar
控制面
Pilot:服务发现、流量管理
Mixer:访问控制、遥测
Citadel:终端用户认证、流量加密
流量管理
安全
可观察性
多平台支持
集成和定制
下面是我对Istio架构总结的思惟导图:
如下是Istio官网经典的 BookInfo Demo, 这是一个多语言组成的异构微服务系统:
Bookinfo Application(图片来自Isio官网文档)
下面我将现场给你们进行演示, 从demo安装开始, 并体验一下istio的流控功能:
下载istio release: istio.io/docs/setup/…
1kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml2helm install install/kubernetes/helm/istio --name istio --namespace istio-system复制代码
注意事项, 若要开启sidecar自动注入功能, 须要:
确保 kube-apiserver 启动参数 开启了ValidatingAdmissionWebhook 和 MutatingAdmissionWebhook
给namespace 增长 label: kubectl label namespace default istio-injection=enabled
同时还要保证 kube-apiserver 的 aggregator layer 开启: --enable-aggregator-routing=true
且证书和api server连通性正确设置.
1helm delete --purge istio2kubectl delete -f install/kubernetes/helm/istio/templates/crds.yaml -n istio-system复制代码
更多安装选择请参考: istio.io/docs/setup/…
Bookinfo 是一个多语言异构的微服务demo, 其中 productpage 微服务会调用 details 和 reviews 两个微服务, reviews 会调用ratings 微服务, reviews 微服务有 3 个版本. 关于此项目更多细节请参考: istio.io/docs/exampl…
1kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml复制代码
这将建立 productpage, details, ratings, reviews 对应的deployments 和 service, 其中reviews 有三个deployments, 表明三个不一样的版本.
1 % kubectl get pod2NAME READY STATUS RESTARTS AGE3details-v1-6865b9b99d-mnxbt 2/2 Running 0 1m4productpage-v1-f8c8fb8-zjbhh 2/2 Running 0 59s5ratings-v1-77f657f55d-95rcz 2/2 Running 0 1m6reviews-v1-6b7f6db5c5-zqvkn 2/2 Running 0 59s7reviews-v2-7ff5966b99-lw72l 2/2 Running 0 59s8reviews-v3-5df889bcff-w9v7g 2/2 Running 0 59s910 % kubectl get svc11NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE12details ClusterIP 172.18.255.240 <none> 9080/TCP 1m13productpage ClusterIP 172.18.255.137 <none> 9080/TCP 1m14ratings ClusterIP 172.18.255.41 <none> 9080/TCP 1m15reviews ClusterIP 172.18.255.140 <none> 9080/TCP 1m复制代码
对入口流量进行配置:
1kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml复制代码
该操做会建立bookinfo-gateway 的Gateway, 并将流量发送到productpage服务
1kubectl get gateway2NAME AGE3bookinfo-gateway 1m复制代码
此时经过bookinfo-gateway 对应的LB或者nodeport 访问/productpage 页面, 能够看到三个版本的reviews服务在随机切换
经过CRD DestinationRule建立3 个reviews 子版本:
1kubectl apply -f samples/bookinfo/networking/destination-rule-reviews.yaml复制代码
经过CRD VirtualService 调整个 reviews 服务子版本的流量比例, 设置 v1 和 v3 各占 50%
1kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml复制代码
刷新页面, 能够看到没法再看到reviews v2的内容, 页面在v1和v3之间切换.
修改reviews CRD, 将jason 登陆的用户版本路由到v2, 其余用户路由到版本v3.
1kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml复制代码
刷新页面, 使用jason登陆的用户, 将看到v2 黑色星星版本, 其余用户将看到v3 红色星星版本.
更多BookInfo 示例, 请参阅: istio.io/docs/exampl…, 若要删除应用: 执行脚本 ./samples/bookinfo/platform/kube/cleanup.sh
3.1 数据面组件
3.2 sidecar 流量劫持原理
3.3 数据面标准API: xDS
3.4 分布式跟踪
Istio 注入sidecar实现:
自动注入: 利用 Kubernetes Dynamic Admission Webhooks 对 新建的pod 进行注入: init container + sidecar
手动注入: 使用istioctl kube-inject
注入Pod内容:
istio-init: 经过配置iptables来劫持Pod中的流量
istio-proxy: 两个进程pilot-agent和envoy, pilot-agent 进行初始化并启动envoy
Istio 利用 Kubernetes Dynamic Admission Webhooks 对pod 进行sidecar注入
查看istio 对这2个Webhooks 的配置 ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration:
1% kubectl get ValidatingWebhookConfiguration -oyaml2% kubectl get mutatingWebhookConfiguration -oyaml复制代码
能够看出:
命名空间istio-system
中的服务 istio-galley
, 经过路由/admitpilot
, 处理config.istio.io部分, rbac.istio.io, authentication.istio.io, networking.istio.io等资源的Validating 工做
命名空间istio-system 中的服务 istio-galley
, 经过路由/admitmixer
, 处理其余config.istio.io资源的Validating 工做
命名空间istio-system 中的服务 istio-sidecar-injector
, 经过路由/inject
, 处理其余v1/pods
的CREATE, 同时须要知足命名空间istio-injection: enabled
数据面的每一个Pod会被注入一个名为istio-init
的initContainer, initContrainer是K8S提供的机制,用于在Pod中执行一些初始化任务.在Initialcontainer执行完毕并退出后,才会启动Pod中的其它container.
1initContainers:2- image: docker.io/istio/proxy_init:1.0.53 args:4 - -p5 - "15001"6 - -u7 - "1337"8 - -m9 - REDIRECT10 - -i11 - '*'12 - -x13 - ""14 - -b15 - "9080"16 - -d17 - ""复制代码
istio-init ENTRYPOINT 和 args 组合的启动命令:
1/usr/local/bin/istio-iptables.sh -p 15001 -u 1337 -m REDIRECT -i '*' -x "" -b 9080 -d ""复制代码
istio-iptables.sh 源码地址为 github.com/istio/istio…
1$ istio-iptables.sh -p PORT -u UID -g GID [-m mode] [-b ports] [-d ports] [-i CIDR] [-x CIDR] [-h]2 -p: 指定重定向全部 TCP 流量的 Envoy 端口(默认为 $ENVOY_PORT = 15001)3 -u: 指定未应用重定向的用户的 UID。一般,这是代理容器的 UID(默认为 $ENVOY_USER 的 uid,istio_proxy 的 uid 或 1337)4 -g: 指定未应用重定向的用户的 GID。(与 -u param 相同的默认值)5 -m: 指定入站链接重定向到 Envoy 的模式,“REDIRECT” 或 “TPROXY”(默认为 $ISTIO_INBOUND_INTERCEPTION_MODE)6 -b: 逗号分隔的入站端口列表,其流量将重定向到 Envoy(可选)。使用通配符 “*” 表示重定向全部端口。为空时表示禁用全部入站重定向(默认为 $ISTIO_INBOUND_PORTS)7 -d: 指定要从重定向到 Envoy 中排除(可选)的入站端口列表,以逗号格式分隔。使用通配符“*” 表示重定向全部入站流量(默认为 $ISTIO_LOCAL_EXCLUDE_PORTS)8 -i: 指定重定向到 Envoy(可选)的 IP 地址范围,以逗号分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向全部出站流量。空列表将禁用全部出站重定向(默认为 $ISTIO_SERVICE_CIDR)9 -x: 指定将从重定向中排除的 IP 地址范围,以逗号分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向全部出站流量(默认为 $ISTIO_SERVICE_EXCLUDE_CIDR)。1011环境变量位于 $ISTIO_SIDECAR_CONFIG(默认在:/var/lib/istio/envoy/sidecar.env)复制代码
istio-init 经过配置iptable来劫持Pod中的流量:
参数-p 15001
: Pod中的数据流量被iptable拦截,并发向15001端口, 该端口将由 envoy 监听
参数-u 1337
: 用于排除用户ID为1337,即Envoy自身的流量,以免Iptable把Envoy发出的数据又重定向到Envoy, UID 为 1337,即 Envoy 所处的用户空间,这也是 istio-proxy 容器默认使用的用户, 见Sidecar istio-proxy
配置参数securityContext.runAsUser
参数-b 9080
-d ""
: 入站端口控制, 将全部访问 9080 端口(即应用容器的端口)的流量重定向到 Envoy 代理
参数-i '*'
-x ""
: 出站IP控制, 将全部出站流量都重定向到 Envoy 代理
Init 容器初始化完毕后就会自动终止,可是 Init 容器初始化结果(iptables)会保留到应用容器和 Sidecar 容器中.
istio-proxy 以 sidecar 的形式注入到应用容器所在的pod中, 简化的注入yaml:
1- image: docker.io/istio/proxyv2:1.0.52 name: istio-proxy3 args:4 - proxy5 - sidecar6 - --configPath7 - /etc/istio/proxy8 - --binaryPath9 - /usr/local/bin/envoy10 - --serviceCluster11 - ratings12 - --drainDuration13 - 45s14 - --parentShutdownDuration15 - 1m0s16 - --discoveryAddress17 - istio-pilot.istio-system:1500718 - --discoveryRefreshDelay19 - 1s20 - --zipkinAddress21 - zipkin.istio-system:941122 - --connectTimeout23 - 10s24 - --proxyAdminPort25 - "15000"26 - --controlPlaneAuthPolicy27 - NONE28 env:29 ......30 ports:31 - containerPort: 1509032 name: http-envoy-prom33 protocol: TCP34 securityContext:35 runAsUser: 133736 ......复制代码
istio-proxy容器中有两个进程pilot-agent和envoy:
1~ % kubectl exec productpage-v1-f8c8fb8-wgmzk -c istio-proxy -- ps -ef2UID PID PPID C STIME TTY TIME CMD3istio-p+ 1 0 0 Jan03 ? 00:00:27 /usr/local/bin/pilot-agent proxy sidecar --configPath /etc/istio/proxy --binaryPath /usr/local/bin/envoy --serviceCluster productpage --drainDuration 45s --parentShutdownDuration 1m0s --discoveryAddress istio-pilot.istio-system:15007 --discoveryRefreshDelay 1s --zipkinAddress zipkin.istio-system:9411 --connectTimeout 10s --proxyAdminPort 15000 --controlPlaneAuthPolicy NONE4istio-p+ 21 1 0 Jan03 ? 01:26:24 /usr/local/bin/envoy -c /etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster productpage --service-node sidecar~172.18.3.12~productpage-v1-f8c8fb8-wgmzk.default~default.svc.cluster.local --max-obj-name-len 189 --allow-unknown-fields -l warn --v2-config-only复制代码
能够看到:
/usr/local/bin/pilot-agent
是 /usr/local/bin/envoy
的父进程, Pilot-agent进程根据启动参数和K8S API Server中的配置信息生成Envoy的初始配置文件(/etc/istio/proxy/envoy-rev0.json
),并负责启动Envoy进程
pilot-agent 的启动参数里包括: discoveryAddress(pilot服务地址), Envoy 二进制文件的位置, 服务集群名, 监控指标上报地址, Envoy 的管理端口, 热重启时间等
Envoy配置初始化流程:
Pilot-agent根据启动参数和K8S API Server中的配置信息生成Envoy的初始配置文件envoy-rev0.json,该文件告诉Envoy从xDS server中获取动态配置信息,并配置了xDS server的地址信息,即控制面的Pilot
Pilot-agent使用envoy-rev0.json启动Envoy进程
Envoy根据初始配置得到Pilot地址,采用xDS接口从Pilot获取到Listener,Cluster,Route等d动态配置信息
Envoy根据获取到的动态配置启动Listener,并根据Listener的配置,结合Route和Cluster对拦截到的流量进行处理
查看envoy 初始配置文件:
1kubectl exec productpage-v1-f8c8fb8-wgmzk -c istio-proxy -- cat /etc/istio/proxy/envoy-rev0.json复制代码
sidecar 既要做为服务消费者端的正向代理,又要做为服务提供者端的反向代理, 具体拦截过程以下:
Pod 所在的network namespace内, 除了envoy发出的流量外, iptables规则会对进入和发出的流量都进行拦截,经过nat redirect重定向到Envoy监听的15001端口.
envoy 会根据从Pilot拿到的 XDS 规则, 对流量进行转发.
envoy 的 listener 0.0.0.0:15001 接收进出 Pod 的全部流量,而后将请求移交给对应的virtual listener
对于本pod的服务, 有一个http listener podIP+端口
接受inbound 流量
每一个service+非http端口, 监听器配对的 Outbound 非 HTTP 流量
每一个service+http端口, 有一个http listener: 0.0.0.0+端口
接受outbound流量
整个拦截转发过程对业务容器是透明的, 业务容器仍然使用 Service 域名和端口进行通讯, service 域名仍然会转换为service IP, 但service IP 在sidecar 中会被直接转换为 pod IP, 从容器中出去的流量已经使用了pod IP会直接转发到对应的Pod, 对比传统kubernetes 服务机制, service IP 转换为Pod IP 在node上进行, 由 kube-proxy维护的iptables实现.
xDS是一类发现服务的总称,包含LDS,RDS,CDS,EDS以及 SDS。Envoy经过xDS API能够动态获取Listener(监听器), Route(路由),Cluster(集群),Endpoint(集群成员)以 及Secret(证书)配置
xDS API 涉及的概念:
Host
Downstream
Upstream
Listener
Cluster
Envoy 配置热更新: 配置的动态变动,而不须要重启 Envoy:
新老进程采用基本的RPC协议使用Unix Domain Socket通信.
新进程启动并完成全部初始化工做后,向老进程请求监听套接字的副本.
新进程接管套接字后,通知老进程关闭套接字.
通知老进程终止本身.
Pilot在9093端口提供了下述调试接口:
1# What is sent to envoy2# Listeners and routes3curl $PILOT/debug/adsz45# Endpoints6curl $PILOT/debug/edsz78# Clusters9curl $PILOT/debug/cdsz复制代码
Sidecar Envoy 也提供了管理接口,缺省为localhost的15000端口,能够获取listener,cluster以及完整的配置数据
能够经过如下命令查看支持的调试接口:
1kubectl exec productpage-v1-f8c8fb8-zjbhh -c istio-proxy curl http://127.0.0.1:15000/help复制代码
或者forward到本地就行调试
1kubectl port-forward productpage-v1-f8c8fb8-zjbhh 15000复制代码
相关的调试接口:
1http://127.0.0.1:150002http://127.0.0.1:15000/help3http://127.0.0.1:15000/config_dump4http://127.0.0.1:15000/listeners5http://127.0.0.1:15000/clusters复制代码
使用istioctl 查看代理配置:
1istioctl pc {xDS类型} {POD_NAME} {过滤条件} {-o json/yaml}23eg:4istioctl pc routes productpage-v1-f8c8fb8-zjbhh --name 9080 -o json复制代码
xDS 类型包括: listener, route, cluster, endpoint
查看 product 的全部listener:
1% istioctl pc listener productpage-v1-f8c8fb8-zjbhh2ADDRESS PORT TYPE3172.18.255.178 15011 TCP4172.18.255.194 44134 TCP5172.18.255.110 443 TCP6172.18.255.190 50000 TCP7172.18.255.203 853 TCP8172.18.255.2 443 TCP9172.18.255.239 16686 TCP100.0.0.0 80 TCP11172.18.255.215 3306 TCP12172.18.255.203 31400 TCP13172.18.255.111 443 TCP14172.18.255.203 8060 TCP15172.18.255.203 443 TCP16172.18.255.40 443 TCP17172.18.255.1 443 TCP18172.18.255.53 53 TCP19172.18.255.203 15011 TCP20172.18.255.105 14268 TCP21172.18.255.125 42422 TCP22172.18.255.105 14267 TCP23172.18.255.52 80 TCP240.0.0.0 15010 HTTP250.0.0.0 9411 HTTP260.0.0.0 8060 HTTP270.0.0.0 9080 HTTP280.0.0.0 15004 HTTP290.0.0.0 20001 HTTP300.0.0.0 9093 HTTP310.0.0.0 8080 HTTP320.0.0.0 15030 HTTP330.0.0.0 9091 HTTP340.0.0.0 9090 HTTP350.0.0.0 15031 HTTP360.0.0.0 3000 HTTP370.0.0.0 15001 TCP38172.18.3.50 9080 HTTP 这是当前pod ip 暴露的服务地址, 会路由到回环地址, 各个pod 会不同复制代码
envoy 流量入口的listener:
1% istioctl pc listener productpage-v1-f8c8fb8-zjbhh --address 0.0.0.0 --port 15001 -o json2[3 {4 "name": "virtual",5 "address": {6 "socketAddress": {7 "address": "0.0.0.0",8 "portValue": 150019 }10 },11 "filterChains": [12 {13 "filters": [14 {15 "name": "envoy.tcp_proxy",16 "config": {17 "cluster": "BlackHoleCluster",18 "stat_prefix": "BlackHoleCluster"19 }20 }21 ]22 }23 ],24 "useOriginalDst": true # 这意味着它将请求交给最符合请求原始目标的监听器。若是找不到任何匹配的虚拟监听器,它会将请求发送给返回 404 的 BlackHoleCluster25 }26]复制代码
如下是reviews的全部pod IP
1 % kubectl get ep reviews2NAME ENDPOINTS AGE3reviews 172.18.2.35:9080,172.18.3.48:9080,172.18.3.49:9080 1d复制代码
对于目的地址是以上ip的http访问, 这些 ip 并无对应的listener, 所以会经过端口9080 匹配到listener 0.0.0.0 9080
查看listener 0.0.0.0 9080
:
1% istioctl pc listener productpage-v1-f8c8fb8-zjbhh --address 0.0.0.0 --port 9080 -ojson2 {3 "name": "0.0.0.0_9080",4 "address": {5 "socketAddress": {6 "address": "0.0.0.0",7 "portValue": 90808 }9 },10 ......1112 "rds": {13 "config_source": {14 "ads": {}15 },16 "route_config_name": "9080"17 },18 ......复制代码
查看名为9080
的 route:
1% istioctl pc routes productpage-v1-f8c8fb8-zjbhh --name 9080 -o json23[4 {5 "name": "9080",6 "virtualHosts": [7 {8 "name": "details.default.svc.cluster.local:9080",9 "domains": [10 "details.default.svc.cluster.local",11 "details.default.svc.cluster.local:9080",12 "details",13 "details:9080",14 "details.default.svc.cluster",15 "details.default.svc.cluster:9080",16 "details.default.svc",17 "details.default.svc:9080",18 "details.default",19 "details.default:9080",20 "172.18.255.240",21 "172.18.255.240:9080"22 ],23 "routes": [24 {25 "match": {26 "prefix": "/"27 },28 "route": {29 "cluster": "outbound|9080||details.default.svc.cluster.local",30 "timeout": "0.000s",31 "maxGrpcTimeout": "0.000s"32 },33 ......34 {35 "name": "productpage.default.svc.cluster.local:9080",36 "domains": [37 "productpage.default.svc.cluster.local",38 "productpage.default.svc.cluster.local:9080",39 "productpage",40 "productpage:9080",41 "productpage.default.svc.cluster",42 "productpage.default.svc.cluster:9080",43 "productpage.default.svc",44 "productpage.default.svc:9080",45 "productpage.default",46 "productpage.default:9080",47 "172.18.255.137",48 "172.18.255.137:9080"49 ],50 "routes": [ ...... ]51 },52 {53 "name": "ratings.default.svc.cluster.local:9080",54 "domains": [55 "ratings.default.svc.cluster.local",56 "ratings.default.svc.cluster.local:9080",57 "ratings",58 "ratings:9080",59 "ratings.default.svc.cluster",60 "ratings.default.svc.cluster:9080",61 "ratings.default.svc",62 "ratings.default.svc:9080",63 "ratings.default",64 "ratings.default:9080",65 "172.18.255.41",66 "172.18.255.41:9080"67 ],68 "routes": [ ...... ]69 },70 {71 "name": "reviews.default.svc.cluster.local:9080",72 "domains": [73 "reviews.default.svc.cluster.local",74 "reviews.default.svc.cluster.local:9080",75 "reviews",76 "reviews:9080",77 "reviews.default.svc.cluster",78 "reviews.default.svc.cluster:9080",79 "reviews.default.svc",80 "reviews.default.svc:9080",81 "reviews.default",82 "reviews.default:9080",83 "172.18.255.140",84 "172.18.255.140:9080"85 ],86 "routes": [87 {88 "match": {89 "prefix": "/",90 "headers": [91 {92 "name": "end-user",93 "exactMatch": "jason"94 }95 ]96 },97 "route": {98 "cluster": "outbound|9080|v2|reviews.default.svc.cluster.local",99 "timeout": "0.000s",100 "maxGrpcTimeout": "0.000s"101 },102 ......103 },104 {105 "match": {106 "prefix": "/"107 },108 "route": {109 "cluster": "outbound|9080|v3|reviews.default.svc.cluster.local",110 "timeout": "0.000s",111 "maxGrpcTimeout": "0.000s"112 },113 .......114 }115 ]116 }117 ],118 "validateClusters": false119 }120]复制代码
能够看到, 在9080 这个route 中, 包含全部这个端口的http 路由信息, 经过virtualHosts列表进行服务域名分发到各个cluster.
查看virtualHosts reviews.default.svc.cluster.local:9080
中的routes信息, 能够看到jason 路由到了cluster outbound|9080|v2|reviews.default.svc.cluster.local
查看该cluster:
1% istioctl pc cluster productpage-v1-f8c8fb8-zjbhh --fqdn reviews.default.svc.cluster.local --subset v2 -o json2[3 {4 "name": "outbound|9080|v2|reviews.default.svc.cluster.local",5 "type": "EDS",6 "edsClusterConfig": {7 "edsConfig": {8 "ads": {}9 },10 "serviceName": "outbound|9080|v2|reviews.default.svc.cluster.local"11 },12 "connectTimeout": "1.000s",13 "lbPolicy": "RANDOM",14 "circuitBreakers": {15 "thresholds": [16 {}17 ]18 }19 }20]复制代码
查看其对应的endpoint:
1 % istioctl pc endpoint productpage-v1-f8c8fb8-zjbhh --cluster 'outbound|9080|v2|reviews.default.svc.cluster.local'2ENDPOINT STATUS CLUSTER3172.18.2.35:9080 HEALTHY outbound|9080|v2|reviews.default.svc.cluster.local复制代码
该endpoint 即为 reviews 服务 V2 对应的 pod IP
遵循 make before break 模型
如下是分布式全链路跟踪示意图:
一个典型的Trace案例(图片来自opentracing文档中文版)
Jaeger 是Uber 开源的全链路跟踪系统, 符合OpenTracing协议, OpenTracing 和 Jaeger 均是CNCF 成员项目, 如下是Jaeger 架构的示意图:
Jaeger 架构示意图(图片来自Jaeger官方文档)
分布式跟踪系统让开发者可以获得可视化的调用流程展现。这对复杂的微服务系统进行问题排查和性能优化时相当重要.
Envoy 原生支持http 链路跟踪:
生成 Request ID:Envoy 会在须要的时候生成 UUID,并操做名为 [x-request-id] 的 HTTP Header。应用能够转发这个 Header 用于统一的记录和跟踪.
支持集成外部跟踪服务:Envoy 支持可插接的外部跟踪可视化服务。目前支持有:
LightStep
Zipkin 或者 Zipkin 兼容的后端(好比说 Jaeger)
Datadog
客户端跟踪 ID 链接:x-client-trace-id Header 能够用来把不信任的请求 ID 链接到受信的 x-request-id Header 上
无论使用的是哪一个跟踪服务,都应该传播 x-request-id,这样在被调用服务中启动相关性的记录
若是使用的是 Zipkin,Envoy 要传播的是 B3 Header。(x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, 以及 x-b3-flags. x-b3-sampled)
上下文跟踪并不是零修改, 在调用下游服务时, 上游应用应该自行传播跟踪相关的 HTTP Header
4.1 Pilot 架构
4.2 流量管理模型
4.3 故障处理
4.4 Mixer 架构
4.5 Mixer适配器模型
4.6 Mixer 缓存机制
Pilot Architecture(图片来自Isio官网文档)
Rules API: 对外封装统一的 API,供服务的开发者或者运维人员调用,能够用于流量控制。
Envoy API: 对内封装统一的 API,供 Envoy 调用以获取注册信息、流量控制信息等。
抽象模型层: 对服务的注册信息、流量控制规则等进行抽象,使其描述与平台无关。
平台适配层: 用于适配各个平台如 Kubernetes、Mesos、Cloud Foundry 等,把平台特定的注册信息、资源信息等转换成抽象模型层定义的平台无关的描述。例如,Pilot 中的 Kubernetes 适配器实现必要的控制器来 watch Kubernetes API server 中 pod 注册信息、ingress 资源以及用于存储流量管理规则的第三方资源的更改
VirtualService
DestinationRule
ServiceEntry
Gateway
VirtualService 中定义了一系列针对指定服务的流量路由规则。每一个路由规则都是针对特定协议的匹配规则。若是流量符合这些特征,就会根据规则发送到服务注册表中的目标服务, 或者目标服务的子集或版本, 匹配规则中还包含了对流量发起方的定义,这样一来,规则还能够针对特定客户上下文进行定制.
Gateway 描述了一个负载均衡器,用于承载网格边缘的进入和发出链接。这一规范中描述了一系列开放端口,以及这些端口所使用的协议、负载均衡的 SNI 配置等内容
Istio 服务网格内部会维护一个与平台无关的使用通用模型表示的服务注册表,当你的服务网格须要访问外部服务的时候,就须要使用 ServiceEntry 来添加服务注册, 这类服务多是网格外的 API,或者是处于网格内部但却不存在于平台的服务注册表中的条目(例如须要和 Kubernetes 服务沟通的一组虚拟机服务).
EnvoyFilter 描述了针对代理服务的过滤器,用来定制由 Istio Pilot 生成的代理配置.
合并了L4-6和L7的规范, 对传统技术栈用户的应用迁入不方便
表现力不足:
只能对 service、port、HTTP 路径等有限字段匹配来路由流量
端口只支持默认80/443
Istio Gateway:·
定义了四层到六层的负载均衡属性 (一般是SecOps或NetOps关注的内容)
端口
端口所使用的协议(HTTP, HTTPS, GRPC, HTTP2, MONGO, TCP, TLS)
Hosts
TLS SNI header 路由支持
TLS 配置支持(http 自动301, 证书等)
ip / unix domain socket
如下是对Kubernetes, Istio, Envoy xDS 模型的不严格对比
Kubernetes | Istio | Envoy xDS | |
---|---|---|---|
入口流量 | Ingress | GateWay | Listener |
服务定义 | Service | - | Cluster+Listener |
外部服务定义 | - | ServiceEntry | Cluster+Listener |
版本定义 | - | DestinationRule | Cluster+Listener |
版本路由 | - | VirtualService | Route |
实例 | Endpoint | - | Endpoint |
Kubernetes:
kube-dns: service domain -> service ip
kube-proxy(node iptables): service ip -> pod ip
Istio:
kube-dns: service domain -> service ip
sidecar envoy: service ip -> pod ip
随着微服务的拆分粒度加强, 服务调用会增多, 更复杂, 扇入 扇出, 调用失败的风险增长, 如下是常见的服务容错处理方式:
控制端 | 目的 | 实现 | Istio | |
---|---|---|---|---|
超时 | client | 保护client | 请求等待超时/请求运行超时 | timeout |
重试 | client | 容忍server临时错误, 保证业务总体可用性 | 重试次数/重试的超时时间 | retries.attempts, retries.perTryTimeout |
熔断 | client | 下降性能差的服务或实例的影响 | 一般会结合超时+重试, 动态进行服务状态决策(Open/Closed/Half-Open) | trafficPolicy.outlierDetection |
降级 | client | 保证业务主要功能可用 | 主逻辑失败采用备用逻辑的过程(镜像服务分级, 调用备用服务, 或者返回mock数据) | 暂不支持, 须要业务代码按需实现 |
隔离 | client | 防止异常server占用过多client资源 | 隔离对不一样服务调用的资源依赖: 线程池隔离/信号量隔离 | 暂不支持 |
幂等 | server | 容忍client重试, 保证数据一致性 | 惟一ID/加锁/事务等手段 | 暂不支持, 须要业务代码按需实现 |
限流 | server | 保护server | 经常使用算法: 计数器, 漏桶, 令牌桶 | trafficPolicy.connectionPool |
Istio 没有无降级处理支持: Istio能够提升网格中服务的可靠性和可用性。可是,应用程序仍然须要处理故障(错误)并采起适当的回退操做。例如,当负载均衡池中的全部实例都失败时,Envoy 将返回 HTTP 503。应用程序有责任实现必要的逻辑,对这种来自上游服务的 HTTP 503 错误作出合适的响应。
Mixer Topology(图片来自Isio官网文档)
Istio 的四大功能点链接, 安全, 控制, 观察, 其中「控制」和「观察」的功能主要都是由Mixer组件来提供, Mixer 在Istio中角色:
功能上: 负责策略控制和遥测收集
架构上:提供插件模型,能够扩展和定制
Attribute
Template
Adapter
Instance
Handler
Rule
Attribute 是策略和遥测功能中有关请求和环境的基本数据, 是用于描述特定服务请求或请求环境的属性的一小段数据。例如,属性能够指定特定请求的大小、操做的响应代码、请求来自的 IP 地址等.
Istio 中的主要属性生产者是 Envoy,但专用的 Mixer 适配器也能够生成属性
属性词汇表见: Attribute Vocabulary
数据流向: envoy -> mixer
Template 是对 adapter 的数据格式和处理接口的抽象, Template定义了:
当处理请求时发送给adapter 的数据格式
adapter 必须实现的gRPC service 接口
每一个Template 经过 template.proto
进行定义:
名为Template
的一个message
Name: 经过template所在的package name自动生成
template_variety: 可选Check, Report, Quota or AttributeGenerator, 决定了adapter必须实现的方法. 同时决定了在mixer的什么阶段要生成template对应的instance:
Check: 在Mixer’s Check API call时建立并发送instance
Report: 在Mixer’s Report API call时建立并发送instance
Quota: 在Mixer’s Check API call时建立并发送instance(查询配额时)
AttributeGenerator: for both Check, Report Mixer API calls
Istio 内置的Templates: istio.io/docs/refere…
封装了 Mixer 和特定外部基础设施后端进行交互的必要接口,例如 Prometheus 或者 Stackdriver
定义了须要处理的模板(在yaml中配置template)
定义了处理某个Template数据格式的GRPC接口
定义 Adapter须要的配置格式(Params)
能够同时处理多个数据(instance)
Istio 内置的Adapter: istio.io/docs/refere…
表明符合某个Template定义的数据格式的具体实现, 该具体实现由用户配置的 CRD, CRD 定义了将Attributes 转换为具体instance 的规则, 支持属性表达式
Instance CRD 是Template 中定义的数据格式 + 属性转换器
内置的Instance 类型(其实就是内置 Template): Templates
属性表达式见: Expression Language
数据流向: mixer -> adapter 实例
用户配置的 CRD, 为具体Adapter提供一个具体配置, 对应Adapter的可运行实例
用户配置的 CRD, 配置一组规则,这些规则描述了什么时候调用特定(经过Handler对应的)适配器及哪些Instance
计算机科学中的全部问题,均可以用另外一个层来解决,除了层数太多的问题
Kubernetes 自己已经很复杂, Istio 为了更高层控制的抽象, 又增长了不少概念. 复杂度堪比kubernetes.
能够看出istio 设计精良, 在处理微服务的复杂场景有不少优秀之处, 不过目前istio目前的短板仍是很明显, 高度的抽象带来了不少性能的损耗, 社区如今也有不少优化的方向, 像蚂蚁金服开源的SofaMesh 主要是去精简层, 试图在sidecar里去作不少mixer 的事情, 减小sidecar和mixer的同步请求依赖, 而一些其余的sidecar 网络方案, 更多的是考虑去优化层, 优化sidecar 这一层的性能开销.
在Istio 1.0 以前, 主要仍是以功能的实现为主, 不事后面随着社区的积极投入, 相信Istio的性能会有长足的提高.
笔者以前从事过多年的服务治理相关的工做, 过程当中切身体会到微服务治理的痛点, 因此也比较关注 service mesh的发展, 我的对istio也很是看好, 恰好今年咱们中心容器产品今年也有这方面的计划, 期待咱们能在这个方向进行一些产品和技术的深耕.
参考资料: