作者:钟华,腾讯云容器团队高级工程师,热衷于容器、微服务、service mesh、istio 等领域。 Istio 是当前Service Mesh领域最完善的解决方案,同源自kubernetes项目团队,本文根据钟华在腾讯云容器团队进行的istio主题分享和现场演示整理输出
今天分享的内容主要包括以下4个话题:
首先我会和大家一起过一下 Service Mesh的发展历程, 并看看Istio 为 Service Mesh 带来了什么, 这部分相对比较轻松. 接下来我将和大家分析一下Istio的主要架构, 重点是数据面和控制面的实现, 包括sidecar的注入, 流量拦截, xDS介绍, Istio流量模型, 分布式跟踪, Mixer 的适配器模型等等, 中间也会穿插着 istio的现场使用demo.
在计算机网络发展的初期, 开发人员需要在自己的代码中处理服务器之间的网络连接问题, 包括流量控制, 缓存队列, 数据加密等. 在这段时间内底层网络逻辑和业务逻辑是混杂在一起.
随着技术的发展,TCP/IP 等网络标准的出现解决了流量控制等问题。尽管网络逻辑代码依然存在,但已经从应用程序里抽离出来,成为操作系统网络层的一部分, 形成了经典的网络分层模式.
微服务架构是更为复杂的分布式系统,它给运维带来了更多挑战, 这些挑战主要包括资源的有效管理和服务之间的治理, 如:
在微服务架构的实现中,为提升效率和降低门槛,应用开发者会基于微服务框架来实现微服务。微服务框架一定程度上为使用者屏蔽了底层网络的复杂性及分布式场景下的不确定性。通过API/SDK的方式提供服务注册发现、服务RPC通信、服务配置管理、服务负载均衡、路由限流、容错、服务监控及治理、服务发布及升级等通用能力, 比较典型的产品有:
实施微服务的成本往往会超出企业的预期(内容多, 门槛高), 花在服务治理上的时间成本甚至可能高过进行产品研发的时间. 另外上述的方案会限制可用的工具、运行时和编程语言。微服务软件库一般专注于某个平台, 这使得异构系统难以兼容, 存在重复的工作, 系统缺乏可移植性.
Docker 和Kubernetes 技术的流行, 为Pass资源的分配管理和服务的部署提供了新的解决方案, 但是微服务领域的其他服务治理问题仍然存在.
Sidecar(有时会叫做agent) 在原有的客户端和服务端之间加多了一个代理, 为应用程序提供的额外的功能, 如服务发现, 路由代理, 认证授权, 链路跟踪 等等.
业界使用Sidecar 的一些先例:
直观地看, Sidecar 到 Service Mesh 是一个规模的升级, 不过Service Mesh更强调的是:
以下是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 正是这类系统最为突出的代表.
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的网络.
Istio来自希腊语,英文意思是「sail」, 意为「启航」
Istio Architecture(图片来自Isio官网文档)
下面是我对Istio架构总结的思维导图:
以下是Istio官网经典的 BookInfo Demo, 这是一个多语言组成的异构微服务系统:
Bookinfo Application(图片来自Isio官网文档)
下面我将现场给大家进行演示, 从demo安装开始, 并体验一下istio的流控功能:
下载istio release: https://istio.io/docs/setup/kubernetes/download-release/
kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml
helm install install/kubernetes/helm/istio --name istio --namespace istio-system
注意事项, 若要开启sidecar自动注入功能, 需要:
kubectl label namespace default istio-injection=enabled
--enable-aggregator-routing=true
且证书和api server连通性正确设置.helm delete --purge istio
kubectl delete -f install/kubernetes/helm/istio/templates/crds.yaml -n istio-system
更多安装选择请参考: https://istio.io/docs/setup/kubernetes/helm-install/
Bookinfo 是一个多语言异构的微服务demo, 其中 productpage 微服务会调用 details 和 reviews 两个微服务, reviews 会调用ratings 微服务, reviews 微服务有 3 个版本. 关于此项目更多细节请参考: https://istio.io/docs/examples/bookinfo/
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
这将创建 productpage, details, ratings, reviews 对应的deployments 和 service, 其中reviews 有三个deployments, 代表三个不同的版本.
% kubectl get pod
NAME READY STATUS RESTARTS AGE
details-v1-6865b9b99d-mnxbt 2/2 Running 0 1m
productpage-v1-f8c8fb8-zjbhh 2/2 Running 0 59s
ratings-v1-77f657f55d-95rcz 2/2 Running 0 1m
reviews-v1-6b7f6db5c5-zqvkn 2/2 Running 0 59s
reviews-v2-7ff5966b99-lw72l 2/2 Running 0 59s
reviews-v3-5df889bcff-w9v7g 2/2 Running 0 59s
% kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 172.18.255.240 <none> 9080/TCP 1m
productpage ClusterIP 172.18.255.137 <none> 9080/TCP 1m
ratings ClusterIP 172.18.255.41 <none> 9080/TCP 1m
reviews ClusterIP 172.18.255.140 <none> 9080/TCP 1m
对入口流量进行配置:
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
该操作会创建bookinfo-gateway 的Gateway, 并将流量发送到productpage服务
kubectl get gateway
NAME AGE
bookinfo-gateway 1m
此时通过bookinfo-gateway 对应的LB或者nodeport 访问/productpage 页面, 可以看到三个版本的reviews服务在随机切换
通过CRD DestinationRule创建3 个reviews 子版本:
kubectl apply -f samples/bookinfo/networking/destination-rule-reviews.yaml
通过CRD VirtualService 调整个 reviews 服务子版本的流量比例, 设置 v1 和 v3 各占 50%
kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml
刷新页面, 可以看到无法再看到reviews v2的内容, 页面在v1和v3之间切换.
修改reviews CRD, 将jason 登录的用户版本路由到v2, 其他用户路由到版本v3.
kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml
刷新页面, 使用jason登录的用户, 将看到v2 黑色星星版本, 其他用户将看到v3 红色星星版本.
更多BookInfo 示例, 请参阅: https://istio.io/docs/examples/bookinfo/, 若要删除应用: 执行脚本 ./samples/bookinfo/platform/kube/cleanup.sh
Istio 注入sidecar实现:
istioctl kube-inject
注入Pod内容:
Istio 利用 Kubernetes Dynamic Admission Webhooks 对pod 进行sidecar注入
查看istio 对这2个Webhooks 的配置 ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration:
% kubectl get ValidatingWebhookConfiguration -oyaml
% kubectl get mutatingWebhookConfiguration -oyaml
可以看出:
istio-system
中的服务 istio-galley
, 通过路由/admitpilot
, 处理config.istio.io部分, rbac.istio.io, authentication.istio.io, networking.istio.io等资源的Validating 工作istio-galley
, 通过路由/admitmixer
, 处理其他config.istio.io资源的Validating 工作istio-sidecar-injector
, 通过路由/inject
, 处理其他v1/pods
的CREATE, 同时需要满足命名空间istio-injection: enabled
数据面的每个Pod会被注入一个名为istio-init
的initContainer, initContrainer是K8S提供的机制,用于在Pod中执行一些初始化任务.在Initialcontainer执行完毕并退出后,才会启动Pod中的其它container.
initContainers:
- image: docker.io/istio/proxy_init:1.0.5
args:
- -p
- "15001"
- -u
- "1337"
- -m
- REDIRECT
- -i
- '*'
- -x
- ""
- -b
- "9080"
- -d
- ""
istio-init ENTRYPOINT 和 args 组合的启动命令:
/usr/local/bin/istio-iptables.sh -p 15001 -u 1337 -m REDIRECT -i '*' -x "" -b 9080 -d ""
istio-iptables.sh 源码地址为 https://github.com/istio/istio/blob/master/tools/deb/istio-iptables.sh
$ istio-iptables.sh -p PORT -u UID -g GID [-m mode] [-b ports] [-d ports] [-i CIDR] [-x CIDR] [-h]
-p: 指定重定向所有 TCP 流量的 Envoy 端口(默认为 $ENVOY_PORT = 15001)
-u: 指定未应用重定向的用户的 UID。通常,这是代理容器的 UID(默认为 $ENVOY_USER 的 uid,istio_proxy 的 uid 或 1337)
-g: 指定未应用重定向的用户的 GID。(与 -u param 相同的默认值)
-m: 指定入站连接重定向到 Envoy 的模式,“REDIRECT” 或 “TPROXY”(默认为 $ISTIO_INBOUND_INTERCEPTION_MODE)
-b: 逗号分隔的入站端口列表,其流量将重定向到 Envoy(可选)。使用通配符 “*” 表示重定向所有端口。为空时表示禁用所有入站重定向(默认为 $ISTIO_INBOUND_PORTS)
-d: 指定要从重定向到 Envoy 中排除(可选)的入站端口列表,以逗号格式分隔。使用通配符“*” 表示重定向所有入站流量(默认为 $ISTIO_LOCAL_EXCLUDE_PORTS)
-i: 指定重定向到 Envoy(可选)的 IP 地址范围,以逗号分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量。空列表将禁用所有出站重定向(默认为 $ISTIO_SERVICE_CIDR)
-x: 指定将从重定向中排除的 IP 地址范围,以逗号分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量(默认为 $ISTIO_SERVICE_EXCLUDE_CIDR)。
环境变量位于 $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:
- image: docker.io/istio/proxyv2:1.0.5
name: istio-proxy
args:
- proxy
- sidecar
- --configPath
- /etc/istio/proxy
- --binaryPath
- /usr/local/bin/envoy
- --serviceCluster
- ratings
- --drainDuration
- 45s
- --parentShutdownDuration
- 1m0s
- --discoveryAddress
- istio-pilot.istio-system:15007
- --discoveryRefreshDelay
- 1s
- --zipkinAddress
- zipkin.istio-system:9411
- --connectTimeout
- 10s
- --proxyAdminPort
- "15000"
- --controlPlaneAuthPolicy
- NONE
env:
......
ports:
- containerPort: 15090
name: http-envoy-prom
protocol: TCP
securityContext:
runAsUser: 1337
......
istio-proxy容器中有两个进程pilot-agent和envoy:
~ % kubectl exec productpage-v1-f8c8fb8-wgmzk -c istio-proxy -- ps -ef
UID PID PPID C STIME TTY TIME CMD
istio-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 NONE
istio-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进程Envoy配置初始化流程:
查看envoy 初始配置文件:
kubectl exec productpage-v1-f8c8fb8-wgmzk -c istio-proxy -- cat /etc/istio/proxy/envoy-rev0.json
sidecar 既要作为服务消费者端的正向代理,又要作为服务提供者端的反向代理, 具体拦截过程如下:
podIP+端口
接受inbound 流量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 涉及的概念:
Envoy 配置热更新: 配置的动态变更,而不需要重启 Envoy:
Pilot在9093端口提供了下述调试接口:
# Listeners and routes
curl {PILOT_ADDR}/debug/adsz
# Endpoints
curl {PILOT_ADDR}/debug/edsz
# Clusters
curl {PILOT_ADDR}/debug/cdsz
Sidecar Envoy 也提供了管理接口,缺省为localhost的15000端口,可以获取listener,cluster以及完整的配置数据
可以通过以下命令查看支持的调试接口:
kubectl exec productpage-v1-f8c8fb8-zjbhh -c istio-proxy curl http://127.0.0.1:15000/help
或者forward到本地就行调试
kubectl port-forward productpage-v1-f8c8fb8-zjbhh 15000
相关的调试接口:
http://127.0.0.1:15000
http://127.0.0.1:15000/help
http://127.0.0.1:15000/config_dump
http://127.0.0.1:15000/listeners
http://127.0.0.1:15000/clusters
使用istioctl 查看代理配置:
istioctl pc {xDS类型} {POD_NAME} {过滤条件} {-o json/yaml}
eg:
istioctl pc routes productpage-v1-f8c8fb8-zjbhh --name 9080 -o json
xDS 类型包括: listener, route, cluster, endpoint
查看 product 的所有listener:
% istioctl pc listener productpage-v1-f8c8fb8-zjbhh
ADDRESS PORT TYPE
172.18.255.178 15011 TCP
172.18.255.194 44134 TCP
172.18.255.110 443 TCP
172.18.255.190 50000 TCP
172.18.255.203 853 TCP
172.18.255.2 443 TCP
172.18.255.239 16686 TCP
0.0.0.0 80 TCP
172.18.255.215 3306 TCP
172.18.255.203 31400 TCP
172.18.255.111 443 TCP
172.18.255.203 8060 TCP
172.18.255.203 443 TCP
172.18.255.40 443 TCP
172.18.255.1 443 TCP
172.18.255.53 53 TCP
172.18.255.203 15011 TCP
172.18.255.105 14268 TCP
172.18.255.125 42422 TCP
172.18.255.105 14267 TCP
172.18.255.52 80 TCP
0.0.0.0 15010 HTTP
0.0.0.0 9411 HTTP
0.0.0.0 8060 HTTP
0.0.0.0 9080 HTTP
0.0.0.0 15004 HTTP
0.0.0.0 20001 HTTP
0.0.0.0 9093 HTTP
0.0.0.0 8080 HTTP
0.0.0.0 15030 HTTP
0.0.0.0 9091 HTTP
0.0.0.0 9090 HTTP
0.0.0.0 15031 HTTP
0.0.0.0 3000 HTTP
0.0.0.0 15001 TCP
172.18.3.50 9080 HTTP 这是当前pod ip 暴露的服务地址, 会路由到回环地址, 各个pod 会不一样
envoy 流量入口的listener:
% istioctl pc listener productpage-v1-f8c8fb8-zjbhh --address 0.0.0.0 --port 15001 -o json
[
{
"name": "virtual",
"address": {
"socketAddress": {
"address": "0.0.0.0",
"portValue": 15001
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.tcp_proxy",
"config": {
"cluster": "BlackHoleCluster",
"stat_prefix": "BlackHoleCluster"
}
}
]
}
],
"useOriginalDst": true # 这意味着它将请求交给最符合请求原始目标的监听器。如果找不到任何匹配的虚拟监听器,它会将请求发送给返回 404 的 BlackHoleCluster
}
]
以下是reviews的所有pod IP
% kubectl get ep reviews
NAME ENDPOINTS AGE
reviews 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
:
% istioctl pc listener productpage-v1-f8c8fb8-zjbhh --address 0.0.0.0 --port 9080 -ojson
{
"name": "0.0.0.0_9080",
"address": {
"socketAddress": {
"address": "0.0.0.0",
"portValue": 9080
}
},
......
"rds": {
"config_source": {
"ads": {}
},
"route_config_name": "9080"
},
......
查看名为9080
的 route:
% istioctl pc routes productpage-v1-f8c8fb8-zjbhh --name 9080 -o json
[
{
"name": "9080",
"virtualHosts": [
{
"name": "details.default.svc.cluster.local:9080",
"domains": [
"details.default.svc.cluster.local",
"details.default.svc.cluster.local:9080",
"details",
"details:9080",
"details.default.svc.cluster",
"details.default.svc.cluster:9080",
"details.default.svc",
"details.default.svc:9080",
"details.default",
"details.default:9080",
"172.18.255.240",
"172.18.255.240:9080"
],
"routes": [
{
"match": {
"prefix": "/"
},
"route": {
"cluster": "outbound|9080||details.default.svc.cluster.local",
"timeout": "0.000s",
"maxGrpcTimeout": "0.000s"
},
......
{
"name": "productpage.default.svc.cluster.local:9080",
"domains": [
"productpage.default.svc.cluster.local",
"productpage.default.svc.cluster.local:9080",
"productpage",
"productpage:9080",
"productpage.default.svc.cluster",
"productpage.default.svc.cluster:9080",
"productpage.default.svc",
"productpage.default.svc:9080",
"productpage.default",
"productpage.default:9080",
"172.18.255.137",
"172.18.255.137:9080"
],
"routes": [ ...... ]
},
{
"name": "ratings.default.svc.cluster.local:9080",
"domains": [
"ratings.default.svc.cluster.local",
"ratings.default.svc.cluster.local:9080",
"ratings",
"ratings:9080",
"ratings.default.svc.cluster",
"ratings.default.svc.cluster:9080",
"ratings.default.svc",
"ratings.default.svc:9080",
"ratings.default",
"ratings.default:9080",
"172.18.255.41",
"172.18.255.41:9080"
],
"routes": [ ...... ]
},
{
"name": "reviews.default.svc.cluster.local:9080",
"domains": [
"reviews.default.svc.cluster.local",
"reviews.default.svc.cluster.local:9080",
"reviews",
"reviews:9080",
"reviews.default.svc.cluster",
"reviews.default.svc.cluster:9080",
"reviews.default.svc",
"reviews.default.svc:9080",
"reviews.default",
"reviews.default:9080",
"172.18.255.140",
"172.18.255.140:9080"
],
"routes": [
{
"match": {
"prefix": "/",
"headers": [
{
"name": "end-user",
"exactMatch": "jason"
}
]
},
"route": {
"cluster": "outbound|9080|v2|reviews.default.svc.cluster.local",
"timeout": "0.000s",
"maxGrpcTimeout": "0.000s"
},
......
},
{
"match": {
"prefix": "/"
},
"route": {
"cluster": "outbound|9080|v3|reviews.default.svc.cluster.local",
"timeout": "0.000s",
"maxGrpcTimeout": "0.000s"
},
.......
}
]
}
],
"validateClusters": false
}
]
可以看到, 在9080 这个route 中, 包含所有这个端口的http 路由信息, 通过virtualHosts列表进行服务域名分发到各个cluster.
查看virtualHosts reviews.default.svc.cluster.local:9080
中的routes信息, 可以看到jason 路由到了cluster outbound|9080|v2|reviews.default.svc.cluster.local
查看该cluster:
% istioctl pc cluster productpage-v1-f8c8fb8-zjbhh --fqdn reviews.default.svc.cluster.local --subset v2 -o json
[
{
"name": "outbound|9080|v2|reviews.default.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {}
},
"serviceName": "outbound|9080|v2|reviews.default.svc.cluster.local"
},
"connectTimeout": "1.000s",
"lbPolicy": "RANDOM",
"circuitBreakers": {
"thresholds": [
{}
]
}
}
]
查看其对应的endpoint:
% istioctl pc endpoint productpage-v1-f8c8fb8-zjbhh --cluster 'outbound|9080|v2|reviews.default.svc.cluster.local'
ENDPOINT STATUS CLUSTER
172.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 链路跟踪:
Pilot Architecture(图片来自Isio官网文档)
VirtualService 中定义了一系列针对指定服务的流量路由规则。每个路由规则都是针对特定协议的匹配规则。如果流量符合这些特征,就会根据规则发送到服务注册表中的目标服务, 或者目标服务的子集或版本, 匹配规则中还包含了对流量发起方的定义,这样一来,规则还可以针对特定客户上下文进行定制.
Gateway 描述了一个负载均衡器,用于承载网格边缘的进入和发出连接。这一规范中描述了一系列开放端口,以及这些端口所使用的协议、负载均衡的 SNI 配置等内容
Istio 服务网格内部会维护一个与平台无关的使用通用模型表示的服务注册表,当你的服务网格需要访问外部服务的时候,就需要使用 ServiceEntry 来添加服务注册, 这类服务可能是网格外的 API,或者是处于网格内部但却不存在于平台的服务注册表中的条目(例如需要和 Kubernetes 服务沟通的一组虚拟机服务).
EnvoyFilter 描述了针对代理服务的过滤器,用来定制由 Istio Pilot 生成的代理配置.
Istio Gateway:·
以下是对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:
Istio:
随着微服务的拆分粒度增强, 服务调用会增多, 更复杂, 扇入 扇出, 调用失败的风险增加, 以下是常见的服务容错处理方式:
控制端 | 目的 | 实现 | 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 是策略和遥测功能中有关请求和环境的基本数据, 是用于描述特定服务请求或请求环境的属性的一小段数据。例如,属性可以指定特定请求的大小、操作的响应代码、请求来自的 IP 地址等.
Template 是对 adapter 的数据格式和处理接口的抽象, Template定义了:
每个Template 通过 template.proto
进行定义:
Template
的一个messageIstio 内置的Templates: https://istio.io/docs/reference/config/policy-and-telemetry/templates/
封装了 Mixer 和特定外部基础设施后端进行交互的必要接口,例如 Prometheus 或者 Stackdriver
Istio 内置的Adapter: https://istio.io/docs/reference/config/policy-and-telemetry/adapters/
代表符合某个Template定义的数据格式的具体实现, 该具体实现由用户配置的 CRD, CRD 定义了将Attributes 转换为具体instance 的规则, 支持属性表达式
用户配置的 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也非常看好, 刚好今年我们中心容器产品今年也有这方面的计划, 期待我们能在这个方向进行一些产品和技术的深耕.
参考资料:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。