Istio

Istio

容器云未来:Kubernetes、Istio 和 Knative

博云BoCloud 发表了文章 • 0 个评论 • 157 次浏览 • 2019-06-03 10:38 • 来自相关话题

导读 目前以Kubernetes为基础构建的容器生态逐渐完善,这其中Kubernetes、Istio、Knative三个独立项目被越来越多的人提及,并且已经开始尝试大规模落地实践,它们恰好构成了容器云的未来拼图。今天与大家一起分享下,这三个项目究 ...查看全部
导读
目前以Kubernetes为基础构建的容器生态逐渐完善,这其中Kubernetes、Istio、Knative三个独立项目被越来越多的人提及,并且已经开始尝试大规模落地实践,它们恰好构成了容器云的未来拼图。今天与大家一起分享下,这三个项目究竟解决了什么问题,为什么它们能够一鸣惊人。


随着微服务理念不断深入人心,越来越多的企业把自己的应用逐步由单体转变成微服务架构,Container容器技术的出现恰恰加速了这个转移过程,因为它有效地解决了N多服务的快速部署问题。但是随着服务数目的增多,越来越多的企业希望能够把相关服务有效地“聚合”在一起,方便统一部署与管理。Kubenretes的出现恰恰解决了大规模微服务编排部署所带来的挑战,让整个行业意识到PaaS的落地可以成为现实。

当随着微服务体系下的服务数目越来越多,服务运维成为必然要解决的问题,于是Istio出现了,基于网络代理与控制相分离的实现策略,允许对服务控制策略进行有效合理的管控。如果你想和更多容器技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

到这里似乎到了很美好的阶段:

微服务:解决应用内聚、臃肿的问题。
Container:解决服务运行环境统一,和部署问题。
Kubernetes:解决大量微服务有效“聚合”部署问题。
Istio:解决服务上线面临的一系列治理问题。

这个阶段乍一看来,构建容器云似乎有了一个完整的链路和解决方式,一切都将变得那么“完美”。

现在让我们回过头来深入分析一下,微服务体系下的服务交互,目前是否存在问题。

首先,无论是http,还是rpc,本质上都是服务与服务的远程调用。开发应用程序中,无法做到服务与服务间的彼此透明。这样会导致一个问题:无论微服务业务拆分多么“精细”,本质上业务单元之间还是不能够独立运行和发展。同时在面向不同开发领域的衍生,无法选择最合适的实现方式。因此我们希望能够基于不同的“模板”+“配置”的方式能够把开发环境标准化处理,同时提供“事件”机制,将服务与服务交互的耦合度降到最低。

其次,服务线上运行的动态伸缩问题。当下kubernetes环境下的弹性伸缩,需要由客户搜集监测数据,并自主手动来实现,但是我们更希望服务线上能够更加自动化和智能化。

最后,服务标准化问题。我们希望服务内部的模型是标准的、能够快速复制和快速构建的;服务通信是标准的:协议标准,格式标准;运行环境是标准的:快速部署,快速迁移。

Knative的出现恰好解决远程直接调用,服务线上自动管理以及一些列标准化问题。

下面我们来看一下三者的关联:


微信图片_20190603102740.png



Kubernetes和Istio相信大家比较熟悉了,这里不做过多介绍,有需要的同学可以关注下我们之前发布的相关文章,这里我们重点来看一下Knative。

Knative是谷歌开源的serverless架构方案,旨在提供一套简单易用的serverless方案,把serverless标准化。目前参与的公司主要是Google、Pivotal、IBM、Red Hat,于2018年7月份对外发布,目前处于快速发展阶段。


Knative组成


Build
构建系统:把用户定义的应用构建成容器镜像,面向kubernetes的标准化构建,区别于Dockerfile镜像构建,重点解决kubernetes环境的构建标准化问题。

Serving
服务系统:利用Istio的部分功能,来配置应用路由,升级以及弹性伸缩。Serving中包括容器生命周期管理,容器外围对象(service,ingres)生成(恰到好处的把服务实例与访问统一在一起),监控应用请求,自动弹性负载,并且利用Virtual service和destination配置服务访问规则。只有这样才能保证服务呈现一致性以及服务运行自动化管理。

Eventing
事件系统:用于自动完成事件的绑定与触发。事件系统与直接调用最大的区别在于响应式设计,它允许运行服务本身不需要屏蔽了调用方与被调用方的关系。从而在业务层面能够实现业务的快速聚合,或许为后续业务编排创新提供事件。

现在我们换一个角度,聚焦应用服务生命周期:
**· Knative 解决应用模板+面向统一环境的标准化构建场景;
· Kubernetes作为基础设施,解决应用编排和运行环境场景;
· 加粗文字Isito作为通信基础设施层,保证应用服务运行可检测、可配置、可追踪问题。**

这三者贯穿应用服务生命周期全过程,容器云恰恰也是管理应用服务的控制平台,这就能够很好地解释,为什么Kubernetes,Istio,Knative在未来会成为构建容器云的三驾马车。

Kubernetes Istio微服务架构部署和使用

翔宇 发表了文章 • 0 个评论 • 190 次浏览 • 2019-05-27 21:40 • 来自相关话题

#什么是Istio Istio是Service Mesh(服务网格)的主流实现方案。该方案降低了与微服务架构相关的复杂性,并提供了负载均衡、服务发现、流量管理、断路器、监控、故障注入和智能路由等功能特性。 其中,Si ...查看全部
#什么是Istio

Istio是Service Mesh(服务网格)的主流实现方案。该方案降低了与微服务架构相关的复杂性,并提供了负载均衡、服务发现、流量管理、断路器、监控、故障注入和智能路由等功能特性。

其中,Sidecar模式是一种将应用功能从应用本身剥离出来作为单独进程的方式。该模式允许我们向应用无侵入添加多种功能,避免了为满足第三方组件需求而向应用添加额外的配置代码。从某种意义上来说,服务对于网络是无感知的,只知道所附加的sidecar代理,它将网络依赖抽象成了Sidecar。

在Service Mesh中,我们需要了解Data Plane和Control Plane两个概念:

* Data Plane:作用是处理网格内服务间的通信,并完成服务发现、负载均衡、流量管理、健康检查等功能;
* Control Plane:作用是管理和配置智能代理用于路由流量,同时配置Mixers来应用策略、收集指标。

Istio核心组件:

* Envoy:Istio 使用 Envoy调解服务网格中所有服务的入站和出站流量。属于数据平面。
* Mixer:负责在服务网格上执行访问控制和使用策略,以及收集从Envoy和其他服务自动监控到的数据。
* Pilot:为 Envoy sidecar 提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能。属于控制平面。
* Citadel:提供访问控制和用户身份认证功能。

Istio可视化管理组件:

* Vistio:用于近乎实时地监控应用程序和集群之间的网络流量。可以参考:https://www.yangcs.net/posts/vistio-visualize-your-istio-mesh-using-netflixs-vizceral/
* Kiali:提供可视化服务网格拓扑、断路器和请求率等功能。Kiali还包括 Jaeger Tracing,可以提供开箱即用的分布式跟踪功能。可以参考:https://jimmysong.io/istio-handbook/setup/istio-observability-tool-kiali.html
* Jaeger:用于展示Istio微服务调用链关系,以及微服务工作状态监测。注意,在生产环境中,你应当使用Elasticsearch或Cassandra持久化存储Jaeger数据。可以参考:https://blog.csdn.net/ywq935/article/details/80599297
https://mathspanda.github.io/2018/09/19/jaeger-deploy/
https://blog.frognew.com/2017/12/opentracing-jaeger-3.html

其中,Kiali、Jaeger、Prometheus、Grafana管理工具,将和Istio一并部署。如果你想和更多Istio技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#使用Helm部署Istio

依赖环境:

* Helm > 2.10
* Kubernetes > 1.9

下载并解压缩istio的发布包
wget https://github.com/istio/istio/releases/download/1.0.6/istio-1.0.6-linux.tar.gz
tar -zxvf istio-1.0.6-linux.tar.gz
cd istio-1.0.6

Istio的Chart在istio-1.0.6/install/kubernetes/helm目录中,这个Chart包含了下面的代码文件。
# tree install/kubernetes/helm/istio
......
......
31 directories, 139 files

如果安装的Helm版本高于2.10,就不再需要手动使用kubectl安装Istio的CRD。反之,则需要执行如下命令安装。
kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml

查看安装的CRD。
kubectl get CustomResourceDefinition

通过各个组件在vaule file的enabled flag启用或禁用,下面创建名称为istio.yaml的vaule file,将几个默认禁用的组件也启用。
tracing:
enabled: true
servicegraph:
enabled: true
kiali:
enabled: true
grafana:
enabled: true

首先,创建名称为kiali的secret。
# echo -n 'admin' | base64
YWRtaW4=

# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

# cat <
apiVersion: v1
kind: Secret
metadata:
name: kiali
namespace: istio-system
labels:
app: kiali
type: Opaque
data:
username: YWRtaW4=
passphrase: MWYyZDFlMmU2N2Rm
EOF

执行helm安装命令。
helm install install/kubernetes/helm/istio --name istio --namespace istio-system -f istio.yaml

安装完成后确认各个组件的Pod正常运行。
# kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-59b8896965-5f9j2 1/1 Running 0 23m
istio-citadel-6f444d9999-s9jrc 1/1 Running 0 23m
istio-egressgateway-6d79447874-ssbc4 1/1 Running 0 23m
istio-galley-685bb48846-mvf5w 1/1 Running 0 23m
istio-grafana-post-install-6m256 0/1 Completed 0 23m
istio-ingressgateway-5b64fffc9f-mrl9t 1/1 Running 0 23m
istio-pilot-8645f5655b-k6fcz 2/2 Running 0 23m
istio-policy-547d64b8d7-6dgkp 2/2 Running 0 23m
istio-sidecar-injector-5d8dd9448d-zfdsb 1/1 Running 0 23m
istio-telemetry-c5488fc49-qwwcv 2/2 Running 0 23m
istio-tracing-6b994895fd-4vjfx 1/1 Running 0 23m
kiali-5f9ffff7cf-jqk8p 1/1 Running 0 23m
prometheus-76b7745b64-xjzmm 1/1 Running 0 23m
servicegraph-cb9b94c-mlhjm 1/1 Running 0 23m

Istio以一个项目的形式部署到Kubernetes集群中。我们可以看到,部署好的Pod中,除了有istio-citadel、istio-egressgateway、istio-ingressgateway、istio-pilot等Istio本身的功能组件,还集成了微服务相关的监控工具,如:Grafana、jaeger-agent、kiali、Prometheus。正是这些功能丰富且强大的监控工具,帮助Istio实现了微服务的可视化管理。
#运行示例Bookinfo

您可以部署自己的应用或者示例应用程序如Bookinfo。 注意:应用程序必须使用HTTP/1.1或HTTP/2.0协议来传递HTTP流量,因为HTTP/1.0已经不再支持。

如果运行Pod的namespace被标记为istio-injection=enabled的话,Istio-Initializer会向应用程序的Pod中自动注入Envoy容器:
kubectl label namespace  istio-injection=enabled
kubectl create -n -f .yaml

如果您没有安装Istio-initializer-injector的话,您必须使用istioctl kube-inject命令在部署应用之前向应用程序的Pod中手动注入Envoy容器:
kubectl create -f <(istioctl kube-inject -f .yaml)

Bookinfo应用由四个单独的微服务构成,用来演示多种Istio特性,包含:

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

reviews微服务有 3 个版本:

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

下图展示了这个应用的端到端架构。
1.png

运行示例bookinfo,并开启Sidecar自动注入。
# kubectl label namespace default istio-injection=enabled
# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
# kubectl apply -f samples/bookinfo/platform/consul/destination-rule-all.yaml

访问productpage:http://172.16.0.180:31380/productpage
2.png

31380端口可以通过命令获取:
kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.spec.ports[0].nodePort}'

#使用Ingress暴露管理服务

完成Istio的安装后,可以看到安装的组件除了Istio架构中的数据平面和控制平面的各个核心组件,还部署了Prometheus、Grafana、Jaeger、Kiali等辅助组件。 在云原生生态中,我们已经对这些组件很熟悉了。

* Prometheus:监控系统,收集Istio的监控数据
* Grafana:监控信息的图表展现,Istio部署的Grafana为我们内置了各个组件相关的Dashboard
* Jaeger:分布式跟踪系统,Istio中集成Jaeger可以对基于Istio的微服务实现调用链跟踪、依赖分析,为性能优化和故障排查提供支持
* kiali:kiali作为Istio的可视化管理工具,可以认为是Istio的UI,可以展现服务的网络拓扑、服务的容错情况(超时、重试、短路等)、分布式跟踪等

这些辅助组件都有自己的web界面,这里我们使用ingress的方式将这些组件暴露到集群外,以便在集群外部访问。Istio支持使用自带的istio-ingressgateway将服务暴露到集群外部,这个和Kubernetes中暴露Ingress Controller类似,有很多种方式,如NodePort,LoadBalancer,或直接开启hostNetwork: true等等。为了便于统一管理Kubernetes集群中的服务暴露,笔者更倾向使用Traefik Ingress。

使用Ingress暴露Istio服务。

编写ingress yaml文件,如下
# cat istio-ingress.yaml 
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: jaeger-query
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.jaeger-query.com
http:
paths:
- path: /
backend:
serviceName: jaeger-query
servicePort: 16686

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: prometheus
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.prometheus.com
http:
paths:
- path: /
backend:
serviceName: prometheus
servicePort: 9090

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: grafana
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.grafana.com
http:
paths:
- path: /
backend:
serviceName: grafana
servicePort: 3000

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kiali
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.kiali.com
http:
paths:
- path: /
backend:
serviceName: kiali
servicePort: 20001

执行部署命令:
kubectl apply -f istio-ingress.yaml

外部客户端,配置hosts地址解析,如下:
172.16.0.180 istio.prometheus.com
172.16.0.180 istio.jaeger-query.com
172.16.0.180 istio.grafana.com
172.16.0.180 istio.kiali.com

##访问Jaeger

浏览器访问Jaeger之前可以多次刷新productpage页面以便产生访问请求等。选择productpage.default可以查看整个调用链。使用istio.jaeger-query.com域名访问,结果展示:
3.png

##访问kiali

使用域名istio.kiali.com访问kiali页面。用户名admin,密码1f2d1e2e67df。
4.png

##访问Prometheus

使用域名istio.prometheus.com访问Prometheus页面。
5.png

##访问Grafana

使用域名istio.grafana.com访问Prometheus页面。
6.png

##Istio对Pod和服务的要求

要成为服务网格的一部分,Kubernetes 集群中的 Pod 和服务必须满足以下几个要求:

* 需要给端口正确命名:服务端口必须进行命名。端口名称只允许是<协议>[-<后缀>-]模式;
* Pod必须关联到 Kubernetes服务:如果一个 Pod 属于多个服务,这些服务不能再同一端口上使用不同协议,例如 HTTP 和 TCP。
* Deployment应带有app以及version标签:每个 Deployment 都应该有一个有意义的 app 标签和一个用于标识 Deployment 版本的 version 标签。Istio 会用 app 和 version 标签来给监控指标数据加入上下文信息。

#总结

本文实践了使用istio官方提供的helm chart在Kubernetes上部署Istio 1.0.6的过程,并使用Traefik Ingress将Istio集成的Prometheus、Grafana、Jaeger、Kiali等辅助组件暴露到集群外部,并对进入集群的流量进行管理。

在生产环境中,如果是基于公有云,如阿里云、AWS等运行Istio,建议Ingress的IP地址使用ELB地址;如果是自建的平台,则建议使用HAproxy+Keepalived提供的VIP地址,作为Ingress的IP地址,实现高可用。

如果Ingress服务,需要暴露在公网,应当使用CA认证机构颁发的证书https化(如使用cert-manager)。此外建议使用NFS、Ceph等方案实现Istio监控以及微服务应用的数据持久化存储。

Istio参考资料:

* https://istio.io/zh/docs/
* https://jimmysong.io/istio-handbook/
* http://www.servicemesher.com/

原文链接:Kubernetes Istio微服务架构部署和使用

如何为服务网格选择入口网关?

阿娇 发表了文章 • 0 个评论 • 205 次浏览 • 2019-05-21 23:02 • 来自相关话题

在启用了Istio服务网格的Kubernetes集群中,缺省情况下只能在集群内部访问网格中的服务,要如何才能从外部网络访问这些服务呢? Kubernetes和Istio提供了NodePort,LoadBalancer,Kubernetes Ingress,Is ...查看全部
在启用了Istio服务网格的Kubernetes集群中,缺省情况下只能在集群内部访问网格中的服务,要如何才能从外部网络访问这些服务呢? Kubernetes和Istio提供了NodePort,LoadBalancer,Kubernetes Ingress,Istio Gateway等多种外部流量入口的方式,面对这么多种方式,我们在产品部署中应该如何选择?

本文将对Kubernetes和Istio对外提供服务的各种方式进行详细介绍和对比分析,并根据分析结果提出一个可用于产品部署的解决方案。如果你想和更多Istio技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

说明:阅读本文要求读者了解Kubernetes和Istio的基本概念,包括Pod、Service、NodePort、LoadBalancer、Ingress、Gateway、VirtualService等。如对这些概念不熟悉,可以在阅读过程中参考文后的相关链接。
#内部服务间的通信
首先,我们来回顾一下Kubernetes集群内部各个服务之间相互访问的方法。
##Cluster IP
Kubernetes以Pod作为应用部署的最小单位。kubernetes会根据Pod的声明对其进行调度,包括创建、销毁、迁移、水平伸缩等,因此Pod 的IP地址不是固定的,不方便直接采用Pod IP对服务进行访问。

为解决该问题,Kubernetes提供了Service资源,Service对提供同一个服务的多个Pod进行聚合。一个Service提供一个虚拟的Cluster IP,后端对应一个或者多个提供服务的Pod。在集群中访问该Service时,采用Cluster IP即可,Kube-proxy负责将发送到Cluster IP的请求转发到后端的Pod上。

Kube-proxy是一个运行在每个节点上的Go应用程序,支持三种工作模式:

1、Userspace

该模式下kube-proxy会为每一个Service创建一个监听端口。发向Cluster IP的请求被Iptables规则重定向到Kube-proxy监听的端口上,Kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。

该模式下,Kube-proxy充当了一个四层Load balancer的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加两次内核和用户空间之间的数据拷贝,效率较另外两种模式低一些;好处是当后端的Pod不可用时,kube-proxy可以重试其他Pod。
1.png

Kube-proxy userspace模式(来自Kubernetes官网文档

2、iptables

为了避免增加内核和用户空间的数据拷贝操作,提高转发效率,Kube-proxy提供了iptables模式。在该模式下,Kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。

该模式下Kube-proxy不承担四层代理的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
2.png

Kube-proxy iptables模式(来自Kubernetes官网文档

3、IPVS
该模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs rules。IPVS也是在kernel模式下通过netfilter实现的,但采用了hash table来存储规则,因此在规则较多的情况下,IPVS相对iptables转发效率更高。除此以外,IPVS支持更多的LB算法。如果要设置kube-proxy为IPVS模式,必须在操作系统中安装IPVS内核模块。
3.png

Kube-proxy ipvs模式(来自Kubernetes官网文档
##Istio Sidecar Proxy
Cluster IP解决了服务之间相互访问的问题,但从上面Kube-proxy的三种模式可以看到,Cluster IP的方式只提供了服务发现和基本的LB功能。如果要为服务间的通信应用灵活的路由规则以及提供Metrics collection,distributed tracing等服务管控功能,就必须得依靠Istio提供的服务网格能力了。

在Kubernetes中部署Istio后,Istio通过iptables和Sidecar Proxy接管服务之间的通信,服务间的相互通信不再通过Kube-proxy,而是通过Istio的Sidecar Proxy进行。请求流程是这样的:Client发起的请求被iptables重定向到Sidecar Proxy,Sidecar Proxy根据从控制面获取的服务发现信息和路由规则,选择一个后端的Server Pod创建链接,代理并转发Client的请求。

Istio Sidecar Proxy和Kube-proxy的userspace模式的工作机制类似,都是通过在用户空间的一个代理来实现客户端请求的转发和后端多个Pod之间的负载均衡。两者的不同点是:Kube-Proxy工作在四层,而Sidecar Proxy则是一个七层代理,可以针对HTTP,GRPS等应用层的语义进行处理和转发,因此功能更为强大,可以配合控制面实现更为灵活的路由规则和服务管控功能。
4.jpg

Istio Sidecar Proxy
#如何从外部网络访问
Kubernetes的Pod IP和Cluster IP都只能在集群内部访问,而我们通常需要从外部网络上访问集群中的某些服务,Kubernetes提供了下述几种方式来为集群提供外部流量入口。
##NodePort
NodePort在集群中的主机节点上为Service提供一个代理端口,以允许从主机网络上对Service进行访问。Kubernetes官网文档只介绍了NodePort的功能,并未对其实现原理进行解释。下面我们通过实验来分析NodePort的实现机制。

www.katacoda.com这个网站提供了一个交互式的Kubernetes playground,注册即可免费实验Kubernetes的相关功能,下面我们就使用Katacoda来分析Nodeport的实现原理。

在浏览器中输入这个网址:https://www.katacoda.com/courses/kubernetes/networking-introduction, 打开后会提供了一个实验用的Kubernetes集群,并可以通过网元模拟Terminal连接到集群的Master节点。

执行下面的命令创建一个NodePort类型的Service。
kubectl apply -f nodeport.yaml

查看创建的Service,可以看到Kubernetes创建了一个名为webapp-nodeport-svc的Service,并为该Service在主机节点上创建了30080这个NodePort。
master $ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 36m
webapp1-nodeport-svc NodePort 10.103.188.73 80:30080/TCP 3m

webapp-nodeport-svc后端对应两个Pod,其Pod的IP分别为10.32.0.3和10.32.0.5。
master $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IPNODE NOMINATED NODE
webapp1-nodeport-deployment-785989576b-cjc5b 1/1 Running 0 2m 10.32.0.3
webapp1-nodeport-deployment-785989576b-tpfqr 1/1 Running 0 2m 10.32.0.5

通过netstat命令可以看到Kube-proxy在主机网络上创建了30080监听端口,用于接收从主机网络进入的外部流量。
master $ netstat -lnp|grep 30080
tcp6 0 0 :::30080 :::* LISTEN 7427/kube-proxy

下面是Kube-proxy创建的相关iptables规则以及对应的说明。可以看到Kube-proxy为NodePort创建了相应的IPtable规则,将发向30080这个主机端口上的流量重定向到了后端的两个Pod IP上。
iptables-save > iptables-dump
# Generated by iptables-save v1.6.0 on Thu Mar 28 07:33:57 2019
*nat
# Nodeport规则链
:KUBE-NODEPORTS - [0:0]
# Service规则链
:KUBE-SERVICES - [0:0]
# Nodeport和Service共用的规则链
:KUBE-SVC-J2DWGRZTH4C2LPA4 - [0:0]
:KUBE-SEP-4CGFRVESQ3AECDE7 - [0:0]
:KUBE-SEP-YLXG4RMKAICGY2B3 - [0:0]

# 将host上30080端口的外部tcp流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp --dport 30080 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到Cluster IP 10.103.188.73的内部流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
KUBE-SERVICES -d 10.103.188.73/32 -p tcp -m comment --comment "default/webapp1-nodeport-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到webapp1-nodeport-svc的流量转交到第一个Pod(10.32.0.3)相关的规则链上,比例为50%
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YLXG4RMKAICGY2B3
#将发送到webapp1-nodeport-svc的流量转交到第二个Pod(10.32.0.5)相关的规则链上
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -j KUBE-SEP-4CGFRVESQ3AECDE7

#将请求重定向到Pod 10.32.0.3
-A KUBE-SEP-YLXG4RMKAICGY2B3 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.3:80
#将请求重定向到Pod 10.32.0.5
-A KUBE-SEP-4CGFRVESQ3AECDE7 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.5:80

从上面的实验可以看到,通过将一个Service定义为NodePort类型,Kubernetes会通过集群中Node上的Kube-proxy为该Service在主机网络上创建一个监听端口。Kube-proxy并不会直接接收该主机端口进入的流量,而是会创建相应的Iptables规则,并通过Iptables将从该端口收到的流量直接转发到后端的Pod中。

NodePort的流量转发机制和Cluster IP的iptables模式类似,唯一不同之处是在主机网络上开了一个“NodePort”来接受外部流量。从上面的规则也可以看出,在创建Nodeport时,Kube-proxy也会同时为Service创建Cluster IP相关的iptables规则。

备注:除采用iptables进行流量转发,NodePort应该也可以提供userspace模式以及ipvs模式,这里未就这两种模式进行实验验证。



从分析得知,在NodePort模式下,集群内外部的通讯如下图所示:
5.jpg

NodePort
##LoadBalancer
NodePort提供了一种从外部网络访问Kubernetes集群内部Service的方法,但该方法存在下面一些限制,导致这种方式主要适用于程序开发,不适合用于产品部署。

* Kubernetes cluster host的IP必须是一个well-known IP,即客户端必须知道该IP。但Cluster中的host是被作为资源池看待的,可以增加删除,每个host的IP一般也是动态分配的,因此并不能认为host IP对客户端而言是well-known IP。
* 客户端访问某一个固定的host IP的方式存在单点故障。假如一台host宕机了,Kubernetes cluster会把应用reload到另一节点上,但客户端就无法通过该host的NodePort访问应用了。
* 通过一个主机节点作为网络入口,在网络流量较大时存在性能瓶颈。

为了解决这些问题,Kubernetes支持将Service定义为LoadBalancer类型。 Cloud Provider Controller监听Service的变化消息,当LoadBalancer类型的Service创建后,Cloud Provider Controller会将配置下发到Cloud Provider网络中的一个四层负载均衡器,该四层负载均衡器负责将外部网络流量分发到后面的多个节点的NodePort端口上。

下图展示了Kubernetes如何通过LoadBalancer方式对外提供流量入口,图中LoadBalancer后面接入了两个主机节点上的NodePort,后端部署了三个Pod提供服务。根据集群的规模,可以在LoadBalancer后面可以接入更多的主机节点,以进行负荷分担。
6.jpg

NodeBalancer

备注:LoadBalancer类型需要云服务提供商的支持,Service中的定义只是在Kubernetes配置文件中提出了一个要求,即为该Service创建Load Balancer,至于如何创建则是由Google Cloud或Amazon Cloud等云服务商提供的,创建的Load Balancer的过程不在Kubernetes Cluster的管理范围中。



目前AWS,Azure,CloudStack,GCE和OpenStack等主流的公有云和私有云提供商都可以为Kubernetes提供Load Balancer。一般来说,公有云提供商还会为Load Balancer提供一个External IP,以提供Internet接入。如果你的产品没有使用云提供商,而是自建Kubernetes Cluster,则需要自己提供LoadBalancer。
##Ingress
LoadBalancer类型的Service提供的是四层负载均衡器,当只需要向外暴露一个服务的时候,采用这种方式是没有问题的。但当一个应用需要对外提供多个服务时,采用该方式则要求为每一个四层服务(IP+Port)都创建一个外部load balancer。

一般来说,同一个应用的多个服务/资源会放在同一个域名下,在这种情况下,创建多个Load balancer是完全没有必要的,反而带来了额外的开销和管理成本。另外直接将服务暴露给外部用户也会导致了前端和后端的耦合,影响了后端架构的灵活性,如果以后由于业务需求对服务进行调整会直接影响到客户端。

在这种情况下,我们可以通过使用Kubernetes Ingress来统一网络入口。Kubernetes Ingress声明了一个应用层(OSI七层)的负载均衡器,可以根据HTTP请求的内容将来自同一个TCP端口的请求分发到不同的Kubernetes Service,其功能包括:

* 按HTTP请求的URL进行路由,同一个TCP端口进来的流量可以根据URL路由到Cluster中的不同服务,如下图所示:
7.png

Simple fanout

* 按HTTP请求的Host进行路由,同一个IP进来的流量可以根据HTTP请求的Host路由到Cluster中的不同服务,如下图所示:
8.png

Name based virtual hosting

Ingress规则定义了对七层网关的要求,包括URL分发规则,基于不同域名的虚拟主机,SSL证书等。Kubernetes使用Ingress Controller 来监控Ingress规则,并通过一个七层网关来实现这些要求,一般可以使用Nginx,HAProxy,Envoy等。

虽然Ingress Controller通过七层网关为后端的多个Service提供了统一的入口,但由于其部署在集群中,因此并不能直接对外提供服务。实际上Ingress需要配合NodePort和LoadBalancer才能提供对外的流量入口,如下图所示:
9.png

采用Ingress,NodePortal和LoadBalancer提供外部流量入口的拓扑结构
上图描述了如何采用Ingress配合NodePort和Load Balancer为集群提供外部流量入口,从该拓扑图中可以看到该架构的伸缩性非常好,在NodePort,Ingress,Pod等不同的接入层面都可以对系统进行水平扩展,以应对不同的外部流量要求。

上图只展示了逻辑架构,下面的图展示了具体的实现原理:
10.png

采用Ingress,NodePortal和LoadBalancer提供外部流量入口的实现原理
流量从外部网络到达Pod的完整路径如下:

  1. 外部请求先通过四层Load Balancer进入内部网络
  2. Load Balancer将流量分发到后端多个主机节点上的NodePort(userspace转发)
  3. 请求从NodePort进入到Ingress Controller(iptabes规则,Ingress Controller本身是一个NodePort类型的Service)
  4. Ingress Controller根据Ingress rule进行七层分发,根据HTTP的URL和Host将请求分发给不同的Service(userspace转发)
  5. Service将请求最终导入到后端提供服务的Pod中(iptabes规则)

从前面的介绍可以看到,Kubernetes Ingress提供了一个基础的七层网关功能的抽象定义,其作用是对外提供一个七层服务的统一入口,并根据URL/HOST将请求路由到集群内部不同的服务上。
#如何为服务网格选择入口网关?
在Istio服务网格中,通过为每个Service部署一个Sidecar代理,Istio接管了Service之间的请求流量。控制面可以对网格中的所有sidecar代理进行统一配置,实现了对网格内部流量的路由控制,从而可以实现灰度发布,流量镜像,故障注入等服务管控功能。但是,Istio并没有为入口网关提供一个较为完善的解决方案。
##Kubernetes Ingress
在0.8版本以前,Istio缺省采用Kubernetes Ingress来作为Service Mesh的流量入口。Kubernetes Ingress统一了应用的流量入口,但存在两个问题:

* Kubernetes Ingress是独立在Istio体系之外的,需要单独采用Ingress rule进行配置,导致系统入口和内部存在两套互相独立的路由规则配置,运维和管理较为复杂。
* Kubernetes Ingress rule的功能较弱,不能在入口处实现和网格内部类似的路由规则,也不具备网格Sidecar的其它能力,导致难以从整体上为应用系统实现灰度发布、分布式跟踪等服务管控功能。


11.jpg

采用Kubernetes Ingress作为服务网格的流量入口
##Istio Gateway
Istio社区意识到了Ingress和Mesh内部配置割裂的问题,因此从0.8版本开始,社区采用了 Gateway 资源代替K8s Ingress来表示流量入口。

Istio Gateway资源本身只能配置L4-L6的功能,例如暴露的端口,TLS设置等;但Gateway可以和绑定一个VirtualService,在VirtualService 中可以配置七层路由规则,这些七层路由规则包括根据按照服务版本对请求进行导流,故障注入,HTTP重定向,HTTP重写等所有Mesh内部支持的路由规则。

Gateway和VirtualService用于表示Istio Ingress的配置模型,Istio Ingress的缺省实现则采用了和Sidecar相同的Envoy proxy。

通过该方式,Istio控制面用一致的配置模型同时控制了入口网关和内部的sidecar代理。这些配置包括路由规则,策略检查、Telementry收集以及其他服务管控功能。
12.jpg

采用Istio Ingress Gateway作为服务网格的流量入口
##应用对API Gateway的需求
采用Gateway和VirtualService实现的Istio Ingress Gateway提供了网络入口处的基础通信功能,包括可靠的通信和灵活的路由规则。但对于一个服务化应用来说,网络入口除了基础的通讯功能之外,还有一些其他的应用层功能需求,例如:

* 第三方系统对API的访问控制
* 用户对系统的访问控制
* 修改请求/返回数据
* 服务API的生命周期管理
* 服务访问的SLA、限流及计费
* ……


13.png

Kubernetes ingress,Istio Gateway and API Gateway的功能对比

API Gateway需求中很大一部分需要根据不同的应用系统进行定制,目前看来暂时不大可能被纳入Kubernetes Ingress或者Istio Gateway的规范之中。为了满足这些需求,涌现出了各类不同的Kubernetes Ingress Controller以及Istio Ingress Gateway实现,包括Ambassador,Kong,Traefik,Solo等。

这些网关产品在实现在提供基础的Kubernetes Ingress能力的同时,提供了强大的API Gateway功能,但由于缺少统一的标准,这些扩展实现之间相互之间并不兼容。而且遗憾的是,目前这些Ingress Controller都还没有正式提供和Istio 控制面集成的能力。

备注:

* Ambassador将对Istio路由规则的支持纳入了Roadmap https://www.getambassador.io/user-guide/with-istio/
* Istio声称支持Istio-Based Route Rule Discovery(尚处于实验阶段)https://gloo.solo.io/introduction/architecture/

##采用API Gateway + Sidecar Proxy作为服务网格的流量入口
在目前难以找到一个同时具备API Gateway和Isito Ingress能力的网关的情况下,一个可行的方案是使用API Gateway和Sidecar Proxy一起为服务网格提供外部流量入口。

由于API Gateway已经具备七层网关的功能,Mesh Ingress中的Sidecar只需要提供VirtualService资源的路由能力,并不需要提供Gateway资源的网关能力,因此采用Sidecar Proxy即可。网络入口处的Sidecar Proxy和网格内部应用Pod中Sidecar Proxy的唯一一点区别是:该Sidecar只接管API Gateway向Mesh内部的流量,并不接管外部流向API Gateway的流量;而应用Pod中的Sidecar需要接管进入应用的所有流量。
14.png

采用API Gateway + Sidecar Proxy为服务网格提供流量入口

备注:在实际部署时,API Gateway前端需要采用NodePort和LoadBalancer提供外部流量入口。为了突出主题,对上图进行了简化,没有画出NodePort和LoadBalancer。

采用API Gateway和Sidecar Proxy一起作为服务网格的流量入口,既能够通过对网关进行定制开发满足产品对API网关的各种需求,又可以在网络入口处利用服务网格提供的灵活的路由能力和分布式跟踪,策略等管控功能,是服务网格产品入口网关的一个理想方案。

性能方面的考虑:从上图可以看到,采用该方案后,外部请求的处理流程在入口处增加了Sidecar Proxy这一跳,因此该方式会带来少量的性能损失,但该损失是完全可以接受的。

对于请求时延而言,在服务网格中,一个外部请求本来就要经过较多的代理和应用进程的处理,在Ingress处增加一个代理对整体的时延影响基本忽略不计,而且对于绝大多数应用来说,网络转发所占的时间比例本来就很小,99%的耗时都在业务逻辑。如果系统对于增加的该时延非常敏感,则我建议重新考虑是否应该采用微服务架构和服务网格,毕竟任何架构模式都不是万能的,不能因为有了锤子,看什么都像钉子。

对于吞吐量而言,如果入口处的网络吞吐量存在瓶颈,则可以通过对API Gateway + Sidecar Proxy组成的Ingress整体进行水平扩展,来对入口流量进行负荷分担,以提高网格入口的网络吞吐量。

原文链接:如何为服务网格选择入口网关?(作者:赵化冰)

Istio 服务注册插件机制代码解析

老马 发表了文章 • 0 个评论 • 172 次浏览 • 2019-05-21 22:24 • 来自相关话题

集成Istio的Breeze新版本全面发布

wise2c 发表了文章 • 0 个评论 • 160 次浏览 • 2019-05-21 17:49 • 来自相关话题

睿云智合在2018年12月随着官方Kubernetes v1.13版本的推出,在相应Breeze版本里集成了云原生监控工具Prometheus(基于Operator方式部署),作为一款优秀的Kubernetes部署工具,Breeze的核心优势在于: ...查看全部
睿云智合在2018年12月随着官方Kubernetes v1.13版本的推出,在相应Breeze版本里集成了云原生监控工具Prometheus(基于Operator方式部署),作为一款优秀的Kubernetes部署工具,Breeze的核心优势在于:

1、真正的100%离线环境支持(image和rpm保证基于官方未做任何修改);

2、图形化操作降低上手难度;

3、简化K8s繁琐的证书更新管理,避免过期问题导致集群停摆;

4、不仅仅是K8s自身的安装,同时引入了生态链工具的模块安装。


随着ServiceMesh技术的持续火热,我们在近期的各个主要分支版本(v1.11.x / v1.12.x / v1.13.x / v1.14.x)开始集成完整的Istio(包含了Kiali图形化Istio管理工具、分布式追踪Jaeger、基于Prometheus+Grafana的Istio监控)。例如在对应Kubernetes v1.14.2的Breeze v1.14.2,我们集成了最新的Helm v0.24.0 + Istio v1.1.7组件,仍然一如既往的一键式离线部署:


用户只需要选择一台K8s master节点,添加Istio角色并确认各服务暴露的端口,即可将其部署至全新或现有K8s集群中:
图片1.png

图片2.png

图片3.png



部署完成后,对集群进行检查:
图片4.png

图片5.png

图片6.png


登录各服务暴露的端口:

Kiali:

http://任意服务器IP:30201/kiali
图片7.png

图片8.png


Jaeger:

http://任意服务器IP:30280
图片9.png


Prometheus for Istio:

http://任意服务器IP:30290
图片10.png


Grafana for Istio:

http://任意服务器IP:30292
图片11.png



关于睿云智合

深圳睿云智合科技有限公司成立于2012年,总部位于深圳,并分别在成都、深圳设立了研发中心,北京、上海设立了分支机构,核心骨干人员全部为来自金融、科技行业知名企业资深业务专家、技术专家。早期专注于为中国金融保险等大型企业提供创新技术、电子商务、CRM等领域专业咨询服务。

自2016年始,在率先将容器技术引进到中国保险行业客户后,公司组建了专业的容器技术产品研发和实施服务团队,旨在帮助中国金融行业客户将容器创新技术应用于企业信息技术支持业务发展的基础能力改善与提升,成为中国金融保险行业容器技术服务领导品牌。

此外,凭借多年来在呼叫中心领域的业务经验与技术积累,睿云智合率先在业界推出基于开源软交换平台FreeSwitch的微服务架构多媒体数字化业务平台,将语音、视频、webchat、微信、微博等多种客户接触渠道集成,实现客户统一接入、精准识别、智能路由的CRM策略,并以容器化治理来支持平台的全应用生命周期管理,显著提升了数字化业务处理的灵活、高效、弹性、稳定等特性,为帮助传统企业向“以客户为中心”的数字化业务转型提供完美的一站式整体解决方案。

Linkerd or Istio?哪个Service Mesh框架更适合你?

博云BoCloud 发表了文章 • 0 个评论 • 487 次浏览 • 2019-04-30 14:09 • 来自相关话题

翻译 | 宋松 原文 | https://medium.com/solo-io/linkerd-or-istio-6fcd2aad6e42 本周我开始写一篇比较Istio和Linked的帖子,并 ...查看全部
翻译 | 宋松
原文 | https://medium.com/solo-io/linkerd-or-istio-6fcd2aad6e42



本周我开始写一篇比较Istio和Linked的帖子,并且告诉我自己:我将用一个表格来比较两者的特性,这将会很棒,人们会爱上它,这个世界将会幸福几秒钟。我向自己承诺这将是一个公平的比较,没有任何偏见。虽然比较的表格仍然存在,但我转移了文章的终点:目标不再是哪个更好,而是哪个更适合你、你的应用程序和你的组织。

在职业生涯的一段时间中,我曾担任某公司的售前架构师,记得有很多次我们被要求填写产品比较表。我经常需要运用创造力来确保产品看起来很好,几乎不惜一切代价避免表格中令人不愉快的“不支持”的框。考虑到诚信工作,但是有时候不得不这样做。

站在评价者的角度来看,我理解他们(希望)的目的是进行公平的比较,在这种程度上,对比的表格似乎是一种可靠的方式。我们知道一个项目的成功可以预测职业的发展,我们都喜欢这一点。但问题是:如果评估的最终目标是产品对比表格,而不是能让企业更有竞争力的高质量软件,那么这个评估的最后将只是一些“表格”的工作。

产品比较并不是最终目的,通过比较知道哪些对你的用例最好才是最终目的。因此让我们通过七个方面来深入研究Service Mesh,主要是以下几个方面:

  • 流量管理
  • 安全
  • 安装/配置
  • 支持的环境
  • 监测
  • 策略管理
  • 性能
对于上述七个方面中的每一个,我都将发表个人观点,希望我的观点能够帮你做出更接近于简洁的决策。#流量管理需要强调的是,Istio和Linkerd的区别在于数据平面使用了两种不同的代理技术。Istio使用Envoy作为其代理。Envoy是C++编写的,最初是由Lyft构建,以便以非Kubernetes方式促进微服务的流量管理。许多公司已经将Envoy扩展为Kubernetes的ingress技术。Linkerd(v2)使用的是一种名为Linkerd-proxy的专用服务网格代理。这个代理是使用Rust编写的,与该代理一起,许多低级代理(网络客户机与服务器)功能在另一个也是由rust编写名为Tower的项目中实现。Tower依赖于Tokio,Tokio是一个由Rust编写的事件驱动非阻塞I/O库。如果你和我一样欣赏统计学,那么Rust已经连续四年(2016、2017、2018、2019)一直是Stack-overflow最受欢迎的语言。
微信截图_20190429162020.png
Istio是构建与Envoy之上的因此在流量管理方面它是占据优势的,Envoy已经包含了重要的IMHO功能,比如子集路由。用户仍然可以使用Linkerd实现金丝雀/蓝绿/a-b发布,但必须依靠单独的Kubernetes服务和能够分发流量的集群ingress技术,比如Gloo(gloo.solo.io)。Linkerd团队在最近一次社区会议上公开表示,计划在未来的版本中实现更加高级的L7流量管理功能。#安全关于安全,我正在考虑保护通信通道的能力。Istio和Linkerd两者都提供了合理的安全保护功能。
微信截图_20190429162033.png
Istio和Linkerd都依赖于外部根证书,因此两者都能保证进行安全通信。这听起来像是一个很好的周末项目,你觉得呢?#安装和配置
3.png
鉴于Istio可以安装在许多不同的平台上,安装说明可能会存在很大的不同。在写这篇文章的时候,关于Linkerd的安装,我对一些预先需要安装功能的检查印象很深刻。有很多次我在共享的Kubernetes集群中安装一些Linkerd功能时,我不清楚我是否拥有必要的权限。对于Linkerd,pre-check(或check-pre)检查你是否拥有在安装过程中创建Kubernetes所需资源的权限。#环境支持和部署模型对于是选择kubernetes或者是非Kubernetes安装,这是一个很直接的问题,Linkerd2是用基于kubernetes方式构建的,至少目前是这样的,而Istio收到了一下其他的公司的贡献,希望istio能在非kubernetes环境中运行。
4.png
考虑多集群部署,客观来说对于它的解释可能很棘手。从技术上来讲,共享根CA证书的多个不同集群(具有不同的控制平面)上的服务之间可以有效的通信。Istio扩展了上述概念,因为它支持不同情形下的多个集群:
  • 单个控制平面即可满足不同集群之间网络连接和pod之间IP寻址。
  • 通过使用具有单个控制平面的集群边界网关(egress和ingress)即可访问多个集群上的kubernetes API服务器。

在上述两种情况下,包含控制平面的集群将成为mesh管理的SPOF(single point of failure)。在我们这个可以在同一区域下的多个可用区域上部署单个集群的世界中,这将不再是一个问题,但仍然不能完全忽略它。




#监测



5.png




可以说Istio的管理控制台是一个缺失的部分。 Kiali Observability Console确实解决了一些管理员对service mesh所需的一些需求。

Kiali(κιάλι)是一个希腊词,意思是望远镜,从Kiali的网站上可以清楚的看到它打算成为一个可监测性的控制台,而不仅仅是一个Service Mesh管理控制台。

Linkerd控制台还不完整,但是社区决定也要构建一个管理仪表盘的目标是一个优势。

Linkerd未能提供请求追踪。想要以非侵入方式查看请求追踪跨度必须等待Linkerd实现该功能。Istio利用了Envoy支持添加追踪headers的事实。

应该提醒用户,应用程序需要准备好转发跟踪headers,如果没有准备,代理可以生成新的跟踪IDS,这可能会无意中将单个请求分割为多个请求跨度使请求之间失去必要的关联性。大多数开发框架都有转发headers的选项,而无需用户编写大量的代码。



#策略管理

Istio的爱好者,请欢欣鼓舞!Istio的策略管理能力令人印象深刻。

该项目构建了一个可扩展的策略管理机制,允许其他技术可从多个方面与Istio集成,请参阅下面的“template”列表以及一些集成的提供者。你可以认为“template”是一种集成。


6.png



为了突出其他策略类型,Istio也可适用于rating和limiting以及提供对主体身份验证的开箱即用支持。Linkerd用户依赖集群ingress控制器提供rating和limiting。

对于主体身份验证,我一直认为它应该委托给应用程序。请记住#4分布式计算的谬论:网络是安全的。对此持零信任策略。


7.png



Istio令人印象深刻的策略管理能力是需要代价的。考虑到他的广泛性,管理众多的选项增加了本已昂贵的运营成本。

Istio(Mixer)的策略管理组件也增加了显著的性能,我们将在下面详细讨论。



#性能

对比表在哪里?幸运的是,就在最近,发布了两个很棒的博客,对Istio和Linkerd的性能进行了比较,我在下面引用了其中一些结论:

对于这种综合工作负载,Istio的Envoy代理使用比Linkerd多50%的CPU。Linkerd的控制平面使用了一小部分Istio,特别是在考虑“core”组件时。



——Michael Kipper — Benchmarking Istio & Linkerd CPU(https://medium.com/@ihcsim/linkerd-2-0-and-istio-performance-benchmark-df290101c2bb)

And…

在本实验中,与基线设置相比,Linkerd2-meshed设置和Istio-meshed设置都经历了更高的延迟和更低的吞吐量。在Istio-meshed设置中产生的延迟高于在Linkerd2-meshed设置中观察到的延迟。Linkerd2-Meshed设置能够处理比Istio-Meshed设置更高的HTTP和GRPC ping吞吐量。



——Ivan Sim — Linkerd 2.0 and Istio Performance Benchmark(https://medium.com/@ihcsim/linkerd-2-0-and-istio-performance-benchmark-df290101c2bb)

意识到Mixer所增加的处理时间,Istio团队目前正致力于重写Mixer组件:“Mixer将用c++重新并直接嵌入到Envoy中。将不再有任何独立的Mixer服务。这将提高性能并降低运营复杂性。”



—Source Mixer V2 Design Document(https://docs.google.com/document/d/1QKmtem5jU_2F3Lh5SqLp0IuPb80_70J7aJEYu4_gS-s/edit)



#总结



是的,Istio比Linkerd2.3有多的特性。这是很好的,更多的特性意味着处理更复杂和边缘用例的能力增强。这没什么神奇的,更多的特性通常意味着更多的配置,潜在的资源利用率和运营成本的增加,所有这里有三条建议:



如果你不知道80%最常见的工作负载是什么样子的,那么你将很难选择服务网格。如果你不知道这些数字,你的企业可能还没有准备好进行服务网格的使用。如果你只是在探索,那就另当别论了。

如果你想计划解决所有可能的当前和未来的cases(通常叫做comparison spreadsheet),那么你将会有一段糟糕的时间。你很可能会过度获取,这对你购买的任何软件都是如此。

盲目的选择一种技术或另一种会让你过的很糟糕。炒作可能很厉害,但请记住,你并不是在炒作业务(除非真的在炒作)。

试试Istio和Linkerd! Solo SuperGloo是最简单的方式。

我使用SuperGloo是因为它非常简单,可以快速启动两个服务网格,而我几乎不需要做任何努力。我们并没有在生产中使用它,但是它非常适合这样的任务。每个网格实际上是两个命令。

——Michael Kipper — Benchmarking Istio & Linkerd CPU — Shopify(https://medium.com/@michael_87395/benchmarking-istio-linkerd-cpu-c36287e32781)。



微信图片_20190429150753.png




在Solo.io(https://www.solo.io/),我们希望为你的服务网格采用之旅提供便利。 Solo SuperGloo我们的服务Mesh orchestrator可以通过直观简单的命令安装和管理流行的服务网格技术。 正如Michael上面所指出的那样,安装Istio或Linkerd会成为一个单行活动。 SuperGloo并不止于此,它在不同的服务网格技术之上提供了一个抽象,允许对多个网格进行一致且可重复的操作。 SuperGloo是完全开源的,you can try it right now(https://supergloo.solo.io/)。

本文由博云研究院原创翻译发表,转载请注明出处。

DockOne微信分享(二零八):华尔街见闻Istio生产实践

尼古拉斯 发表了文章 • 0 个评论 • 752 次浏览 • 2019-04-24 18:41 • 来自相关话题

【编者的话】随着见闻业务不断增加,所涉及语⾔也越来越多。由于微服务化的引入,就需要为不同语言开发各自的服务发现、监控、链路追踪等组件,更新运维成本较高。同时应用的灰度部署也是见闻在着⼒解决的问题。 Istio通过下沉基础设置,很好的解决了组件跨语言兼容问题, ...查看全部
【编者的话】随着见闻业务不断增加,所涉及语⾔也越来越多。由于微服务化的引入,就需要为不同语言开发各自的服务发现、监控、链路追踪等组件,更新运维成本较高。同时应用的灰度部署也是见闻在着⼒解决的问题。 Istio通过下沉基础设置,很好的解决了组件跨语言兼容问题, 同时带来了智能路由、服务熔断、错误注入等重要的特性。整个搭建过程中也遇到了很多坑和经验,希望和大家分享。

见闻开发团队以Golang为主,同时存在Python,Java服务,这就需要SRE提供更容易接入的微服务基础组件,常见的方案就是为每种语言提供适配的微服务基础组件,但痛点是基础组件更新维护的成本较高。

为了解决痛点,我们将目光放到服务网格,它能利用基础设施下沉来解决多语言基础库依赖的问题,不同的语言不需要再引入各种不同的服务发现、监控等依赖库,只需简单的配置并运行在给定的环境下,就能享有服务发现、流量监控、链路追踪等功能,同时网络作为最重要的通信组件,可以基于它实现很多复杂的功能,譬如智能路由、服务熔断降级等。

我们调研了一些服务网格方案,包括Istio、Linkerd。

对比下来,Istio拥有更多活跃的开源贡献者,迭代速度快,以及Istio架构可行性讨论,我们选择Istio作为实践方案。

服务网格架构图:
1.png

这张图介绍了华尔街见闻典型的服务网格架构,左半图介绍了用户请求是如何处理,右半图介绍运维系统是如何监控服务。
#架构可行性
通过架构图,我们拆分出以下关键组件,经过评估,Istio高度模块化、可拓展,各个组件的可用性、拓展性都有相应的策略达到保障,我们认为Istio是具有可实施性的。
##Istio Ingress高性能,可拓展

性能:Istio Ingress用来处理用户入流量,使用Envoy实现,转发性能高。


可用性:保证实例数量并使用服务探活接口保证服务可用性。


拓展性:挂载在负载均衡后,通过增加实例实现可拓展。


##Istio Proxy随应用部署,轻微性能损耗,可随应用数量拓展

Istio Proxy以Sidecar形式随应用一起部署,增加2次流量转发,存在性能损耗。


性能:4核8G服务器,上面运行Proxy服务和API服务,API服务只返回ok字样。(此测试只测试极限QPS)


单独测试API服务的QPS在59k+,平均延时在1.68ms,CPU占用4核。 通过代理访问的QPS6.8k+,平均延时14.97ms,代理CPU占用2核,API服务CPU占用2核。


CPU消耗以及转发消耗降低了QPS,增加了延时,通过增加机器核数并增加服务部署数量解决该问题,经过测试环境测试,延时可以接受。 


可用性:基于Envoy,我们认为Envoy的可用性高于应用。依赖Pilot Discovery进行服务路由,可用性受Pilot Discovery影响。


拓展性:Sidecar形式,随应用数拓展。


##Istio Policy服务可拓展,但同步调用存在风险

Istio Policy需要在服务调用前访问,是同步请求,会增加服务调用延时,通过拓展服务数量增加处理能力。属于可选服务,华尔街见闻生产环境未使用该组件。 


性能:未测试。


可用性:若开启Policy,必须保证Policy高可用,否则正常服务将不可用。


拓展性:增加实例数量进行拓展。

##Istio Telemetry监控收集服务

性能:从监控上观察Report 5000qps,使用25核,响应时间p99在72ms。异步调用不影响应用的响应时间。


可用性:Telemetry不影响服务可用性。


拓展性:增加实例数量进行拓展。

##Pilot Discovery

性能:服务发现组件(1.0.5版本)经过监控观察,300个Service,1000个Pod,服务变更次数1天100次,平均CPU消耗在0.04核左右,内存占用在1G以内。


可用性:在服务更新时需要保证可用,否则新创建的Pod无法获取最新路由规则,对于已运行Pod由于Proxy存在路由缓存不受Pilot Discovery关闭的影响。


拓展性:增加实例数量可以增加处理量。
#服务监控
Istio通过mixer来搜集上报的遥测数据,并自带Prometheus、Grafana等监控组件,可方便的对服务状态进行监控。见闻目前监控在用Istio自带的,利用Prometheus拉取集群指标,经由Grafana看板展示,可直观展示出各种全局指标及应用服务指标,包括全局QPS、全局调用成功率、各服务延时分布情况、QPS及状态码分布等, 基本满足监控所需。

存储暂未做持久化操作,采用Prometheus的默认的内存存储,数据的存储策略可通过设定Prometheus的启动参数`--storage.tsdb.retention`来设定,见闻生产时间设定为了6h。

Prometheus服务由于数据存储原因会消耗大量内存,所以在部署时建议将Prometheus部署在专有的大内存node节点上,这样如果内存使用过大导致该node节点报错也不会对别的服务造成影响。Istio mixer担负着全网的遥测数据搜集任务,容易成为性能瓶颈,建议和Prometheus一样将其部署在专有节点上, 避免出现问题时对应用服务造成影响。

以下是Mesh汇总面板的Demo:
2.jpg

Service Mesh汇总监控页面
#链路追踪
Envoy原生支持分布式链路追踪, 如Jaeger、Zipkin等,见闻生产选择了Istio自带的Jaeger作为自身链路追踪系统。 默认Jaeger服务为all_in_one形式,包含jaeger-collect、jaeger-query、jaeger-agent等组件,数据存储在内存中。

见闻测试集群采用了此种部署形式。见闻生产环境基于性能与数据持久性考虑,基于Cassandra存储搭建了单独的jaeger-collect、jaeger-query服务。Jaeger兼容Zipkin,可以通过设定Istio ConfigMap中的`zipkinAddress`参数值为jaeger-collector对应地址,来设置Proxy的trace上报地址。同时通过设置istio-pilot环境变量`PILOT_TRACE_SAMPLING`来设置tracing的采样率,见闻生产采用了1%的采样率。

Tracing不像Istio监控系统一样对业务代码完全无侵入性。Envoy在收发请求时若发现该请求没有相关trace headers,就会为该请求自动创建。tracing的实现需要对业务代码稍作变动,这个变动主要用来传递trace相关的header,以便将一次调用产生的各个span串联起来。

见闻底层采用 grpc 微服务框架,在Gateway层面将trace header 加入到入口grpc调用的context中,从而将trace headers 逐级传递下去。
3.jpg

#Istio探活
Istio通过向Pod注入Sidecar接管流量的形式实现服务治理,那么就会有Sidecar与业务容器状态不同步的可能,从而造成各种的调用问题,如下两方面:

* Sidecar就绪时间晚于业务容器:业务容器此时若发起调用,由于Sidecar还未就绪, 就会出现类似no healthy upstream之类错误。若此时该Pod接收请求,就又会出现类似upstream connect error错误。
* Sidecar就绪时间早于业务容器:例如某业务容器初始化时间过长导致Kubernetes误以为该容器已就绪,Sidecar开始进行处理请求,此时就会出现类似upstream connect error错误。

4.jpg

5.jpg

探活涉及Sidecar、业务容器两部分,只有两部分同时就绪,此Pod才可以正式对外提供服务,分为下面两方面:

* Sidecar探活:v1.0.3及以上版本针对Pilot-agent新增了一个探活接口healthz/ready,涉及statusPort、applicationPorts、adminPort等三个端口。其基本逻辑为在statusPort上启动健康监测服务,监听applicationPorts设定的端口是否至少有一个成功监听,之后通过调用本地adminPort端口获取xDS同步状态。若满足至少一个applicationPort成功监听,且CDS、LDS都进行过同步,则该Sidecar才被标记为Ready。
* 业务容器探活:见闻通过基本库,在所有Golang grpc后端服务中注册了一个用于健康检查的handler, 该handler可由开发人员根据自身业务自定义,最后根据handler返回值来判断业务容器状态(如下图)。

6.jpg

#Istio应用更新
为了实现灰度部署,见闻基于Kubernetes Dashboard进行了二次开发,增加了对Istio相关资源的支持,利用Gateway、VirtualService、DestinationRule等crd实现了应用程序的灰度部署,实际细节如下:

1. 更新流量控制将流量指向已有版本
,利用VirtualService将流量全部指向v1版本(见下动图)。
2. 部署新版本的Deployment
,查找旧的Deployment配置,通过筛选app标签符合应用名的Deployment,运维人员基于该Deployment创建v2版本的Deployment,并向destinationRule中增加v2版本。
3. 更新流量控制将流量指向新版,本
利用VirtualService将ServiceA的服务流量全部指向v2版本。
4. 下线老版本的Deployment并删除对应DestinationRule。

利用Istio Dashboard来实现上述流程:
07.gif

为了方便开发人员服务部署,开发了精简版后台,并对可修改部分进行了限定。最终,SRE提供两个后台,对Istio Dashboard进行精细控制:
08.gif

#实践中的宝贵经验
在Istio实践过程中,有哪些需要注意的问题。
##API server的强依赖,单点故障

Istio对Kubernetes的API有很强的依赖,诸如流量控制(Kubernetes资源)、集群监控(Prometheus通过Kubernetes服务发现查找Pod)、服务权限控制(Mixer Policy)。所以需要保障API server的高可用,我们曾遇到Policy组件疯狂请求Kubernetes API server使API server无法服务,从而导致服务发现等服务无法更新配置。



* 为避免这种请求,建议使用者了解与API server直接通信组件的原理,并尽量减少直接通信的组件数量,增加必要的Rate limit。


* 尽量将与API server通信的服务置于可以随时关闭的环境,这是考虑如果部署在同一Kubernetes集群,如果API server挂掉,无法关闭这些有问题的服务,导致死锁(又想恢复API server,又要依靠API server关闭服务)。

##服务配置的自动化

服务配置是Istio部署后的重头戏,避免使用手动方式更改配置,使用代码更新配置,将常用的几个配置更新操作做到运维后台,相信手动一定会犯错。
##关于Pilot Discovery

Pilot Discovery 1.0.0版本有很大的性能问题,1.0.4有很大的性能提升,但引入了一个新bug,所以请使用1.0.5及以上的版本,我们观察到CPU消耗至少是1.0.0版本的1/10,大大降低了Proxy同步配置的延时。
##关于Mixer Policy 1.0.0

这个组件曾导致API server负载过高(很高的list pods请求),所以我们暂时束之高阁,慎用。
##性能调优

在使用Proxy、Telemetry时,默认它们会打印访问日志,我们选择在生产上关闭该日志。
时刻观察Istio社区的最新版本,查看新版本各个组件的性能优化以及bug修复情况,将Istio当做高度模块化的系统,单独升级某些组件。上面就提到我们在Istio1.0的基础上使用了1.0.5版本的Policy、Telemetry、Pilot Discovery等组件。
##服务平滑更新和关闭

Istio依靠Proxy来帮助APP进行路由,考虑几种情况会出现意外的状态:


* APP启动先于Proxy,并开始调用其它服务,这时Proxy尚未初始化完毕,APP调用失败。


* Service B关闭时,调用者Service A的Proxy尚未同步更新Service B关闭的状态,向Service B发送请求,调用失败。
第一种情况要求APP有重试机制,能适当重试请求,避免启动时的Proxy初始化与APP初始化的时差,Istio提供了retry次数配置,可以考虑使用。 
第二种情况,一种是服务更新时,我们使用新建新服务,再切流量;一种是服务异常退出,这种情况是在客户端重试机制。希望使用Istio的开发人员有更好的解决方案。

#Q&A
Q:学Service Mesh什么用?
A:Service Mesh是最近比较火的一个概念,和微服务、Kubernetes有密切关系。出于以后业务发展需要,可以学习下, 增加知识储备。见闻上Istio的主要目的在文章已说明,主要是基础服务的下沉,解决了语言兼容性问题, 还有一个就是灰度发布。

Q:链路追踪的采集方式是怎样的,比如Nodejs,C++等多语言如何支持的?
A:Envoy本身支持链路追踪,也就是将Envoy会在请求head中增加链路追踪相关的数据头,比如x-b3-traceid,x-b3-spanid等等。业务要做的就是将这些head沿着调用链路传递下去即可。所以多语言的话需要在自己的业务侧实现该逻辑。所以Istio的链路追踪对业务代码还是有很小的侵入性的(这个分享中有说明)。

Q:Istio与Spring Cloud两者的优缺点与今后的发展趋势会是怎么样?
A:见闻技术栈是Golang,所以没太认真对比过两者。从社区活跃度上将,Istio > Spring Cloud,稳定性方面,Spring Cloud是更有优势,更适合Java沉淀较深的企业。但个人感觉对于更多企业来讲,跨越了语言兼容性的Istio未来发展很值得期待。

Q:Docker镜像部署可以做到代码保护吗,比如像Nodejs这种非二进制执行程序的项目?
A:代码保护可以通过将镜像上传至指定云服务商上的镜像仓库中,见闻是将自己的业务镜像提交保存在了腾讯云。如果镜像泄露,那么非二进制执行程序的代码还是有泄露风险的。

Q:选型时为什么没考虑Linkerd?
A:选型之初也调研了Linkerd, 对比下来,Istio拥有更多活跃的开源贡献者,迭代速度快,以及Istio架构相较于见闻有较大可行性,所以选择了Istio作为实践方案。

Q:Istio在做运维部署时没有UI工具,你们如何实现运维人员更加便捷地使用?
A:见闻基于Kubernetes官方的Dashboard, 对内容进行了扩充,增加了对Gateway,VirtualService等Istio crd资源的支持, 同时增加了灰度部署等和见闻运维业务相关的功能,所以一定程度上解决了运维部署的问题。

Q:流量从Sidecar代理势必会对请求响应时间有影响,这个有没有更详细案例的说明性能上的损耗情况?
A:Sidecar的转发其实带来了性能一定的性能损耗。4核8G服务器,上面运行Proxy服务和API服务,API服务只返回ok字样。(此测试只测试极限QPS)单独测试API服务的QPS在59k+,平均延时在1.68ms,CPU占用4核。通过代理访问的QPS6.8k+,平均延时14.97ms,代理CPU占用2核,API服务CPU占用2核。 CPU消耗以及转发消耗降低了QPS,增加了延时,通过增加机器核数并增加服务部署数量缓解该问题,经过测试环境测试,延时可以接受。

Q:Sidecar在生产中资源占用为多少?是否会对集群资源占用很多?
A:以单个Pod为例,见闻业务单个Pod中Sidecar所占资源约占整个Pod所耗资源的1/10。

Q:Jeager你们是进行了代码埋点吗?更为底层代码级别的追踪,有用其他方案吗?
A:Envoy本身对tracing有良好的支持,所以业务端所做的改动只需将其所产生的追踪数据延续下去即可。上Istio之前,见闻在相关微服务中通过在基础库中增加链路追踪逻辑(Zipkin)实现了链路追踪,不过只做了Golang版,多语言兼容开发运维难度较大。

Q:相信咱们的mixer在生产环境中,也出现过瓶颈,咱们从哪几个大方向优化的?如何优化的?方面讲解一下吗?
A:mixer见闻在生产过程中所遇的坑在于Policy组件, 会疯狂的list pod,导致API server负载骤增,之后见闻基于自身业务关闭了Policy。

Q:Istio组件实现了高可用么?
A:Istio本身也是基于Kubernetes,所以可用性还是有较好保证的。

以上内容根据2019年4月23日晚微信群分享内容整理。分享人张安伟,华尔街见闻SRE团队运维工程师,负责公司日常运维开发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

基于Kubernetes的微服务可观测性和Istio服务网格(二)

dummy 发表了文章 • 0 个评论 • 524 次浏览 • 2019-04-22 17:01 • 来自相关话题

在本系列文章中,我们将继续探索可观测性工具集,这些工具集作为最新的Istio服务网格中的一部分,包含了Prometheus和Grafana用于度量指标收集、监控和警报,Jaeger用于分布式跟踪,以及Kiali为Istio提供基于服务网格的微服务可视化。同时结 ...查看全部
在本系列文章中,我们将继续探索可观测性工具集,这些工具集作为最新的Istio服务网格中的一部分,包含了PrometheusGrafana用于度量指标收集、监控和警报,Jaeger用于分布式跟踪,以及Kiali为Istio提供基于服务网格的微服务可视化。同时结合云平台原生的监控和日志记录服务,例如谷歌云平台上Google Kubernetes Engine(GKE)Stackdriver,我们为现代分布式应用程序提供了完整的可观测性解决方案。
# 参考平台
为了演示Istio的可观测性工具,在系列的第一部分中,我们部署一个参考平台,包含了8个基于Go的微服务,以服务A-H来标识,1个Angular 7基于TypeScript的前端,4个MongoDB数据库实例和一个RabbitMQ队列用于基于事件队列的通信。
1.png

该参考平台旨在生成基于HTTP的服务到服务,基于TCP的服务到数据库以及基于TCP的服务到队列再到服务(RabbitMQ)的IPC(进程间通信)。服务A调用服务B和C,服务B调用服务D和E,服务D生产消息到RabbitMQ队列供服务F来消费并写入到MongoDB,依此类推。目标是在将系统部署到Kubernetes时使用Istio的可观测性工具来观察这些分布式通信。
# 日志记录
我们在第一部分说到,日志、指标和跟踪通常被称为可观测性的三大核心支柱。当我们在GCP上使用GKE时,我们能利用谷歌云的Stackdriver Logging产品。据谷歌宣称, Stackdriver Logging允许你存储、搜索、分析、监控和根据来自GCP甚至是AWS的数据和事件来进行告警。虽然Stackdriver Logging不包含在Istio可观测性功能中,但是日志记录是整体可观测性策略的重要核心之一。
## 基于Go语言的微服务日志记录
有效的日志记录策略包含了记录的内容,何时记录以及如何记录。作为我们的日志记录策略的一部分,八个基于Go的微服务使用了Logrus,这是一个流行的结构化记录日志组件。这些微服务同时还实现了Banzai Cloud的logrus-runtime-formatter,关于这个日志插件有一篇优秀的文章:《Golang runtime Logrus Formatter》。这两个日志记录软件包能让我们更好地控制记录的内容,何时记录和如何记录关于我们的微服务的信息。使用这个软件包需要的配置也相当少。
func init() {
formatter := runtime.Formatter{ChildFormatter: &log.JSONFormatter{}}
formatter.Line = true
log.SetFormatter(&formatter)
log.SetOutput(os.Stdout)
level, err := log.ParseLevel(getEnv("LOG_LEVEL", "info"))
if err != nil {
log.Error(err)
}
log.SetLevel(level)
}

Logrus比Go内置的简单的日志包log提供多了几个优点。日志不仅只记录致命性错误,同时我们也不应该在生产环境中输出所有明细的日志。本文中涉及到的微服务利用了Logrus的七种日志级别:Trace、Debug、Info、Warning、Error、Fatal和Panic。我们还将日志级别作为变量,允许在部署时在Kubernetes Deployment资源中轻松更改它。

这些微服务同时还利用了Banzai Cloud的logrus-runtime-formatter。这个格式化工具能自动地给日志消息标记上运行时/堆栈信息,包括函数名和代码行号,这些信息在排除故障时非常有用。我们也使用了Logrus的JSON日志格式。注意下面的日志条目是如何将JSON有效负载包含在消息中的。
2.png

## 客户端层面的UI日志记录
同样地,我们使用NGX Logger增强了Angular UI的日志记录。NGX Logger是一个流行,简单的日志记录模块,目前用于Angular 6和7。它能将控制台输出打印得更好看,并允许将被POST到某个服务端URL的消息记录下来。在这次演示中,我们只将日志打印到控制台。与Logrus类似,NGX Logger也支持多种日志级别:Trace、Debug、Info、Warning、Error、Fatal和关闭。NGX Logger不仅可以输出消息,还允许我们将日志条目以合适的格式输出到Web浏览器的控制台。

日志输出级别取决于不同的环境,生产与非生产。下图我们可以看到在本地开发环境中的日志条目,包括了Debug、Info和Error级别。
3.png

在下图基于GKE的生产环境中我们能看到相同的页面。但是请注意,我们无需修改任何配置,Debug级别的日志条目将不会输出到控制台中。我们不希望暴露包含潜在敏感信息的日志给生产环境的终端用户。
4.png

通过将以下三元运算符添加到app.module.ts文件中来实现控制日志记录级别。
LoggerModule.forRoot({
level: !environment.production ? NgxLoggerLevel.DEBUG : NgxLoggerLevel.INFO,
serverLogLevel: NgxLoggerLevel.INFO
})

# 指标
关于指标,我们来看看PrometheusGrafana。这两个先进的工具已作为Istio部署的一部分被安装。
## Prometheus
Prometheus是一个完全开源和社区型驱动的系统监控和告警工具,大约在2012年SoundCloud创建了这个项目。有趣的是,Prometheus于2016年加入云原生计算基金会(CNCF)作为第二个托管项目,众所周知第一个是Kubernetes

根据Istio文档说明,Istio的Mixer中内置了一个Prometheus适配器,它可以暴露一个用于服务那些生成的度量值的端点。这里所说的Prometheus附加组件是一个预先配置了去收集Mixer端点上暴露的指标的Prometheus服务器。它提供了持久存储和查询Istio指标的机制。

GKE集群已跑起来,Istio也已安装,平台已部署,那怎么访问Prometheus?最简单的方法是使用`kubectl port-forward`来连接到Prometheus服务器。根据Google的说法,Kubernetes的端口转发从v1.10版本以后允许使用资源名称(例如服务名称)来选择匹配的Pod。我们将本地端口转发到Prometheus Pod上的端口。
5.png

你可以使用Google Cloud Shell进行连接,也可以将命令复制粘贴到本地shell以从本地端口进行连接。以下是本文中使用的端口转发命令。
# Grafana
kubectl port-forward -n istio-system \
$(kubectl get pod -n istio-system -l app=grafana \
-o jsonpath='{.items[0].metadata.name}') 3000:3000 &

# Prometheus
kubectl -n istio-system port-forward \
$(kubectl -n istio-system get pod -l app=prometheus \
-o jsonpath='{.items[0].metadata.name}') 9090:9090 &

# Jaeger
kubectl port-forward -n istio-system \
$(kubectl get pod -n istio-system -l app=jaeger \
-o jsonpath='{.items[0].metadata.name}') 16686:16686 &

# Kiali
kubectl -n istio-system port-forward \
$(kubectl -n istio-system get pod -l app=kiali \
-o jsonpath='{.items[0].metadata.name}') 20001:20001 &

Prometheus文档中写道,用户可使用名为PromQL(Prometheus查询语言)的函数查询语言来实时选择和汇总时间序列数据。查询表达式的结果可在Prometheus的Web UI中显示为表格数据并绘制为图形,也可以通过Prometheus的HTTP API由外部系统使用。Web UI界面包含了一个下拉菜单,其中包含所有可用指标作为构建查询的基础。下面显示的是本文中使用的一些PromQL示例。
up{namespace="dev",pod_name=~"service-.*"}
container_memory_max_usage_bytes{namespace="dev",container_name=~"service-.*"}
container_memory_max_usage_bytes{namespace="dev",container_name="service-f"}
container_network_transmit_packets_total{namespace="dev",pod_name=~"service-e-.*"}
istio_requests_total{destination_service_namespace="dev",connection_security_policy="mutual_tls",destination_app="service-a"}
istio_response_bytes_count{destination_service_namespace="dev",connection_security_policy="mutual_tls",source_app="service-a"}

在下图显示的Prometheus控制台中,我们看到了部署到GKE的八个基于Go的微服务的示例图。该图显示了五分钟内的容器内存使用情况。在一半的时间内,服务处于休息状态。另一半时间区域,服务使用了`hey`工具来模拟负载。查看负载下服务的内存简况可以帮助我们确定容器内存最小值和限制,这会影响Kubernetes在GKE集群上的工作负载调度。诸如此类的度量标准也可能会发现内存泄漏或路由问题,例如下面的服务,它似乎比同类服务消耗的内存多25-50%。
6.png

下面的另一个例子,这个图表表示系统处于负载状态下`dev`命名空间中对服务A的总的Istio请求。
7.png

比较上面的图表视图与控制台视图中显示的相同指标,多个指标显示了在检测的五分钟周期内,`dev`命名空间里的服务A的多个实例。各个度量标准元素中的值指出了收集到的最新度量标准。
8.png

Prometheus同时还收集有关Istio组件,Kubernetes组件和GKE集群的基本指标。下面我们可以查看GKE集群中每个n1-standard-2虚机节点的总内存。
9.png

## Grafana
Grafana自称是一个先进的时间序列分析开源软件。根据Grafana Labs的说法,Grafana允许你查询,可视化,提醒和了解熟悉你的指标,无论它们是存放在哪里。你可以轻松创建,浏览并共享具有丰富视觉效果的以数据驱动的仪表板。Grafana还能直观地让你为那些最重要的指标定义警报规则,它将不断评估规则并发送通知。

Istio文档中写到,Grafana附加组件其实是一个预先配置好的Grafana实例。Grafana的容器基础镜像已被修改为支持Prometheus数据源和适配到Istio仪表板。Istio的基本安装文件,特别是Mixer,包含了一个默认的全局的(用于每个服务)度量标准的配置。预配置的Istio仪表板可与默认的Istio指标配置和Prometheus后端结合使用。

我们在下图可以看到预先配置的Istio负载仪表板。较大的仪表板的特定部分已过滤用于显示在GKE集群中`dev`命名空间中的出站服务指标。
10.png

同样,在下面我们看到预先配置的Istio服务仪表板。较大的仪表板的特定部分已过滤用以显示GKE集群中Istio Ingress Gateway的客户端工作负载指标。
11.png

最后,我们看到预配置的Istio网格仪表板。此仪表板同样已过滤用以显示部署到GKE集群的组件的度量标准的表格视图。
12.png

有效的可观测性策略一定不仅仅包括可视化结果的能力,还必须包括异常检测并通知(警报)合适的资源或直接采取行动以解决事件的能力。像Prometheus一样,Grafana能够发出警报和通知。你可以直观地为关键指标定义警报规则。Grafana将根据规则不断评估指标,并在违反预定义阈值时发送通知。

Grafana支持多种流行的通知渠道,包括PagerDuty、HipChat、Email、Kafka和Slack。下面是一个新的通知频道,它向Slack支持频道发送警报通知。
13.png

Grafana能够发送详细的基于文本和视图的通知。
14.png

# 链路跟踪
根据Open Tracing网站介绍,分布式跟踪(也称为分布式请求跟踪)是一种用于分析和监控应用程序的方法,尤其是那些使用微服务架构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。

Istio中说到,尽管Istio中的代理程序能够自动发送span信息,但应用程序需要能传播适当的HTTP头信息,这样当代理发送span时,该span可以正确地关联到单个跟踪中。为此,应用程序需要收集传入请求中的以下头部并将其传播到任何传出的请求。

  • `x-request-id`
  • `x-b3-traceid`
  • `x-b3-spanid`
  • `x-b3-parentspanid`
  • `x-b3-sampled`
  • `x-b3-flags`
  • `x-ot-span-context`

`x-b3`头部一开始作为Zipkin项目的一部分。标题的B3部分以Zipkin的原始名称BigBrotherBird命名。在服务调用之间传递这些标头称为B3传播。根据Zipkin文档,这些属性在进程间传播,最终在下游(通常通过HTTP头)传播,以确保来自同一根的所有活动被收集在一起。

为了演示Jaeger的分布式跟踪,我修改了服务A,服务B和服务E,这三个服务会向其他上游服务发出HTTP请求。我添加了以下代码以便将标头从一个服务传播到下一个服务。Istio的边车代理,即Envoy生成第一个报头。至关重要的是,你只需传播下游请求中存在且包含值的标头,如下代码所示。传播任何一个空的请求头将破坏分布式跟踪。
headers := []string{
"x-request-id",
"x-b3-traceid",
"x-b3-spanid",
"x-b3-parentspanid",
"x-b3-sampled",
"x-b3-flags",
"x-ot-span-context",
}
for _, header := range headers {
if r.Header.Get(header) != "" {
req.Header.Add(header, r.Header.Get(header))
}
}

下图在高亮的Stackdriver日志条目的JSON有效负载中,我们看到从根span传播所需的头部,其中包含一个值,在上游请求中从服务A传递到服务C。
15.png

## Jaeger
Jaeger是受DapperOpenZipkin启发,是Uber科技开源的一套分布式跟踪系统。它用于监控和为基于微服务的分布式系统提供故障排除功能,包括了分布式上下文传播、分布式事务监控、根源分析、服务依赖性分析以及性能和延迟优化。Jaeger网站对Jaeger的架构和通用的跟踪相关术语进行了很好的概述。

下面我们看到Jaeger UI的Traces(跟踪)页面。其显示在大约四十分钟时间内搜索Istio Ingress Gateway服务的结果。我们在顶部看到了跟踪时间线,下面是跟踪结果列表。正如Jaeger网站上所讨论的,跟踪由span组成。span表示Jaeger中具有操作名称的逻辑工作单元。一次跟踪代表了通过系统的执行路径,可以被认为是有向无环图(DAG)或span。如果你曾使用过类似Apache Spark这样的系统,那么你可能已经很熟悉DAG是什么。
16.png

下面我们看到Jaeger UI的Trace Detail(跟踪详情)页面。该示例跟踪包含16个span,其中包含八个服务,七个基于Go的服务和一个Istio Ingress Gateway。跟踪和span都有各自的时间记录。跟踪中的根span是Istio Ingress Gateway。在终端用户的Web浏览器中加载的Angular UI通过Istio Ingress Gateway调用网格边缘服务A。从这一步开始,我们看到了服务到服务间IPC的预期流程。服务A调用服务B和C,服务B调用服务E,E又调用服务G和服务H。在该演示中,跟踪不贯穿RabbitMQ消息队列。这意味着你不能从RabbitMQ中看到包含从服务D到服务F的调用的跟踪。
17.png

在Jaeger UI跟踪详情页中,你还可以定位到包含其他元数据的单个范围。元数据包括被调用的URL、HTTP方法、响应状态和其他几个头部信息。
18.png

Jaeger的最新版本还包括Compare(对比)功能和两个Dependencies(依赖)视图,力导向图和DAG。我发现这两种视图与Kiali相比比较原始,与Service Graph更相似。在Kiali成为可能之前,这些作为依赖图来说非常有用。
19.png

# Kiali:微服务观测
Kiali网站上,我们大部分人对服务网格存在的问题得到了解答:我的Istio服务网格中有哪些微服务,它们是如何连接的?这里通过一个通用的Kubernetes Secret对象来控制对Kiali API和UI的访问。默认登录名是`admin`,密码是`1f2d1e2e67df`。
20.png

登录到Kiali后,我们能看到Overview菜单条目,它提供了Istio服务网格中所有命名空间的全局视图以及每个命名空间中的应用程序数。
21.png

Kiali UI中的图形视图是在Istio服务网格中运行的组件的直观展示。下面,对集群的`dev`命名空间进行过滤,我们可以观察到Kiali映射了8个应用程序(工作负载),10个服务和24个边界(图形术语)。具体来说,我们看到服务网格边缘的Istio Ingress代理、Angular UI、八个基于Go的微服务及其处理流量的Envoy代理边车(在此示例中服务F没有从其他服务直接获取流量),外部MongoDB Atlas集群和外部CloudAMQP集群。注意服务到服务的流量走向,通过Istio是如何从服务流向其边车代理再流向另一个服务的边车代理,最后到达其他服务。
22.png

下面,我们看到了服务网格的类似视图,但此时Istio Ingress网关和服务A之间存在故障,以红色显示。我们还可以观察HTTP流量的总体指标,例如每分钟共多少请求,错误和状态代码。
23.png

Kiali还可以显示图表中每个边界的平均请求时间和其他指标(即两个组件之间的通信)。
24.png

Kiali还可以显示部署的应用程序版本,如下所示,微服务中包含了版本1.3和1.4。
25.png

再说到外部的MongoDB Atlas集群,Kiali还允许我们查看在服务网格中的四个服务与外部集群的TCP流量。
26.png

“Applications(应用)”菜单列表列出了所有应用程序及其错误率,可以按命名空间和时间间隔进行筛选。在这里,我们看到Angular UI以16.67%的速率产生错误。
27.png

在Applications跟Workloads菜单条目中,我们可以深入查看组件以查看其详细信息,包括总体运行状况,Pod数量,服务和目标服务。下面我们可以查看在`dev`命名空间中服务B的详细信息。
28.png

Workloads详细视图还包括入站和出站指标。下面是`dev`命名空间中服务A的出站流量,持续时间和大小度量标准。
29.png

最后,Kiali还提供了一个Istio Config菜单。Istio Config菜单显示用户环境中存在的所有可用Istio配置对象的列表。
30.png

通常情况下,Kiali是我在解决平台问题时的第一个工具。一旦我确定了有问题的特定组件或通信路径,我就可以搜索Stackdriver日志和通过Grafana仪表板搜索Prometheus指标。
# 结论
在本系列文中,我们探索了当前最新版本的Istio服务网格中的一部分,可观测性工具集。它包括了Prometheus和Grafana,用于度量指标收集,监控和警报,Jaeger用于分布式跟踪,以及Kiali提供给Istio基于服务网格的微服务可视化。结合云平台本地监控和日志记录服务,例如谷歌云平台(GCP)上的Google Kubernetes Engine(GKE)Stackdriver,我们为现代分布式应用程序提供了完整的可观测性解决方案。

原文链接:Kubernetes-based Microservice Observability with Istio Service Mesh: Part 2(翻译:冯旭松)

基于Kubernetes的微服务可观测性与Istio服务网格(一)

dummy 发表了文章 • 0 个评论 • 783 次浏览 • 2019-04-19 15:40 • 来自相关话题

本系列文章将分为两部分,在此我们将探讨Istio服务网格中一部分,即可观测性工具集。这些工具包含了Jaeger、Kiali、Prometheus以及Grafana。为辅助我们此行探索,我们将在GCP上部署基于Go的微服务参考平台到GKE上去。 ...查看全部
本系列文章将分为两部分,在此我们将探讨Istio服务网格中一部分,即可观测性工具集。这些工具包含了Jaeger、Kiali、Prometheus以及Grafana。为辅助我们此行探索,我们将在GCP上部署基于Go的微服务参考平台到GKE上去。
1.png

# 什么是可观测性
与区块链、无服务器、AI和机器学习、聊天机器人、网络安全和服务网格类似,可观测性现在是IT行业中的一大热门话题。根据维基百科记录,可观测性指的是如何从外部输出来推断衡量系统内部状态。日志、指标和跟踪通常被成为可观测性的三大核心支柱。这些是我们可观察到的系统的外部输出。

由Cindy Sridharan撰写,O’Reilly出版的分布式系统可观测性一书在第四章节中详细地介绍了“可观测性的三大支柱”。在继续下文之前,我强烈建议你阅读下这篇在线摘录。关于可观测性资讯的另一大来源是honeycomb.io,一个生产系统可观测性工具的开发商,由知名的行业思想领袖Charity Majors领导。这个站点上面发布了很多关于可观测性的文章、博文、白皮书和博客。

随着现代分布式系统变得越发复杂,想具备观察这些系统的能力需要同样在设计之初就考虑到适配如此复杂环境的现代化的工具。传统的日志记录和监控系统通常与当今的混合和多云、基于多种语言、事件驱动、基于容器和无服务器、可无限扩展的、临时计算的平台相竞争。

Istio服务网格这类工具试图通过提供与几种同类最佳的开源遥测工具的原生集成方案来解决可观测性带来的挑战。Istio的集成包括Jaeger用于分布式跟踪,Kiali用于分布式系统可视化,PrometheusGrafana用于度量指标收集、监控和警报。同时结合云平台原生的监控和日志服务,例如谷歌云平台上Google Kubernetes Engine(GKE)Stackdriver,我们为现代化的分布式应用打造完整的可观测平台。
# 一个供参考的微服务平台
为了演示与最新版本的Istio服务网格集成的可观测性工具,我们将部署一个具备参考意义的,使用Go编写的微服务平台到GKE上面去。我开发了相关参考服务平台来演示涉及到的概念,例如API管理、服务网格、可观测性、DevOps和混沌工程等。该平台由14个组件组成,包含了8个基于Go的微服务,以服务A-H来标记,一个Augular 7,基于TypeScript的前端,4个MongoDB数据库实例,一个RabbitMQ队列用于基于事件队列的通信。该平台以及所有代码都已开源。

该参考平台旨在生成基于HTTP的服务到服务,基于TCP的服务到数据库以及基于TCP的服务到队列再到服务(RabbitMQ)的IPC(进程间通信)。服务A调用服务B和C,服务B调用服务D和E,服务D生产消息到RabbitMQ队列供服务F来消费并写入到MongoDB,依此类推。当这个系统部署到运行Istio服务网格的Kubernetes集群中时,可以使用Istio的可观测性工具来观察这些分布式通信。
## 服务响应
在该平台上,每个上游服务通过返回一个小的JSON信息负载(在源码中称为问候语)来响应下游服务的请求。
2.png

这些请求响应在调用链中聚合,进而产生给边缘服务的一系列服务响应,并返回给UI界面,最终展示在用户的浏览器中。响应聚合功能只是简单验证服务到服务间通信,Istio组件和遥测工具都能否正常工作。
3.png

所有的Go微服务都包含一个`/ping`和`/health`端点。`/health`端点用于配置Kubernetes的存活以及就绪探针。此外,边缘服务A使用响应头`access-control-allow-origin: *`用来配置Cross-Origin Resource Sharing(CORS)。CORS允许用于浏览器来调用位于与UI不同子域的`/ping`端点。相关服务A的源码可以在此查看。

在本次演示中,MongoDB数据库将被托管到GCP的外部,即MongoDB Atlas,它是一个基于云的MongoDB即服务平台。同样的,RabbitMQ队列服务将被托管到CloudAMQP,这是一个基于云的RabbitMQ即服务平台。我曾在之前的几篇文章中使用过这两种Saas供应商。使用外部服务将帮助我们了解Istio和它的可观测性工具是如何为位于Kubernetes集群中和外部系统的通信提供遥测的。

服务F消费来自RabbitMQ队列的消息,服务D将消息写入队列并写入到MongoDB中,这些服务都能通过对应链接打开直接查看源码。
# 源码
所有本文涉及到的源码都可以在GitHub的两个项目中找到。基于Go的微服务的源码,所有的Kubernetes资源和部署脚本都位于k8s-istio-observe-backend这个项目仓库中。Angular UI前端项目源码位于k8s-istio-observe-frontend中。此次演示中你将不需要下载前端项目。
git clone --branch master --single-branch --depth 1 --no-tags \
https://github.com/garystafford/k8s-istio-observe-backend.git

Kubernetes资源中引用到的相关Go服务和UI界面的容器镜像,都可以在Docker Hub上找到。Go服务镜像是使用官方的Golang Alpine来作为基础镜像,包含了Go 1.12.0版本。使用Alpine镜像来编译源码将能保证容器镜像尽可能地小并且包含更小的可攻击面。
# 系统要求
文章接下来的部分,你需要将最新版本的`gcloud`的客户端工具(最小版本要求为239.0.0)、Helm和刚刚发布的Istio 1.1.0版本安装并配置在你的本地或者是构建机器上。
4.png

# 配置和安装
为了将该微服务平台部署到GKE,我们将按以下步骤进行:

  1. 创建MongoDB Atlas数据库集群
  2. 创建CloudAMQP RabbitMQ集群
  3. 根据自己的环境调整Kubernetes的资源文件和脚本
  4. 在GCP上创建GKE集群
  5. 使用Helm在GKE集群中部署Istio 1.1.0版本
  6. 为平台中需要暴露访问的资源创建DNS记录
  7. 部署所有Go微服务,Angular UI和与GKE相关联的资源
  8. 测试或为你的平台排障
  9. 在第二篇中查看观察的结果

# MongoDB Atlas集群
MongoDB Atlas是一个完全托管的MongoDB即服务,可在AWS、Azure和GCP上使用。Atlas是一款成熟的SaaS产品,提供高可用性,有保证的正常运行时间SLA,弹性可扩展性,跨区域复制,企业级安全性,LDAP集成,BI连接器等等。

MongoDB Atlas目前提供有四种定价方案,包含免费版、基础版、高级版和企业版。这些方案范围从最小的共享内存和512MB存储的M0规模的MongoDB集群,到最高具有488GB内存和3TB存储的大型M400 MongoDB集群。

在本文中,我在GCP的us-central1地区创建了一个M2大小的MongoDB集群,并为该演示创建了一个数据库账户,该帐户将用于连接GKE上运行的八个基于Go的微服务的其中四个。
5.png

最初我使用了一个M0大小的集群,但发现计算资源不足以支撑来自这些Go语言的微服务。在此我建议至少使用M2大小乃至更大的集群。
# CloudAMQP RabbitMQ集群
CloudAMQP在所有主流云供应商和应用程序平台上提供完全托管的RabbitMQ集群。RabbitMQ将支持一部分基于Go的微服务的解耦,最终一致的基于消息的架构。在本文中,我同样在GCP的us-central1区域创建了一个RabbitMQ集群,与我们的GKE集群和MongoDB Atlas集群相同,我选择了一个最低配置的RabbitMQ免费版本。CloudAMQP还提供强大的多节点RabbitMQ集群以供生产级别环境使用。
# 修改配置
在GitHub项目中的Kubernetes资源文件和Bash部署脚本中你需要对应调整部分配置设置。
## 配置MongoDB Atlas的Istio ServiceEntry
external-mesh-mongodb-atlas.yaml文件中添加MongoDB Atlas主机地址。此文件允许从GKE上的四个微服务到外部MongoDB Atlas集群的出口流量。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: mongodb-atlas-external-mesh
spec:
hosts:
- {{ your_host_goes_here }}
ports:
- name: mongo
number: 27017
protocol: MONGO
location: MESH_EXTERNAL
resolution: NONE

## 配置CloudAMQP RabbitMQ的Istio ServiceEntry
external-mesh-cloudamqp.yaml文件中添加CloudAMQP主机地址,此文件允许从两个微服务到CloudAMQP群集的出口流量。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: cloudamqp-external-mesh
spec:
hosts:
- {{ your_host_goes_here }}
ports:
- name: rabbitmq
number: 5672
protocol: TCP
location: MESH_EXTERNAL
resolution: NONE

## Istio Gateway和VirtualService
通过Istio你可以有许多策略用于配置路由流量。此文中我使用了example-api.com这个域名,还有4组子域名。一组子域用于Angular UI,分别是dev命名空间(ui.dev.example-api.com)和test命名空间(ui.test.example-api.com)。另一组子域用于边缘API微服务,即被UI界面调用的服务A(api.dev.example-api.comapi.test.example-api.com)。流量将根据URL路由到特定的Kubernetes服务去。

Istio中所定义的Gateway对象描述了一个在网格边缘操作的负载均衡器,它负责接收传入或传出的HTTP/TCP连接。修改Istio ingress Gateway,在该hosts部分中插入你自己的域名或子域,这些是端口80上允许进入网格的主机。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: demo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- ui.dev.example-api.com
- ui.test.example-api.com
- api.dev.example-api.com
- api.test.example-api.com

Istio中的VirtualService定义了一组主机域名被寻址时应用的流量路由规则。一个VirtualServiceGateway绑定来控制到达特定主机和端口的流量的转发。修改项目中的4个VirtualServices,将你的域名或子域添加进去。以下是在istio-gateway.yaml中一个VirtualService的例子。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: angular-ui-dev
spec:
hosts:
- ui.dev.example-api.com
gateways:
- demo-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
host: angular-ui.dev.svc.cluster.local

## Kubernetes Secret
该项目中包含了一个Kubernetes Secret对象,go-srv-demo.yaml文件中指定了两个键值,一个用于MongoDB Atlas的连接,一个用于CloudAMQP,Kubernetes中的Secret的值需要经过`base64`加密。
apiVersion: v1
kind: Secret
metadata:
name: go-srv-config
type: Opaque
data:
mongodb.conn: {{ your_base64_encoded_secret }}
rabbitmq.conn: {{ your_base64_encoded_secret }}

在Linux和Mac上,你能直接使用`base64`程序来对此连接字符串进行编码。
> echo -n "mongodb+srv://username:password@atlas-cluster.gcp.mongodb.net/test?retryWrites=true" | base64
bW9uZ29kYitzcnY6Ly91c2VybmFtZTpwYXNzd29yZEBhdGxhcy1jbHVzdGVyLmdjcC5tb25nb2RiLm5ldC90ZXN0P3JldHJ5V3JpdGVzPXRydWU=

[quote] echo -n "amqp://username:password@rmq.cloudamqp.com/cluster" | base64
YW1xcDovL3VzZXJuYW1lOnBhc3N3b3JkQHJtcS5jbG91ZGFtcXAuY29tL2NsdXN0ZXI=

## Bash脚本变量
脚本part3_create_gke_cluster.sh包含了一系列环境变量。你至少需要更改所有脚本中的PROJECT变量为你的GCP项目名。
# 对应修改这些常量
readonly PROJECT='{{ your_gcp_project_goes_here }}'
readonly CLUSTER='go-srv-demo-cluster'
readonly REGION='us-central1'
readonly MASTER_AUTH_NETS='72.231.208.0/24'
readonly GKE_VERSION='1.12.5-gke.5'
readonly MACHINE_TYPE='n1-standard-2'

脚本part4_install_istio.sh中包含了ISTIO_HOME这个变量,该值应与你本地的Istio 1.1.0的路径一致。下面是在我本地的Mac上的值:
readonly ISTIO_HOME='/Applications/istio-1.1.0'

# 部署GKE集群
接下来使用脚本part3_create_gke_cluster.sh来部署GKE集群。这一步将创建一个区域,多可用区的3节点的GKE集群。该集群将会被部署到与MongoDB Atlas和CloudAMQP集群相同的区域,即us-central1(Iowa)。规划云资源所处的位置,对于Saas供应商和主流云供应商而言,能最大限度地减少网络I/O密集型应用程序的延迟。
6.png

# 使用Helm部署Istio
等待GKE集群和相关的基础设施就绪后,我们将部署Istio。此文中,我推荐选择使用Helm部署Istio的部署方式。要使用该种方式,请使用脚本part4_install_istio.sh
7.png

该脚本使用本地Istio 1.1.0中`install/kubernetes/helm/istio`目录中的Helm Chart安装Istio。该安装脚本使用`--set`命令行标志覆写了Istio Helm Chart中的多个默认值。相关可用的配置项在GitHub project中有详细说明。这些选项启用了Istio的可观测性功能,包含Kiali、Grafana、Prometheus和Jaeger,这些我们将在本系列的第二篇中探索。
helm install ${ISTIO_HOME}/install/kubernetes/helm/istio-init \
--name istio-init \
--namespace istio-system[/quote]

helm install ${ISTIO_HOME}/install/kubernetes/helm/istio \
--name istio \
--namespace istio-system \
--set prometheus.enabled=true \
--set grafana.enabled=true \
--set kiali.enabled=true \
--set tracing.enabled=true

kubectl apply --namespace istio-system \
-f ./resources/secrets/kiali.yaml

如下图,我们可以看到与Istio相关联的负载已经运行在集群中,包含了可观测性工具集。
8.png

同样,我们能看到集群中相应的Istio相关的Service资源。
9.png

# 修改DNS记录
我们将使用DNS,而非使用IP地址来路由GKE集群及其应用程序的流量。如上所述,我使用了example-api.com这个域名和四个子域。一个子域用于devtest命名空间的Angular UI服务,其他被用于API调用的边缘微服务A。流量基于URL路由到特定的Kubernetes Service资源。

部署GKE集群和Istio会触发创建一个Google Load Balancer,四个IP地址和所有必要的防火墙规则。与转发规则相关联的四个IP地址之一(如下所示)将与负载均衡器的前端相关联。
10.png

如下所示,我们能看到一个新的负载均衡器,包含了前端IP地址和三个GKE集群工作节点的后端VM池。每个节点都被分配了一个IP地址。
11.png

接着我使用了Google Cloud DNS创建了四个子域并将所有子域与负载均衡器前端的IP绑定。到这些地址的入口流量将通过Istio ingress Gateway和四个Istio VirtualService然后路由到适当的Kubernetes Service资源去。使用你选定的DNS管理工具来创建四个A类型的DNS记录。
12.png

# 部署整个参考平台
接下来,将八个基于Go的微服务,Angular UI以及相关的Kubernetes和Istio资源部署到GKE集群。请使用脚本part5a_deploy_resources.sh来部署平台。如果任何操作失败并且在不破坏GKE集群或Istio的情况下,你想要删除现有资源并重新部署,则可以使用part5b_delete_resources.sh删除脚本。
14.png

部署脚本将所有资源部署到两个Kubernetes命名空间,分别是devtest。这将使我们能够在使用可观测性工具时区分不同的命名空间。

下图展示刚刚部署的与Istio相关的资源,它们包括Istio Gateway,四个Istio VirtualService和两个Istio ServiceEntry资源。
15.png

接着是在集群上运行此平台的工作负载(Kubernetes Deployment资源)。在这我们可以看到每个工作负载有两个Pod,共有18个Pod,在dev命名空间中运行。每个Pod都包含已部署的微服务或UI组件,以及Istio的Envoy Proxy的副本。
16.png

下图我们看到dev命名空间中创建了对应的Kubernetes Service资源。
17.png

下图test命令空间中的资源与dev命名空间的类似。
18.png

# 测试该平台
我们想确保平台中的八个基于Go的微服务和Angular UI都能正常工作,相互通信,并与外部的MongoDB Atlas和CloudAMQP RabbitMQ集群进行通信。最简单的方式就是直接在浏览器查看Augular UI。
19.png

UI界面要求你输入服务A的主机名,即API的边缘服务。由于你无法使用我的子域,并且JavaScript代码是在你的Web浏览器本地运行,因此该选项允许你提供自己的主机域。这与你在VirtualService中为UI配置的域名相同。此域名将API调用路由到dev命名空间中运行的Service A服务的FQDN service-a.dev.svc.cluster.local,或test命名空间service-a.test.svc.cluster.local
20.png

你还可以使用性能测试工具对平台进行负载测试。很多问题在平台出现负载前都很难发现。最近我开始使用`hey`,一个现代化的负载生成工具,作为Apache Bench的替代品,它不像ab,hey支持HTTP/2端点,这是测试运行在包含了Istio组件的GKE集群上的平台工作所必需的。下面我直接在Google Cloud Shell使用`hey`工具,将模拟25个并发用户,为服务A生成总共1000个基于HTTP/2的GET请求。
21.png

# 故障排除
如果由于某些原因导致UI无法显示或者是从UI发起的调用请求失败,并且假设所有Kubernetes和Istio资源都运行在GKE集群上,则最常见的解释通常就是以下的资源存在错误配置:

  1. 四个DNS记录中存在错误,它们不是解析到负载均衡器的前端IP地址上
  2. 没有为四个Istio的VirtualService资源配置正确的子域名
  3. 基于Go的微服务无法访问外部MongoDB Atlas和CloudAMQP RabbiqMQ集群。可能是Kuberetes Secret资源结构不对或者是两个ServiceEntry中包含了那些到外部集群的错误的主机信息

我建议通过使用cURL或Postman工具直接调用服务A(API的边缘服务)来开始排障。如果你能看到类似下图的JSON格式的响应,那则表明问题在于UI而非API。
22.png

接下来,确认为服务D、F、G和H创建了四个MongoDB数据库。另外确保新文档被正确写入数据库。
23.png

另外使用CloudAMQP RabbitMQ管理控制台确认已创建新的RabbitMQ队列。服务D产生信息,服务F从队列中取出并消费。
24.png

最后查看Stackdriver日志以查看是否存在任何明显错误。
25.png

# 未完待续
在此系列的第二部分中,我们将详细探索每个可观测性工具,并了解它们如何帮助我们管理GKE集群以及运行在上面的相关平台。
26.png

由于集群只需几分钟即可完成创建和部署资源,如果需要清除集群请运行part6_tear_down.sh脚本。
27.png

以上所有仅代表我个人观点,与现任、前任雇主和客户无关。

原文链接:Kubernetes-based Microservice Observability with Istio Service Mesh: Part 1(翻译:冯旭松)

华为云和开源Istio运维管理对比样例应用部署

CCE_SWR 发表了文章 • 0 个评论 • 446 次浏览 • 2019-04-15 17:34 • 来自相关话题

前言 在公有云方面,华为云已经率先将 Istio 作为产品投入到公有云中进行商业应用中,保持和开源istio高度兼容,做了商业化的运维管理界面,同时进行了性能优化。这里我们做一次验证测试。 ...查看全部
前言

在公有云方面,华为云已经率先将 Istio 作为产品投入到公有云中进行商业应用中,保持和开源istio高度兼容,做了商业化的运维管理界面,同时进行了性能优化。这里我们做一次验证测试。




Bookinfo 应用

这里我们部署一个demo,由四个单独的微服务构成(注意这里的四个微服务是由不同的语言编写的),用来演示多种 Istio 特性。这个应用模仿在线书店的一个分类,显示一本书的信息。页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。



Bookinfo 应用分为四个单独的微服务:



productpage:productpage微服务会调用details和reviews两个微服务,用来生成页面。

details:这个微服务包含了书籍的信息。

reviews:这个微服务包含了书籍相关的评论。它还会调用 ratings 微服务。

ratings:ratings 微服务中包含了由书籍评价组成的评级信息。



这里主要使用reviews来演示 Istio 特性,reviews微服务有 3 个版本:



v1 版本不会调用ratings服务。

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

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



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




0415_1.jpg



Istio 注入之前的 Bookinfo 应用



Bookinfo 是一个异构应用,几个微服务是由不同的语言编写的。这些服务对 Istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。





部署应用

这里 Istio 的安装部署就不在赘述了。



值得注意的是:如果使用的是开源K8s服务安装的 Istio ,要配置负载均衡。



在 Istio 中运行这一应用,无需对应用自身做出任何改变。我们只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个服务之中。这个过程所需的具体命令和配置方法由运行时环境决定,而部署结果较为一致,如下图所示:




0415_2.jpg



Bookinfo 应用



所有的微服务都和 Envoysidecar 集成在一起,被集成服务所有的出入流量都被 sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用 Istio 控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。

下载安装



到 GitHub 中 istio 的 release 中下载相应版本的 istio包,下载后将 bin目录配置到环境变量 PATH中 export PATH="/istio/bin:$PATH",这里我们使用的是 istio 1.0.5版本



Bookinfo 这个应用就在samples/目录下





在华为云(CCE)上运行


华为云率先将 Istio 作为产品投入到公有云中进行商业应用,开通方式十分简单,只要在华为云CCE上创建集群,然后申请 Istio 公测即可。



为了方便测试Bookinfo 应用在华为云上提供了一键体验应用,点击即可省去刚刚那一系列的kubectl操作




0415_3.jpg



一键创建体验应用


0415_4.jpg



点击灰度发布即可


0415_5.jpg



创建金丝雀发布


0415_6.jpg



选择灰度发布的组件


0415_7.jpg



填写版本号


0415_8.jpg



选择镜像版本


0415_9.jpg



版本创建完成后配置灰度策略


0415_10.jpg



选择相应策略,策略下发即可



总的来说,华为云的Istio 确实已经是商业化应用,这里只是展示了部分灰度发布的功能。其他比如流量治理,流量监控等功能还没展示,这些功能做的十分细致,值得尝试。


参考

基于ISTIO服务网格的灰度发布

https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_0012.html

如何为服务网格选择入口网关?

阿娇 发表了文章 • 0 个评论 • 205 次浏览 • 2019-05-21 23:02 • 来自相关话题

在启用了Istio服务网格的Kubernetes集群中,缺省情况下只能在集群内部访问网格中的服务,要如何才能从外部网络访问这些服务呢? Kubernetes和Istio提供了NodePort,LoadBalancer,Kubernetes Ingress,Is ...查看全部
在启用了Istio服务网格的Kubernetes集群中,缺省情况下只能在集群内部访问网格中的服务,要如何才能从外部网络访问这些服务呢? Kubernetes和Istio提供了NodePort,LoadBalancer,Kubernetes Ingress,Istio Gateway等多种外部流量入口的方式,面对这么多种方式,我们在产品部署中应该如何选择?

本文将对Kubernetes和Istio对外提供服务的各种方式进行详细介绍和对比分析,并根据分析结果提出一个可用于产品部署的解决方案。如果你想和更多Istio技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

说明:阅读本文要求读者了解Kubernetes和Istio的基本概念,包括Pod、Service、NodePort、LoadBalancer、Ingress、Gateway、VirtualService等。如对这些概念不熟悉,可以在阅读过程中参考文后的相关链接。
#内部服务间的通信
首先,我们来回顾一下Kubernetes集群内部各个服务之间相互访问的方法。
##Cluster IP
Kubernetes以Pod作为应用部署的最小单位。kubernetes会根据Pod的声明对其进行调度,包括创建、销毁、迁移、水平伸缩等,因此Pod 的IP地址不是固定的,不方便直接采用Pod IP对服务进行访问。

为解决该问题,Kubernetes提供了Service资源,Service对提供同一个服务的多个Pod进行聚合。一个Service提供一个虚拟的Cluster IP,后端对应一个或者多个提供服务的Pod。在集群中访问该Service时,采用Cluster IP即可,Kube-proxy负责将发送到Cluster IP的请求转发到后端的Pod上。

Kube-proxy是一个运行在每个节点上的Go应用程序,支持三种工作模式:

1、Userspace

该模式下kube-proxy会为每一个Service创建一个监听端口。发向Cluster IP的请求被Iptables规则重定向到Kube-proxy监听的端口上,Kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。

该模式下,Kube-proxy充当了一个四层Load balancer的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加两次内核和用户空间之间的数据拷贝,效率较另外两种模式低一些;好处是当后端的Pod不可用时,kube-proxy可以重试其他Pod。
1.png

Kube-proxy userspace模式(来自Kubernetes官网文档

2、iptables

为了避免增加内核和用户空间的数据拷贝操作,提高转发效率,Kube-proxy提供了iptables模式。在该模式下,Kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。

该模式下Kube-proxy不承担四层代理的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
2.png

Kube-proxy iptables模式(来自Kubernetes官网文档

3、IPVS
该模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs rules。IPVS也是在kernel模式下通过netfilter实现的,但采用了hash table来存储规则,因此在规则较多的情况下,IPVS相对iptables转发效率更高。除此以外,IPVS支持更多的LB算法。如果要设置kube-proxy为IPVS模式,必须在操作系统中安装IPVS内核模块。
3.png

Kube-proxy ipvs模式(来自Kubernetes官网文档
##Istio Sidecar Proxy
Cluster IP解决了服务之间相互访问的问题,但从上面Kube-proxy的三种模式可以看到,Cluster IP的方式只提供了服务发现和基本的LB功能。如果要为服务间的通信应用灵活的路由规则以及提供Metrics collection,distributed tracing等服务管控功能,就必须得依靠Istio提供的服务网格能力了。

在Kubernetes中部署Istio后,Istio通过iptables和Sidecar Proxy接管服务之间的通信,服务间的相互通信不再通过Kube-proxy,而是通过Istio的Sidecar Proxy进行。请求流程是这样的:Client发起的请求被iptables重定向到Sidecar Proxy,Sidecar Proxy根据从控制面获取的服务发现信息和路由规则,选择一个后端的Server Pod创建链接,代理并转发Client的请求。

Istio Sidecar Proxy和Kube-proxy的userspace模式的工作机制类似,都是通过在用户空间的一个代理来实现客户端请求的转发和后端多个Pod之间的负载均衡。两者的不同点是:Kube-Proxy工作在四层,而Sidecar Proxy则是一个七层代理,可以针对HTTP,GRPS等应用层的语义进行处理和转发,因此功能更为强大,可以配合控制面实现更为灵活的路由规则和服务管控功能。
4.jpg

Istio Sidecar Proxy
#如何从外部网络访问
Kubernetes的Pod IP和Cluster IP都只能在集群内部访问,而我们通常需要从外部网络上访问集群中的某些服务,Kubernetes提供了下述几种方式来为集群提供外部流量入口。
##NodePort
NodePort在集群中的主机节点上为Service提供一个代理端口,以允许从主机网络上对Service进行访问。Kubernetes官网文档只介绍了NodePort的功能,并未对其实现原理进行解释。下面我们通过实验来分析NodePort的实现机制。

www.katacoda.com这个网站提供了一个交互式的Kubernetes playground,注册即可免费实验Kubernetes的相关功能,下面我们就使用Katacoda来分析Nodeport的实现原理。

在浏览器中输入这个网址:https://www.katacoda.com/courses/kubernetes/networking-introduction, 打开后会提供了一个实验用的Kubernetes集群,并可以通过网元模拟Terminal连接到集群的Master节点。

执行下面的命令创建一个NodePort类型的Service。
kubectl apply -f nodeport.yaml

查看创建的Service,可以看到Kubernetes创建了一个名为webapp-nodeport-svc的Service,并为该Service在主机节点上创建了30080这个NodePort。
master $ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 36m
webapp1-nodeport-svc NodePort 10.103.188.73 80:30080/TCP 3m

webapp-nodeport-svc后端对应两个Pod,其Pod的IP分别为10.32.0.3和10.32.0.5。
master $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IPNODE NOMINATED NODE
webapp1-nodeport-deployment-785989576b-cjc5b 1/1 Running 0 2m 10.32.0.3
webapp1-nodeport-deployment-785989576b-tpfqr 1/1 Running 0 2m 10.32.0.5

通过netstat命令可以看到Kube-proxy在主机网络上创建了30080监听端口,用于接收从主机网络进入的外部流量。
master $ netstat -lnp|grep 30080
tcp6 0 0 :::30080 :::* LISTEN 7427/kube-proxy

下面是Kube-proxy创建的相关iptables规则以及对应的说明。可以看到Kube-proxy为NodePort创建了相应的IPtable规则,将发向30080这个主机端口上的流量重定向到了后端的两个Pod IP上。
iptables-save > iptables-dump
# Generated by iptables-save v1.6.0 on Thu Mar 28 07:33:57 2019
*nat
# Nodeport规则链
:KUBE-NODEPORTS - [0:0]
# Service规则链
:KUBE-SERVICES - [0:0]
# Nodeport和Service共用的规则链
:KUBE-SVC-J2DWGRZTH4C2LPA4 - [0:0]
:KUBE-SEP-4CGFRVESQ3AECDE7 - [0:0]
:KUBE-SEP-YLXG4RMKAICGY2B3 - [0:0]

# 将host上30080端口的外部tcp流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp --dport 30080 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到Cluster IP 10.103.188.73的内部流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
KUBE-SERVICES -d 10.103.188.73/32 -p tcp -m comment --comment "default/webapp1-nodeport-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到webapp1-nodeport-svc的流量转交到第一个Pod(10.32.0.3)相关的规则链上,比例为50%
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YLXG4RMKAICGY2B3
#将发送到webapp1-nodeport-svc的流量转交到第二个Pod(10.32.0.5)相关的规则链上
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -j KUBE-SEP-4CGFRVESQ3AECDE7

#将请求重定向到Pod 10.32.0.3
-A KUBE-SEP-YLXG4RMKAICGY2B3 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.3:80
#将请求重定向到Pod 10.32.0.5
-A KUBE-SEP-4CGFRVESQ3AECDE7 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.5:80

从上面的实验可以看到,通过将一个Service定义为NodePort类型,Kubernetes会通过集群中Node上的Kube-proxy为该Service在主机网络上创建一个监听端口。Kube-proxy并不会直接接收该主机端口进入的流量,而是会创建相应的Iptables规则,并通过Iptables将从该端口收到的流量直接转发到后端的Pod中。

NodePort的流量转发机制和Cluster IP的iptables模式类似,唯一不同之处是在主机网络上开了一个“NodePort”来接受外部流量。从上面的规则也可以看出,在创建Nodeport时,Kube-proxy也会同时为Service创建Cluster IP相关的iptables规则。

备注:除采用iptables进行流量转发,NodePort应该也可以提供userspace模式以及ipvs模式,这里未就这两种模式进行实验验证。



从分析得知,在NodePort模式下,集群内外部的通讯如下图所示:
5.jpg

NodePort
##LoadBalancer
NodePort提供了一种从外部网络访问Kubernetes集群内部Service的方法,但该方法存在下面一些限制,导致这种方式主要适用于程序开发,不适合用于产品部署。

* Kubernetes cluster host的IP必须是一个well-known IP,即客户端必须知道该IP。但Cluster中的host是被作为资源池看待的,可以增加删除,每个host的IP一般也是动态分配的,因此并不能认为host IP对客户端而言是well-known IP。
* 客户端访问某一个固定的host IP的方式存在单点故障。假如一台host宕机了,Kubernetes cluster会把应用reload到另一节点上,但客户端就无法通过该host的NodePort访问应用了。
* 通过一个主机节点作为网络入口,在网络流量较大时存在性能瓶颈。

为了解决这些问题,Kubernetes支持将Service定义为LoadBalancer类型。 Cloud Provider Controller监听Service的变化消息,当LoadBalancer类型的Service创建后,Cloud Provider Controller会将配置下发到Cloud Provider网络中的一个四层负载均衡器,该四层负载均衡器负责将外部网络流量分发到后面的多个节点的NodePort端口上。

下图展示了Kubernetes如何通过LoadBalancer方式对外提供流量入口,图中LoadBalancer后面接入了两个主机节点上的NodePort,后端部署了三个Pod提供服务。根据集群的规模,可以在LoadBalancer后面可以接入更多的主机节点,以进行负荷分担。
6.jpg

NodeBalancer

备注:LoadBalancer类型需要云服务提供商的支持,Service中的定义只是在Kubernetes配置文件中提出了一个要求,即为该Service创建Load Balancer,至于如何创建则是由Google Cloud或Amazon Cloud等云服务商提供的,创建的Load Balancer的过程不在Kubernetes Cluster的管理范围中。



目前AWS,Azure,CloudStack,GCE和OpenStack等主流的公有云和私有云提供商都可以为Kubernetes提供Load Balancer。一般来说,公有云提供商还会为Load Balancer提供一个External IP,以提供Internet接入。如果你的产品没有使用云提供商,而是自建Kubernetes Cluster,则需要自己提供LoadBalancer。
##Ingress
LoadBalancer类型的Service提供的是四层负载均衡器,当只需要向外暴露一个服务的时候,采用这种方式是没有问题的。但当一个应用需要对外提供多个服务时,采用该方式则要求为每一个四层服务(IP+Port)都创建一个外部load balancer。

一般来说,同一个应用的多个服务/资源会放在同一个域名下,在这种情况下,创建多个Load balancer是完全没有必要的,反而带来了额外的开销和管理成本。另外直接将服务暴露给外部用户也会导致了前端和后端的耦合,影响了后端架构的灵活性,如果以后由于业务需求对服务进行调整会直接影响到客户端。

在这种情况下,我们可以通过使用Kubernetes Ingress来统一网络入口。Kubernetes Ingress声明了一个应用层(OSI七层)的负载均衡器,可以根据HTTP请求的内容将来自同一个TCP端口的请求分发到不同的Kubernetes Service,其功能包括:

* 按HTTP请求的URL进行路由,同一个TCP端口进来的流量可以根据URL路由到Cluster中的不同服务,如下图所示:
7.png

Simple fanout

* 按HTTP请求的Host进行路由,同一个IP进来的流量可以根据HTTP请求的Host路由到Cluster中的不同服务,如下图所示:
8.png

Name based virtual hosting

Ingress规则定义了对七层网关的要求,包括URL分发规则,基于不同域名的虚拟主机,SSL证书等。Kubernetes使用Ingress Controller 来监控Ingress规则,并通过一个七层网关来实现这些要求,一般可以使用Nginx,HAProxy,Envoy等。

虽然Ingress Controller通过七层网关为后端的多个Service提供了统一的入口,但由于其部署在集群中,因此并不能直接对外提供服务。实际上Ingress需要配合NodePort和LoadBalancer才能提供对外的流量入口,如下图所示:
9.png

采用Ingress,NodePortal和LoadBalancer提供外部流量入口的拓扑结构
上图描述了如何采用Ingress配合NodePort和Load Balancer为集群提供外部流量入口,从该拓扑图中可以看到该架构的伸缩性非常好,在NodePort,Ingress,Pod等不同的接入层面都可以对系统进行水平扩展,以应对不同的外部流量要求。

上图只展示了逻辑架构,下面的图展示了具体的实现原理:
10.png

采用Ingress,NodePortal和LoadBalancer提供外部流量入口的实现原理
流量从外部网络到达Pod的完整路径如下:

  1. 外部请求先通过四层Load Balancer进入内部网络
  2. Load Balancer将流量分发到后端多个主机节点上的NodePort(userspace转发)
  3. 请求从NodePort进入到Ingress Controller(iptabes规则,Ingress Controller本身是一个NodePort类型的Service)
  4. Ingress Controller根据Ingress rule进行七层分发,根据HTTP的URL和Host将请求分发给不同的Service(userspace转发)
  5. Service将请求最终导入到后端提供服务的Pod中(iptabes规则)

从前面的介绍可以看到,Kubernetes Ingress提供了一个基础的七层网关功能的抽象定义,其作用是对外提供一个七层服务的统一入口,并根据URL/HOST将请求路由到集群内部不同的服务上。
#如何为服务网格选择入口网关?
在Istio服务网格中,通过为每个Service部署一个Sidecar代理,Istio接管了Service之间的请求流量。控制面可以对网格中的所有sidecar代理进行统一配置,实现了对网格内部流量的路由控制,从而可以实现灰度发布,流量镜像,故障注入等服务管控功能。但是,Istio并没有为入口网关提供一个较为完善的解决方案。
##Kubernetes Ingress
在0.8版本以前,Istio缺省采用Kubernetes Ingress来作为Service Mesh的流量入口。Kubernetes Ingress统一了应用的流量入口,但存在两个问题:

* Kubernetes Ingress是独立在Istio体系之外的,需要单独采用Ingress rule进行配置,导致系统入口和内部存在两套互相独立的路由规则配置,运维和管理较为复杂。
* Kubernetes Ingress rule的功能较弱,不能在入口处实现和网格内部类似的路由规则,也不具备网格Sidecar的其它能力,导致难以从整体上为应用系统实现灰度发布、分布式跟踪等服务管控功能。


11.jpg

采用Kubernetes Ingress作为服务网格的流量入口
##Istio Gateway
Istio社区意识到了Ingress和Mesh内部配置割裂的问题,因此从0.8版本开始,社区采用了 Gateway 资源代替K8s Ingress来表示流量入口。

Istio Gateway资源本身只能配置L4-L6的功能,例如暴露的端口,TLS设置等;但Gateway可以和绑定一个VirtualService,在VirtualService 中可以配置七层路由规则,这些七层路由规则包括根据按照服务版本对请求进行导流,故障注入,HTTP重定向,HTTP重写等所有Mesh内部支持的路由规则。

Gateway和VirtualService用于表示Istio Ingress的配置模型,Istio Ingress的缺省实现则采用了和Sidecar相同的Envoy proxy。

通过该方式,Istio控制面用一致的配置模型同时控制了入口网关和内部的sidecar代理。这些配置包括路由规则,策略检查、Telementry收集以及其他服务管控功能。
12.jpg

采用Istio Ingress Gateway作为服务网格的流量入口
##应用对API Gateway的需求
采用Gateway和VirtualService实现的Istio Ingress Gateway提供了网络入口处的基础通信功能,包括可靠的通信和灵活的路由规则。但对于一个服务化应用来说,网络入口除了基础的通讯功能之外,还有一些其他的应用层功能需求,例如:

* 第三方系统对API的访问控制
* 用户对系统的访问控制
* 修改请求/返回数据
* 服务API的生命周期管理
* 服务访问的SLA、限流及计费
* ……


13.png

Kubernetes ingress,Istio Gateway and API Gateway的功能对比

API Gateway需求中很大一部分需要根据不同的应用系统进行定制,目前看来暂时不大可能被纳入Kubernetes Ingress或者Istio Gateway的规范之中。为了满足这些需求,涌现出了各类不同的Kubernetes Ingress Controller以及Istio Ingress Gateway实现,包括Ambassador,Kong,Traefik,Solo等。

这些网关产品在实现在提供基础的Kubernetes Ingress能力的同时,提供了强大的API Gateway功能,但由于缺少统一的标准,这些扩展实现之间相互之间并不兼容。而且遗憾的是,目前这些Ingress Controller都还没有正式提供和Istio 控制面集成的能力。

备注:

* Ambassador将对Istio路由规则的支持纳入了Roadmap https://www.getambassador.io/user-guide/with-istio/
* Istio声称支持Istio-Based Route Rule Discovery(尚处于实验阶段)https://gloo.solo.io/introduction/architecture/

##采用API Gateway + Sidecar Proxy作为服务网格的流量入口
在目前难以找到一个同时具备API Gateway和Isito Ingress能力的网关的情况下,一个可行的方案是使用API Gateway和Sidecar Proxy一起为服务网格提供外部流量入口。

由于API Gateway已经具备七层网关的功能,Mesh Ingress中的Sidecar只需要提供VirtualService资源的路由能力,并不需要提供Gateway资源的网关能力,因此采用Sidecar Proxy即可。网络入口处的Sidecar Proxy和网格内部应用Pod中Sidecar Proxy的唯一一点区别是:该Sidecar只接管API Gateway向Mesh内部的流量,并不接管外部流向API Gateway的流量;而应用Pod中的Sidecar需要接管进入应用的所有流量。
14.png

采用API Gateway + Sidecar Proxy为服务网格提供流量入口

备注:在实际部署时,API Gateway前端需要采用NodePort和LoadBalancer提供外部流量入口。为了突出主题,对上图进行了简化,没有画出NodePort和LoadBalancer。

采用API Gateway和Sidecar Proxy一起作为服务网格的流量入口,既能够通过对网关进行定制开发满足产品对API网关的各种需求,又可以在网络入口处利用服务网格提供的灵活的路由能力和分布式跟踪,策略等管控功能,是服务网格产品入口网关的一个理想方案。

性能方面的考虑:从上图可以看到,采用该方案后,外部请求的处理流程在入口处增加了Sidecar Proxy这一跳,因此该方式会带来少量的性能损失,但该损失是完全可以接受的。

对于请求时延而言,在服务网格中,一个外部请求本来就要经过较多的代理和应用进程的处理,在Ingress处增加一个代理对整体的时延影响基本忽略不计,而且对于绝大多数应用来说,网络转发所占的时间比例本来就很小,99%的耗时都在业务逻辑。如果系统对于增加的该时延非常敏感,则我建议重新考虑是否应该采用微服务架构和服务网格,毕竟任何架构模式都不是万能的,不能因为有了锤子,看什么都像钉子。

对于吞吐量而言,如果入口处的网络吞吐量存在瓶颈,则可以通过对API Gateway + Sidecar Proxy组成的Ingress整体进行水平扩展,来对入口流量进行负荷分担,以提高网格入口的网络吞吐量。

原文链接:如何为服务网格选择入口网关?(作者:赵化冰)

DockOne微信分享(二零八):华尔街见闻Istio生产实践

尼古拉斯 发表了文章 • 0 个评论 • 752 次浏览 • 2019-04-24 18:41 • 来自相关话题

【编者的话】随着见闻业务不断增加,所涉及语⾔也越来越多。由于微服务化的引入,就需要为不同语言开发各自的服务发现、监控、链路追踪等组件,更新运维成本较高。同时应用的灰度部署也是见闻在着⼒解决的问题。 Istio通过下沉基础设置,很好的解决了组件跨语言兼容问题, ...查看全部
【编者的话】随着见闻业务不断增加,所涉及语⾔也越来越多。由于微服务化的引入,就需要为不同语言开发各自的服务发现、监控、链路追踪等组件,更新运维成本较高。同时应用的灰度部署也是见闻在着⼒解决的问题。 Istio通过下沉基础设置,很好的解决了组件跨语言兼容问题, 同时带来了智能路由、服务熔断、错误注入等重要的特性。整个搭建过程中也遇到了很多坑和经验,希望和大家分享。

见闻开发团队以Golang为主,同时存在Python,Java服务,这就需要SRE提供更容易接入的微服务基础组件,常见的方案就是为每种语言提供适配的微服务基础组件,但痛点是基础组件更新维护的成本较高。

为了解决痛点,我们将目光放到服务网格,它能利用基础设施下沉来解决多语言基础库依赖的问题,不同的语言不需要再引入各种不同的服务发现、监控等依赖库,只需简单的配置并运行在给定的环境下,就能享有服务发现、流量监控、链路追踪等功能,同时网络作为最重要的通信组件,可以基于它实现很多复杂的功能,譬如智能路由、服务熔断降级等。

我们调研了一些服务网格方案,包括Istio、Linkerd。

对比下来,Istio拥有更多活跃的开源贡献者,迭代速度快,以及Istio架构可行性讨论,我们选择Istio作为实践方案。

服务网格架构图:
1.png

这张图介绍了华尔街见闻典型的服务网格架构,左半图介绍了用户请求是如何处理,右半图介绍运维系统是如何监控服务。
#架构可行性
通过架构图,我们拆分出以下关键组件,经过评估,Istio高度模块化、可拓展,各个组件的可用性、拓展性都有相应的策略达到保障,我们认为Istio是具有可实施性的。
##Istio Ingress高性能,可拓展

性能:Istio Ingress用来处理用户入流量,使用Envoy实现,转发性能高。


可用性:保证实例数量并使用服务探活接口保证服务可用性。


拓展性:挂载在负载均衡后,通过增加实例实现可拓展。


##Istio Proxy随应用部署,轻微性能损耗,可随应用数量拓展

Istio Proxy以Sidecar形式随应用一起部署,增加2次流量转发,存在性能损耗。


性能:4核8G服务器,上面运行Proxy服务和API服务,API服务只返回ok字样。(此测试只测试极限QPS)


单独测试API服务的QPS在59k+,平均延时在1.68ms,CPU占用4核。 通过代理访问的QPS6.8k+,平均延时14.97ms,代理CPU占用2核,API服务CPU占用2核。


CPU消耗以及转发消耗降低了QPS,增加了延时,通过增加机器核数并增加服务部署数量解决该问题,经过测试环境测试,延时可以接受。 


可用性:基于Envoy,我们认为Envoy的可用性高于应用。依赖Pilot Discovery进行服务路由,可用性受Pilot Discovery影响。


拓展性:Sidecar形式,随应用数拓展。


##Istio Policy服务可拓展,但同步调用存在风险

Istio Policy需要在服务调用前访问,是同步请求,会增加服务调用延时,通过拓展服务数量增加处理能力。属于可选服务,华尔街见闻生产环境未使用该组件。 


性能:未测试。


可用性:若开启Policy,必须保证Policy高可用,否则正常服务将不可用。


拓展性:增加实例数量进行拓展。

##Istio Telemetry监控收集服务

性能:从监控上观察Report 5000qps,使用25核,响应时间p99在72ms。异步调用不影响应用的响应时间。


可用性:Telemetry不影响服务可用性。


拓展性:增加实例数量进行拓展。

##Pilot Discovery

性能:服务发现组件(1.0.5版本)经过监控观察,300个Service,1000个Pod,服务变更次数1天100次,平均CPU消耗在0.04核左右,内存占用在1G以内。


可用性:在服务更新时需要保证可用,否则新创建的Pod无法获取最新路由规则,对于已运行Pod由于Proxy存在路由缓存不受Pilot Discovery关闭的影响。


拓展性:增加实例数量可以增加处理量。
#服务监控
Istio通过mixer来搜集上报的遥测数据,并自带Prometheus、Grafana等监控组件,可方便的对服务状态进行监控。见闻目前监控在用Istio自带的,利用Prometheus拉取集群指标,经由Grafana看板展示,可直观展示出各种全局指标及应用服务指标,包括全局QPS、全局调用成功率、各服务延时分布情况、QPS及状态码分布等, 基本满足监控所需。

存储暂未做持久化操作,采用Prometheus的默认的内存存储,数据的存储策略可通过设定Prometheus的启动参数`--storage.tsdb.retention`来设定,见闻生产时间设定为了6h。

Prometheus服务由于数据存储原因会消耗大量内存,所以在部署时建议将Prometheus部署在专有的大内存node节点上,这样如果内存使用过大导致该node节点报错也不会对别的服务造成影响。Istio mixer担负着全网的遥测数据搜集任务,容易成为性能瓶颈,建议和Prometheus一样将其部署在专有节点上, 避免出现问题时对应用服务造成影响。

以下是Mesh汇总面板的Demo:
2.jpg

Service Mesh汇总监控页面
#链路追踪
Envoy原生支持分布式链路追踪, 如Jaeger、Zipkin等,见闻生产选择了Istio自带的Jaeger作为自身链路追踪系统。 默认Jaeger服务为all_in_one形式,包含jaeger-collect、jaeger-query、jaeger-agent等组件,数据存储在内存中。

见闻测试集群采用了此种部署形式。见闻生产环境基于性能与数据持久性考虑,基于Cassandra存储搭建了单独的jaeger-collect、jaeger-query服务。Jaeger兼容Zipkin,可以通过设定Istio ConfigMap中的`zipkinAddress`参数值为jaeger-collector对应地址,来设置Proxy的trace上报地址。同时通过设置istio-pilot环境变量`PILOT_TRACE_SAMPLING`来设置tracing的采样率,见闻生产采用了1%的采样率。

Tracing不像Istio监控系统一样对业务代码完全无侵入性。Envoy在收发请求时若发现该请求没有相关trace headers,就会为该请求自动创建。tracing的实现需要对业务代码稍作变动,这个变动主要用来传递trace相关的header,以便将一次调用产生的各个span串联起来。

见闻底层采用 grpc 微服务框架,在Gateway层面将trace header 加入到入口grpc调用的context中,从而将trace headers 逐级传递下去。
3.jpg

#Istio探活
Istio通过向Pod注入Sidecar接管流量的形式实现服务治理,那么就会有Sidecar与业务容器状态不同步的可能,从而造成各种的调用问题,如下两方面:

* Sidecar就绪时间晚于业务容器:业务容器此时若发起调用,由于Sidecar还未就绪, 就会出现类似no healthy upstream之类错误。若此时该Pod接收请求,就又会出现类似upstream connect error错误。
* Sidecar就绪时间早于业务容器:例如某业务容器初始化时间过长导致Kubernetes误以为该容器已就绪,Sidecar开始进行处理请求,此时就会出现类似upstream connect error错误。

4.jpg

5.jpg

探活涉及Sidecar、业务容器两部分,只有两部分同时就绪,此Pod才可以正式对外提供服务,分为下面两方面:

* Sidecar探活:v1.0.3及以上版本针对Pilot-agent新增了一个探活接口healthz/ready,涉及statusPort、applicationPorts、adminPort等三个端口。其基本逻辑为在statusPort上启动健康监测服务,监听applicationPorts设定的端口是否至少有一个成功监听,之后通过调用本地adminPort端口获取xDS同步状态。若满足至少一个applicationPort成功监听,且CDS、LDS都进行过同步,则该Sidecar才被标记为Ready。
* 业务容器探活:见闻通过基本库,在所有Golang grpc后端服务中注册了一个用于健康检查的handler, 该handler可由开发人员根据自身业务自定义,最后根据handler返回值来判断业务容器状态(如下图)。

6.jpg

#Istio应用更新
为了实现灰度部署,见闻基于Kubernetes Dashboard进行了二次开发,增加了对Istio相关资源的支持,利用Gateway、VirtualService、DestinationRule等crd实现了应用程序的灰度部署,实际细节如下:

1. 更新流量控制将流量指向已有版本
,利用VirtualService将流量全部指向v1版本(见下动图)。
2. 部署新版本的Deployment
,查找旧的Deployment配置,通过筛选app标签符合应用名的Deployment,运维人员基于该Deployment创建v2版本的Deployment,并向destinationRule中增加v2版本。
3. 更新流量控制将流量指向新版,本
利用VirtualService将ServiceA的服务流量全部指向v2版本。
4. 下线老版本的Deployment并删除对应DestinationRule。

利用Istio Dashboard来实现上述流程:
07.gif

为了方便开发人员服务部署,开发了精简版后台,并对可修改部分进行了限定。最终,SRE提供两个后台,对Istio Dashboard进行精细控制:
08.gif

#实践中的宝贵经验
在Istio实践过程中,有哪些需要注意的问题。
##API server的强依赖,单点故障

Istio对Kubernetes的API有很强的依赖,诸如流量控制(Kubernetes资源)、集群监控(Prometheus通过Kubernetes服务发现查找Pod)、服务权限控制(Mixer Policy)。所以需要保障API server的高可用,我们曾遇到Policy组件疯狂请求Kubernetes API server使API server无法服务,从而导致服务发现等服务无法更新配置。



* 为避免这种请求,建议使用者了解与API server直接通信组件的原理,并尽量减少直接通信的组件数量,增加必要的Rate limit。


* 尽量将与API server通信的服务置于可以随时关闭的环境,这是考虑如果部署在同一Kubernetes集群,如果API server挂掉,无法关闭这些有问题的服务,导致死锁(又想恢复API server,又要依靠API server关闭服务)。

##服务配置的自动化

服务配置是Istio部署后的重头戏,避免使用手动方式更改配置,使用代码更新配置,将常用的几个配置更新操作做到运维后台,相信手动一定会犯错。
##关于Pilot Discovery

Pilot Discovery 1.0.0版本有很大的性能问题,1.0.4有很大的性能提升,但引入了一个新bug,所以请使用1.0.5及以上的版本,我们观察到CPU消耗至少是1.0.0版本的1/10,大大降低了Proxy同步配置的延时。
##关于Mixer Policy 1.0.0

这个组件曾导致API server负载过高(很高的list pods请求),所以我们暂时束之高阁,慎用。
##性能调优

在使用Proxy、Telemetry时,默认它们会打印访问日志,我们选择在生产上关闭该日志。
时刻观察Istio社区的最新版本,查看新版本各个组件的性能优化以及bug修复情况,将Istio当做高度模块化的系统,单独升级某些组件。上面就提到我们在Istio1.0的基础上使用了1.0.5版本的Policy、Telemetry、Pilot Discovery等组件。
##服务平滑更新和关闭

Istio依靠Proxy来帮助APP进行路由,考虑几种情况会出现意外的状态:


* APP启动先于Proxy,并开始调用其它服务,这时Proxy尚未初始化完毕,APP调用失败。


* Service B关闭时,调用者Service A的Proxy尚未同步更新Service B关闭的状态,向Service B发送请求,调用失败。
第一种情况要求APP有重试机制,能适当重试请求,避免启动时的Proxy初始化与APP初始化的时差,Istio提供了retry次数配置,可以考虑使用。 
第二种情况,一种是服务更新时,我们使用新建新服务,再切流量;一种是服务异常退出,这种情况是在客户端重试机制。希望使用Istio的开发人员有更好的解决方案。

#Q&A
Q:学Service Mesh什么用?
A:Service Mesh是最近比较火的一个概念,和微服务、Kubernetes有密切关系。出于以后业务发展需要,可以学习下, 增加知识储备。见闻上Istio的主要目的在文章已说明,主要是基础服务的下沉,解决了语言兼容性问题, 还有一个就是灰度发布。

Q:链路追踪的采集方式是怎样的,比如Nodejs,C++等多语言如何支持的?
A:Envoy本身支持链路追踪,也就是将Envoy会在请求head中增加链路追踪相关的数据头,比如x-b3-traceid,x-b3-spanid等等。业务要做的就是将这些head沿着调用链路传递下去即可。所以多语言的话需要在自己的业务侧实现该逻辑。所以Istio的链路追踪对业务代码还是有很小的侵入性的(这个分享中有说明)。

Q:Istio与Spring Cloud两者的优缺点与今后的发展趋势会是怎么样?
A:见闻技术栈是Golang,所以没太认真对比过两者。从社区活跃度上将,Istio > Spring Cloud,稳定性方面,Spring Cloud是更有优势,更适合Java沉淀较深的企业。但个人感觉对于更多企业来讲,跨越了语言兼容性的Istio未来发展很值得期待。

Q:Docker镜像部署可以做到代码保护吗,比如像Nodejs这种非二进制执行程序的项目?
A:代码保护可以通过将镜像上传至指定云服务商上的镜像仓库中,见闻是将自己的业务镜像提交保存在了腾讯云。如果镜像泄露,那么非二进制执行程序的代码还是有泄露风险的。

Q:选型时为什么没考虑Linkerd?
A:选型之初也调研了Linkerd, 对比下来,Istio拥有更多活跃的开源贡献者,迭代速度快,以及Istio架构相较于见闻有较大可行性,所以选择了Istio作为实践方案。

Q:Istio在做运维部署时没有UI工具,你们如何实现运维人员更加便捷地使用?
A:见闻基于Kubernetes官方的Dashboard, 对内容进行了扩充,增加了对Gateway,VirtualService等Istio crd资源的支持, 同时增加了灰度部署等和见闻运维业务相关的功能,所以一定程度上解决了运维部署的问题。

Q:流量从Sidecar代理势必会对请求响应时间有影响,这个有没有更详细案例的说明性能上的损耗情况?
A:Sidecar的转发其实带来了性能一定的性能损耗。4核8G服务器,上面运行Proxy服务和API服务,API服务只返回ok字样。(此测试只测试极限QPS)单独测试API服务的QPS在59k+,平均延时在1.68ms,CPU占用4核。通过代理访问的QPS6.8k+,平均延时14.97ms,代理CPU占用2核,API服务CPU占用2核。 CPU消耗以及转发消耗降低了QPS,增加了延时,通过增加机器核数并增加服务部署数量缓解该问题,经过测试环境测试,延时可以接受。

Q:Sidecar在生产中资源占用为多少?是否会对集群资源占用很多?
A:以单个Pod为例,见闻业务单个Pod中Sidecar所占资源约占整个Pod所耗资源的1/10。

Q:Jeager你们是进行了代码埋点吗?更为底层代码级别的追踪,有用其他方案吗?
A:Envoy本身对tracing有良好的支持,所以业务端所做的改动只需将其所产生的追踪数据延续下去即可。上Istio之前,见闻在相关微服务中通过在基础库中增加链路追踪逻辑(Zipkin)实现了链路追踪,不过只做了Golang版,多语言兼容开发运维难度较大。

Q:相信咱们的mixer在生产环境中,也出现过瓶颈,咱们从哪几个大方向优化的?如何优化的?方面讲解一下吗?
A:mixer见闻在生产过程中所遇的坑在于Policy组件, 会疯狂的list pod,导致API server负载骤增,之后见闻基于自身业务关闭了Policy。

Q:Istio组件实现了高可用么?
A:Istio本身也是基于Kubernetes,所以可用性还是有较好保证的。

以上内容根据2019年4月23日晚微信群分享内容整理。分享人张安伟,华尔街见闻SRE团队运维工程师,负责公司日常运维开发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

基于Kubernetes的微服务可观测性和Istio服务网格(二)

dummy 发表了文章 • 0 个评论 • 524 次浏览 • 2019-04-22 17:01 • 来自相关话题

在本系列文章中,我们将继续探索可观测性工具集,这些工具集作为最新的Istio服务网格中的一部分,包含了Prometheus和Grafana用于度量指标收集、监控和警报,Jaeger用于分布式跟踪,以及Kiali为Istio提供基于服务网格的微服务可视化。同时结 ...查看全部
在本系列文章中,我们将继续探索可观测性工具集,这些工具集作为最新的Istio服务网格中的一部分,包含了PrometheusGrafana用于度量指标收集、监控和警报,Jaeger用于分布式跟踪,以及Kiali为Istio提供基于服务网格的微服务可视化。同时结合云平台原生的监控和日志记录服务,例如谷歌云平台上Google Kubernetes Engine(GKE)Stackdriver,我们为现代分布式应用程序提供了完整的可观测性解决方案。
# 参考平台
为了演示Istio的可观测性工具,在系列的第一部分中,我们部署一个参考平台,包含了8个基于Go的微服务,以服务A-H来标识,1个Angular 7基于TypeScript的前端,4个MongoDB数据库实例和一个RabbitMQ队列用于基于事件队列的通信。
1.png

该参考平台旨在生成基于HTTP的服务到服务,基于TCP的服务到数据库以及基于TCP的服务到队列再到服务(RabbitMQ)的IPC(进程间通信)。服务A调用服务B和C,服务B调用服务D和E,服务D生产消息到RabbitMQ队列供服务F来消费并写入到MongoDB,依此类推。目标是在将系统部署到Kubernetes时使用Istio的可观测性工具来观察这些分布式通信。
# 日志记录
我们在第一部分说到,日志、指标和跟踪通常被称为可观测性的三大核心支柱。当我们在GCP上使用GKE时,我们能利用谷歌云的Stackdriver Logging产品。据谷歌宣称, Stackdriver Logging允许你存储、搜索、分析、监控和根据来自GCP甚至是AWS的数据和事件来进行告警。虽然Stackdriver Logging不包含在Istio可观测性功能中,但是日志记录是整体可观测性策略的重要核心之一。
## 基于Go语言的微服务日志记录
有效的日志记录策略包含了记录的内容,何时记录以及如何记录。作为我们的日志记录策略的一部分,八个基于Go的微服务使用了Logrus,这是一个流行的结构化记录日志组件。这些微服务同时还实现了Banzai Cloud的logrus-runtime-formatter,关于这个日志插件有一篇优秀的文章:《Golang runtime Logrus Formatter》。这两个日志记录软件包能让我们更好地控制记录的内容,何时记录和如何记录关于我们的微服务的信息。使用这个软件包需要的配置也相当少。
func init() {
formatter := runtime.Formatter{ChildFormatter: &log.JSONFormatter{}}
formatter.Line = true
log.SetFormatter(&formatter)
log.SetOutput(os.Stdout)
level, err := log.ParseLevel(getEnv("LOG_LEVEL", "info"))
if err != nil {
log.Error(err)
}
log.SetLevel(level)
}

Logrus比Go内置的简单的日志包log提供多了几个优点。日志不仅只记录致命性错误,同时我们也不应该在生产环境中输出所有明细的日志。本文中涉及到的微服务利用了Logrus的七种日志级别:Trace、Debug、Info、Warning、Error、Fatal和Panic。我们还将日志级别作为变量,允许在部署时在Kubernetes Deployment资源中轻松更改它。

这些微服务同时还利用了Banzai Cloud的logrus-runtime-formatter。这个格式化工具能自动地给日志消息标记上运行时/堆栈信息,包括函数名和代码行号,这些信息在排除故障时非常有用。我们也使用了Logrus的JSON日志格式。注意下面的日志条目是如何将JSON有效负载包含在消息中的。
2.png

## 客户端层面的UI日志记录
同样地,我们使用NGX Logger增强了Angular UI的日志记录。NGX Logger是一个流行,简单的日志记录模块,目前用于Angular 6和7。它能将控制台输出打印得更好看,并允许将被POST到某个服务端URL的消息记录下来。在这次演示中,我们只将日志打印到控制台。与Logrus类似,NGX Logger也支持多种日志级别:Trace、Debug、Info、Warning、Error、Fatal和关闭。NGX Logger不仅可以输出消息,还允许我们将日志条目以合适的格式输出到Web浏览器的控制台。

日志输出级别取决于不同的环境,生产与非生产。下图我们可以看到在本地开发环境中的日志条目,包括了Debug、Info和Error级别。
3.png

在下图基于GKE的生产环境中我们能看到相同的页面。但是请注意,我们无需修改任何配置,Debug级别的日志条目将不会输出到控制台中。我们不希望暴露包含潜在敏感信息的日志给生产环境的终端用户。
4.png

通过将以下三元运算符添加到app.module.ts文件中来实现控制日志记录级别。
LoggerModule.forRoot({
level: !environment.production ? NgxLoggerLevel.DEBUG : NgxLoggerLevel.INFO,
serverLogLevel: NgxLoggerLevel.INFO
})

# 指标
关于指标,我们来看看PrometheusGrafana。这两个先进的工具已作为Istio部署的一部分被安装。
## Prometheus
Prometheus是一个完全开源和社区型驱动的系统监控和告警工具,大约在2012年SoundCloud创建了这个项目。有趣的是,Prometheus于2016年加入云原生计算基金会(CNCF)作为第二个托管项目,众所周知第一个是Kubernetes

根据Istio文档说明,Istio的Mixer中内置了一个Prometheus适配器,它可以暴露一个用于服务那些生成的度量值的端点。这里所说的Prometheus附加组件是一个预先配置了去收集Mixer端点上暴露的指标的Prometheus服务器。它提供了持久存储和查询Istio指标的机制。

GKE集群已跑起来,Istio也已安装,平台已部署,那怎么访问Prometheus?最简单的方法是使用`kubectl port-forward`来连接到Prometheus服务器。根据Google的说法,Kubernetes的端口转发从v1.10版本以后允许使用资源名称(例如服务名称)来选择匹配的Pod。我们将本地端口转发到Prometheus Pod上的端口。
5.png

你可以使用Google Cloud Shell进行连接,也可以将命令复制粘贴到本地shell以从本地端口进行连接。以下是本文中使用的端口转发命令。
# Grafana
kubectl port-forward -n istio-system \
$(kubectl get pod -n istio-system -l app=grafana \
-o jsonpath='{.items[0].metadata.name}') 3000:3000 &

# Prometheus
kubectl -n istio-system port-forward \
$(kubectl -n istio-system get pod -l app=prometheus \
-o jsonpath='{.items[0].metadata.name}') 9090:9090 &

# Jaeger
kubectl port-forward -n istio-system \
$(kubectl get pod -n istio-system -l app=jaeger \
-o jsonpath='{.items[0].metadata.name}') 16686:16686 &

# Kiali
kubectl -n istio-system port-forward \
$(kubectl -n istio-system get pod -l app=kiali \
-o jsonpath='{.items[0].metadata.name}') 20001:20001 &

Prometheus文档中写道,用户可使用名为PromQL(Prometheus查询语言)的函数查询语言来实时选择和汇总时间序列数据。查询表达式的结果可在Prometheus的Web UI中显示为表格数据并绘制为图形,也可以通过Prometheus的HTTP API由外部系统使用。Web UI界面包含了一个下拉菜单,其中包含所有可用指标作为构建查询的基础。下面显示的是本文中使用的一些PromQL示例。
up{namespace="dev",pod_name=~"service-.*"}
container_memory_max_usage_bytes{namespace="dev",container_name=~"service-.*"}
container_memory_max_usage_bytes{namespace="dev",container_name="service-f"}
container_network_transmit_packets_total{namespace="dev",pod_name=~"service-e-.*"}
istio_requests_total{destination_service_namespace="dev",connection_security_policy="mutual_tls",destination_app="service-a"}
istio_response_bytes_count{destination_service_namespace="dev",connection_security_policy="mutual_tls",source_app="service-a"}

在下图显示的Prometheus控制台中,我们看到了部署到GKE的八个基于Go的微服务的示例图。该图显示了五分钟内的容器内存使用情况。在一半的时间内,服务处于休息状态。另一半时间区域,服务使用了`hey`工具来模拟负载。查看负载下服务的内存简况可以帮助我们确定容器内存最小值和限制,这会影响Kubernetes在GKE集群上的工作负载调度。诸如此类的度量标准也可能会发现内存泄漏或路由问题,例如下面的服务,它似乎比同类服务消耗的内存多25-50%。
6.png

下面的另一个例子,这个图表表示系统处于负载状态下`dev`命名空间中对服务A的总的Istio请求。
7.png

比较上面的图表视图与控制台视图中显示的相同指标,多个指标显示了在检测的五分钟周期内,`dev`命名空间里的服务A的多个实例。各个度量标准元素中的值指出了收集到的最新度量标准。
8.png

Prometheus同时还收集有关Istio组件,Kubernetes组件和GKE集群的基本指标。下面我们可以查看GKE集群中每个n1-standard-2虚机节点的总内存。
9.png

## Grafana
Grafana自称是一个先进的时间序列分析开源软件。根据Grafana Labs的说法,Grafana允许你查询,可视化,提醒和了解熟悉你的指标,无论它们是存放在哪里。你可以轻松创建,浏览并共享具有丰富视觉效果的以数据驱动的仪表板。Grafana还能直观地让你为那些最重要的指标定义警报规则,它将不断评估规则并发送通知。

Istio文档中写到,Grafana附加组件其实是一个预先配置好的Grafana实例。Grafana的容器基础镜像已被修改为支持Prometheus数据源和适配到Istio仪表板。Istio的基本安装文件,特别是Mixer,包含了一个默认的全局的(用于每个服务)度量标准的配置。预配置的Istio仪表板可与默认的Istio指标配置和Prometheus后端结合使用。

我们在下图可以看到预先配置的Istio负载仪表板。较大的仪表板的特定部分已过滤用于显示在GKE集群中`dev`命名空间中的出站服务指标。
10.png

同样,在下面我们看到预先配置的Istio服务仪表板。较大的仪表板的特定部分已过滤用以显示GKE集群中Istio Ingress Gateway的客户端工作负载指标。
11.png

最后,我们看到预配置的Istio网格仪表板。此仪表板同样已过滤用以显示部署到GKE集群的组件的度量标准的表格视图。
12.png

有效的可观测性策略一定不仅仅包括可视化结果的能力,还必须包括异常检测并通知(警报)合适的资源或直接采取行动以解决事件的能力。像Prometheus一样,Grafana能够发出警报和通知。你可以直观地为关键指标定义警报规则。Grafana将根据规则不断评估指标,并在违反预定义阈值时发送通知。

Grafana支持多种流行的通知渠道,包括PagerDuty、HipChat、Email、Kafka和Slack。下面是一个新的通知频道,它向Slack支持频道发送警报通知。
13.png

Grafana能够发送详细的基于文本和视图的通知。
14.png

# 链路跟踪
根据Open Tracing网站介绍,分布式跟踪(也称为分布式请求跟踪)是一种用于分析和监控应用程序的方法,尤其是那些使用微服务架构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。

Istio中说到,尽管Istio中的代理程序能够自动发送span信息,但应用程序需要能传播适当的HTTP头信息,这样当代理发送span时,该span可以正确地关联到单个跟踪中。为此,应用程序需要收集传入请求中的以下头部并将其传播到任何传出的请求。

  • `x-request-id`
  • `x-b3-traceid`
  • `x-b3-spanid`
  • `x-b3-parentspanid`
  • `x-b3-sampled`
  • `x-b3-flags`
  • `x-ot-span-context`

`x-b3`头部一开始作为Zipkin项目的一部分。标题的B3部分以Zipkin的原始名称BigBrotherBird命名。在服务调用之间传递这些标头称为B3传播。根据Zipkin文档,这些属性在进程间传播,最终在下游(通常通过HTTP头)传播,以确保来自同一根的所有活动被收集在一起。

为了演示Jaeger的分布式跟踪,我修改了服务A,服务B和服务E,这三个服务会向其他上游服务发出HTTP请求。我添加了以下代码以便将标头从一个服务传播到下一个服务。Istio的边车代理,即Envoy生成第一个报头。至关重要的是,你只需传播下游请求中存在且包含值的标头,如下代码所示。传播任何一个空的请求头将破坏分布式跟踪。
headers := []string{
"x-request-id",
"x-b3-traceid",
"x-b3-spanid",
"x-b3-parentspanid",
"x-b3-sampled",
"x-b3-flags",
"x-ot-span-context",
}
for _, header := range headers {
if r.Header.Get(header) != "" {
req.Header.Add(header, r.Header.Get(header))
}
}

下图在高亮的Stackdriver日志条目的JSON有效负载中,我们看到从根span传播所需的头部,其中包含一个值,在上游请求中从服务A传递到服务C。
15.png

## Jaeger
Jaeger是受DapperOpenZipkin启发,是Uber科技开源的一套分布式跟踪系统。它用于监控和为基于微服务的分布式系统提供故障排除功能,包括了分布式上下文传播、分布式事务监控、根源分析、服务依赖性分析以及性能和延迟优化。Jaeger网站对Jaeger的架构和通用的跟踪相关术语进行了很好的概述。

下面我们看到Jaeger UI的Traces(跟踪)页面。其显示在大约四十分钟时间内搜索Istio Ingress Gateway服务的结果。我们在顶部看到了跟踪时间线,下面是跟踪结果列表。正如Jaeger网站上所讨论的,跟踪由span组成。span表示Jaeger中具有操作名称的逻辑工作单元。一次跟踪代表了通过系统的执行路径,可以被认为是有向无环图(DAG)或span。如果你曾使用过类似Apache Spark这样的系统,那么你可能已经很熟悉DAG是什么。
16.png

下面我们看到Jaeger UI的Trace Detail(跟踪详情)页面。该示例跟踪包含16个span,其中包含八个服务,七个基于Go的服务和一个Istio Ingress Gateway。跟踪和span都有各自的时间记录。跟踪中的根span是Istio Ingress Gateway。在终端用户的Web浏览器中加载的Angular UI通过Istio Ingress Gateway调用网格边缘服务A。从这一步开始,我们看到了服务到服务间IPC的预期流程。服务A调用服务B和C,服务B调用服务E,E又调用服务G和服务H。在该演示中,跟踪不贯穿RabbitMQ消息队列。这意味着你不能从RabbitMQ中看到包含从服务D到服务F的调用的跟踪。
17.png

在Jaeger UI跟踪详情页中,你还可以定位到包含其他元数据的单个范围。元数据包括被调用的URL、HTTP方法、响应状态和其他几个头部信息。
18.png

Jaeger的最新版本还包括Compare(对比)功能和两个Dependencies(依赖)视图,力导向图和DAG。我发现这两种视图与Kiali相比比较原始,与Service Graph更相似。在Kiali成为可能之前,这些作为依赖图来说非常有用。
19.png

# Kiali:微服务观测
Kiali网站上,我们大部分人对服务网格存在的问题得到了解答:我的Istio服务网格中有哪些微服务,它们是如何连接的?这里通过一个通用的Kubernetes Secret对象来控制对Kiali API和UI的访问。默认登录名是`admin`,密码是`1f2d1e2e67df`。
20.png

登录到Kiali后,我们能看到Overview菜单条目,它提供了Istio服务网格中所有命名空间的全局视图以及每个命名空间中的应用程序数。
21.png

Kiali UI中的图形视图是在Istio服务网格中运行的组件的直观展示。下面,对集群的`dev`命名空间进行过滤,我们可以观察到Kiali映射了8个应用程序(工作负载),10个服务和24个边界(图形术语)。具体来说,我们看到服务网格边缘的Istio Ingress代理、Angular UI、八个基于Go的微服务及其处理流量的Envoy代理边车(在此示例中服务F没有从其他服务直接获取流量),外部MongoDB Atlas集群和外部CloudAMQP集群。注意服务到服务的流量走向,通过Istio是如何从服务流向其边车代理再流向另一个服务的边车代理,最后到达其他服务。
22.png

下面,我们看到了服务网格的类似视图,但此时Istio Ingress网关和服务A之间存在故障,以红色显示。我们还可以观察HTTP流量的总体指标,例如每分钟共多少请求,错误和状态代码。
23.png

Kiali还可以显示图表中每个边界的平均请求时间和其他指标(即两个组件之间的通信)。
24.png

Kiali还可以显示部署的应用程序版本,如下所示,微服务中包含了版本1.3和1.4。
25.png

再说到外部的MongoDB Atlas集群,Kiali还允许我们查看在服务网格中的四个服务与外部集群的TCP流量。
26.png

“Applications(应用)”菜单列表列出了所有应用程序及其错误率,可以按命名空间和时间间隔进行筛选。在这里,我们看到Angular UI以16.67%的速率产生错误。
27.png

在Applications跟Workloads菜单条目中,我们可以深入查看组件以查看其详细信息,包括总体运行状况,Pod数量,服务和目标服务。下面我们可以查看在`dev`命名空间中服务B的详细信息。
28.png

Workloads详细视图还包括入站和出站指标。下面是`dev`命名空间中服务A的出站流量,持续时间和大小度量标准。
29.png

最后,Kiali还提供了一个Istio Config菜单。Istio Config菜单显示用户环境中存在的所有可用Istio配置对象的列表。
30.png

通常情况下,Kiali是我在解决平台问题时的第一个工具。一旦我确定了有问题的特定组件或通信路径,我就可以搜索Stackdriver日志和通过Grafana仪表板搜索Prometheus指标。
# 结论
在本系列文中,我们探索了当前最新版本的Istio服务网格中的一部分,可观测性工具集。它包括了Prometheus和Grafana,用于度量指标收集,监控和警报,Jaeger用于分布式跟踪,以及Kiali提供给Istio基于服务网格的微服务可视化。结合云平台本地监控和日志记录服务,例如谷歌云平台(GCP)上的Google Kubernetes Engine(GKE)Stackdriver,我们为现代分布式应用程序提供了完整的可观测性解决方案。

原文链接:Kubernetes-based Microservice Observability with Istio Service Mesh: Part 2(翻译:冯旭松)

基于Kubernetes的微服务可观测性与Istio服务网格(一)

dummy 发表了文章 • 0 个评论 • 783 次浏览 • 2019-04-19 15:40 • 来自相关话题

本系列文章将分为两部分,在此我们将探讨Istio服务网格中一部分,即可观测性工具集。这些工具包含了Jaeger、Kiali、Prometheus以及Grafana。为辅助我们此行探索,我们将在GCP上部署基于Go的微服务参考平台到GKE上去。 ...查看全部
本系列文章将分为两部分,在此我们将探讨Istio服务网格中一部分,即可观测性工具集。这些工具包含了Jaeger、Kiali、Prometheus以及Grafana。为辅助我们此行探索,我们将在GCP上部署基于Go的微服务参考平台到GKE上去。
1.png

# 什么是可观测性
与区块链、无服务器、AI和机器学习、聊天机器人、网络安全和服务网格类似,可观测性现在是IT行业中的一大热门话题。根据维基百科记录,可观测性指的是如何从外部输出来推断衡量系统内部状态。日志、指标和跟踪通常被成为可观测性的三大核心支柱。这些是我们可观察到的系统的外部输出。

由Cindy Sridharan撰写,O’Reilly出版的分布式系统可观测性一书在第四章节中详细地介绍了“可观测性的三大支柱”。在继续下文之前,我强烈建议你阅读下这篇在线摘录。关于可观测性资讯的另一大来源是honeycomb.io,一个生产系统可观测性工具的开发商,由知名的行业思想领袖Charity Majors领导。这个站点上面发布了很多关于可观测性的文章、博文、白皮书和博客。

随着现代分布式系统变得越发复杂,想具备观察这些系统的能力需要同样在设计之初就考虑到适配如此复杂环境的现代化的工具。传统的日志记录和监控系统通常与当今的混合和多云、基于多种语言、事件驱动、基于容器和无服务器、可无限扩展的、临时计算的平台相竞争。

Istio服务网格这类工具试图通过提供与几种同类最佳的开源遥测工具的原生集成方案来解决可观测性带来的挑战。Istio的集成包括Jaeger用于分布式跟踪,Kiali用于分布式系统可视化,PrometheusGrafana用于度量指标收集、监控和警报。同时结合云平台原生的监控和日志服务,例如谷歌云平台上Google Kubernetes Engine(GKE)Stackdriver,我们为现代化的分布式应用打造完整的可观测平台。
# 一个供参考的微服务平台
为了演示与最新版本的Istio服务网格集成的可观测性工具,我们将部署一个具备参考意义的,使用Go编写的微服务平台到GKE上面去。我开发了相关参考服务平台来演示涉及到的概念,例如API管理、服务网格、可观测性、DevOps和混沌工程等。该平台由14个组件组成,包含了8个基于Go的微服务,以服务A-H来标记,一个Augular 7,基于TypeScript的前端,4个MongoDB数据库实例,一个RabbitMQ队列用于基于事件队列的通信。该平台以及所有代码都已开源。

该参考平台旨在生成基于HTTP的服务到服务,基于TCP的服务到数据库以及基于TCP的服务到队列再到服务(RabbitMQ)的IPC(进程间通信)。服务A调用服务B和C,服务B调用服务D和E,服务D生产消息到RabbitMQ队列供服务F来消费并写入到MongoDB,依此类推。当这个系统部署到运行Istio服务网格的Kubernetes集群中时,可以使用Istio的可观测性工具来观察这些分布式通信。
## 服务响应
在该平台上,每个上游服务通过返回一个小的JSON信息负载(在源码中称为问候语)来响应下游服务的请求。
2.png

这些请求响应在调用链中聚合,进而产生给边缘服务的一系列服务响应,并返回给UI界面,最终展示在用户的浏览器中。响应聚合功能只是简单验证服务到服务间通信,Istio组件和遥测工具都能否正常工作。
3.png

所有的Go微服务都包含一个`/ping`和`/health`端点。`/health`端点用于配置Kubernetes的存活以及就绪探针。此外,边缘服务A使用响应头`access-control-allow-origin: *`用来配置Cross-Origin Resource Sharing(CORS)。CORS允许用于浏览器来调用位于与UI不同子域的`/ping`端点。相关服务A的源码可以在此查看。

在本次演示中,MongoDB数据库将被托管到GCP的外部,即MongoDB Atlas,它是一个基于云的MongoDB即服务平台。同样的,RabbitMQ队列服务将被托管到CloudAMQP,这是一个基于云的RabbitMQ即服务平台。我曾在之前的几篇文章中使用过这两种Saas供应商。使用外部服务将帮助我们了解Istio和它的可观测性工具是如何为位于Kubernetes集群中和外部系统的通信提供遥测的。

服务F消费来自RabbitMQ队列的消息,服务D将消息写入队列并写入到MongoDB中,这些服务都能通过对应链接打开直接查看源码。
# 源码
所有本文涉及到的源码都可以在GitHub的两个项目中找到。基于Go的微服务的源码,所有的Kubernetes资源和部署脚本都位于k8s-istio-observe-backend这个项目仓库中。Angular UI前端项目源码位于k8s-istio-observe-frontend中。此次演示中你将不需要下载前端项目。
git clone --branch master --single-branch --depth 1 --no-tags \
https://github.com/garystafford/k8s-istio-observe-backend.git

Kubernetes资源中引用到的相关Go服务和UI界面的容器镜像,都可以在Docker Hub上找到。Go服务镜像是使用官方的Golang Alpine来作为基础镜像,包含了Go 1.12.0版本。使用Alpine镜像来编译源码将能保证容器镜像尽可能地小并且包含更小的可攻击面。
# 系统要求
文章接下来的部分,你需要将最新版本的`gcloud`的客户端工具(最小版本要求为239.0.0)、Helm和刚刚发布的Istio 1.1.0版本安装并配置在你的本地或者是构建机器上。
4.png

# 配置和安装
为了将该微服务平台部署到GKE,我们将按以下步骤进行:

  1. 创建MongoDB Atlas数据库集群
  2. 创建CloudAMQP RabbitMQ集群
  3. 根据自己的环境调整Kubernetes的资源文件和脚本
  4. 在GCP上创建GKE集群
  5. 使用Helm在GKE集群中部署Istio 1.1.0版本
  6. 为平台中需要暴露访问的资源创建DNS记录
  7. 部署所有Go微服务,Angular UI和与GKE相关联的资源
  8. 测试或为你的平台排障
  9. 在第二篇中查看观察的结果

# MongoDB Atlas集群
MongoDB Atlas是一个完全托管的MongoDB即服务,可在AWS、Azure和GCP上使用。Atlas是一款成熟的SaaS产品,提供高可用性,有保证的正常运行时间SLA,弹性可扩展性,跨区域复制,企业级安全性,LDAP集成,BI连接器等等。

MongoDB Atlas目前提供有四种定价方案,包含免费版、基础版、高级版和企业版。这些方案范围从最小的共享内存和512MB存储的M0规模的MongoDB集群,到最高具有488GB内存和3TB存储的大型M400 MongoDB集群。

在本文中,我在GCP的us-central1地区创建了一个M2大小的MongoDB集群,并为该演示创建了一个数据库账户,该帐户将用于连接GKE上运行的八个基于Go的微服务的其中四个。
5.png

最初我使用了一个M0大小的集群,但发现计算资源不足以支撑来自这些Go语言的微服务。在此我建议至少使用M2大小乃至更大的集群。
# CloudAMQP RabbitMQ集群
CloudAMQP在所有主流云供应商和应用程序平台上提供完全托管的RabbitMQ集群。RabbitMQ将支持一部分基于Go的微服务的解耦,最终一致的基于消息的架构。在本文中,我同样在GCP的us-central1区域创建了一个RabbitMQ集群,与我们的GKE集群和MongoDB Atlas集群相同,我选择了一个最低配置的RabbitMQ免费版本。CloudAMQP还提供强大的多节点RabbitMQ集群以供生产级别环境使用。
# 修改配置
在GitHub项目中的Kubernetes资源文件和Bash部署脚本中你需要对应调整部分配置设置。
## 配置MongoDB Atlas的Istio ServiceEntry
external-mesh-mongodb-atlas.yaml文件中添加MongoDB Atlas主机地址。此文件允许从GKE上的四个微服务到外部MongoDB Atlas集群的出口流量。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: mongodb-atlas-external-mesh
spec:
hosts:
- {{ your_host_goes_here }}
ports:
- name: mongo
number: 27017
protocol: MONGO
location: MESH_EXTERNAL
resolution: NONE

## 配置CloudAMQP RabbitMQ的Istio ServiceEntry
external-mesh-cloudamqp.yaml文件中添加CloudAMQP主机地址,此文件允许从两个微服务到CloudAMQP群集的出口流量。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: cloudamqp-external-mesh
spec:
hosts:
- {{ your_host_goes_here }}
ports:
- name: rabbitmq
number: 5672
protocol: TCP
location: MESH_EXTERNAL
resolution: NONE

## Istio Gateway和VirtualService
通过Istio你可以有许多策略用于配置路由流量。此文中我使用了example-api.com这个域名,还有4组子域名。一组子域用于Angular UI,分别是dev命名空间(ui.dev.example-api.com)和test命名空间(ui.test.example-api.com)。另一组子域用于边缘API微服务,即被UI界面调用的服务A(api.dev.example-api.comapi.test.example-api.com)。流量将根据URL路由到特定的Kubernetes服务去。

Istio中所定义的Gateway对象描述了一个在网格边缘操作的负载均衡器,它负责接收传入或传出的HTTP/TCP连接。修改Istio ingress Gateway,在该hosts部分中插入你自己的域名或子域,这些是端口80上允许进入网格的主机。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: demo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- ui.dev.example-api.com
- ui.test.example-api.com
- api.dev.example-api.com
- api.test.example-api.com

Istio中的VirtualService定义了一组主机域名被寻址时应用的流量路由规则。一个VirtualServiceGateway绑定来控制到达特定主机和端口的流量的转发。修改项目中的4个VirtualServices,将你的域名或子域添加进去。以下是在istio-gateway.yaml中一个VirtualService的例子。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: angular-ui-dev
spec:
hosts:
- ui.dev.example-api.com
gateways:
- demo-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
host: angular-ui.dev.svc.cluster.local

## Kubernetes Secret
该项目中包含了一个Kubernetes Secret对象,go-srv-demo.yaml文件中指定了两个键值,一个用于MongoDB Atlas的连接,一个用于CloudAMQP,Kubernetes中的Secret的值需要经过`base64`加密。
apiVersion: v1
kind: Secret
metadata:
name: go-srv-config
type: Opaque
data:
mongodb.conn: {{ your_base64_encoded_secret }}
rabbitmq.conn: {{ your_base64_encoded_secret }}

在Linux和Mac上,你能直接使用`base64`程序来对此连接字符串进行编码。
> echo -n "mongodb+srv://username:password@atlas-cluster.gcp.mongodb.net/test?retryWrites=true" | base64
bW9uZ29kYitzcnY6Ly91c2VybmFtZTpwYXNzd29yZEBhdGxhcy1jbHVzdGVyLmdjcC5tb25nb2RiLm5ldC90ZXN0P3JldHJ5V3JpdGVzPXRydWU=

[quote] echo -n "amqp://username:password@rmq.cloudamqp.com/cluster" | base64
YW1xcDovL3VzZXJuYW1lOnBhc3N3b3JkQHJtcS5jbG91ZGFtcXAuY29tL2NsdXN0ZXI=

## Bash脚本变量
脚本part3_create_gke_cluster.sh包含了一系列环境变量。你至少需要更改所有脚本中的PROJECT变量为你的GCP项目名。
# 对应修改这些常量
readonly PROJECT='{{ your_gcp_project_goes_here }}'
readonly CLUSTER='go-srv-demo-cluster'
readonly REGION='us-central1'
readonly MASTER_AUTH_NETS='72.231.208.0/24'
readonly GKE_VERSION='1.12.5-gke.5'
readonly MACHINE_TYPE='n1-standard-2'

脚本part4_install_istio.sh中包含了ISTIO_HOME这个变量,该值应与你本地的Istio 1.1.0的路径一致。下面是在我本地的Mac上的值:
readonly ISTIO_HOME='/Applications/istio-1.1.0'

# 部署GKE集群
接下来使用脚本part3_create_gke_cluster.sh来部署GKE集群。这一步将创建一个区域,多可用区的3节点的GKE集群。该集群将会被部署到与MongoDB Atlas和CloudAMQP集群相同的区域,即us-central1(Iowa)。规划云资源所处的位置,对于Saas供应商和主流云供应商而言,能最大限度地减少网络I/O密集型应用程序的延迟。
6.png

# 使用Helm部署Istio
等待GKE集群和相关的基础设施就绪后,我们将部署Istio。此文中,我推荐选择使用Helm部署Istio的部署方式。要使用该种方式,请使用脚本part4_install_istio.sh
7.png

该脚本使用本地Istio 1.1.0中`install/kubernetes/helm/istio`目录中的Helm Chart安装Istio。该安装脚本使用`--set`命令行标志覆写了Istio Helm Chart中的多个默认值。相关可用的配置项在GitHub project中有详细说明。这些选项启用了Istio的可观测性功能,包含Kiali、Grafana、Prometheus和Jaeger,这些我们将在本系列的第二篇中探索。
helm install ${ISTIO_HOME}/install/kubernetes/helm/istio-init \
--name istio-init \
--namespace istio-system[/quote]

helm install ${ISTIO_HOME}/install/kubernetes/helm/istio \
--name istio \
--namespace istio-system \
--set prometheus.enabled=true \
--set grafana.enabled=true \
--set kiali.enabled=true \
--set tracing.enabled=true

kubectl apply --namespace istio-system \
-f ./resources/secrets/kiali.yaml

如下图,我们可以看到与Istio相关联的负载已经运行在集群中,包含了可观测性工具集。
8.png

同样,我们能看到集群中相应的Istio相关的Service资源。
9.png

# 修改DNS记录
我们将使用DNS,而非使用IP地址来路由GKE集群及其应用程序的流量。如上所述,我使用了example-api.com这个域名和四个子域。一个子域用于devtest命名空间的Angular UI服务,其他被用于API调用的边缘微服务A。流量基于URL路由到特定的Kubernetes Service资源。

部署GKE集群和Istio会触发创建一个Google Load Balancer,四个IP地址和所有必要的防火墙规则。与转发规则相关联的四个IP地址之一(如下所示)将与负载均衡器的前端相关联。
10.png

如下所示,我们能看到一个新的负载均衡器,包含了前端IP地址和三个GKE集群工作节点的后端VM池。每个节点都被分配了一个IP地址。
11.png

接着我使用了Google Cloud DNS创建了四个子域并将所有子域与负载均衡器前端的IP绑定。到这些地址的入口流量将通过Istio ingress Gateway和四个Istio VirtualService然后路由到适当的Kubernetes Service资源去。使用你选定的DNS管理工具来创建四个A类型的DNS记录。
12.png

# 部署整个参考平台
接下来,将八个基于Go的微服务,Angular UI以及相关的Kubernetes和Istio资源部署到GKE集群。请使用脚本part5a_deploy_resources.sh来部署平台。如果任何操作失败并且在不破坏GKE集群或Istio的情况下,你想要删除现有资源并重新部署,则可以使用part5b_delete_resources.sh删除脚本。
14.png

部署脚本将所有资源部署到两个Kubernetes命名空间,分别是devtest。这将使我们能够在使用可观测性工具时区分不同的命名空间。

下图展示刚刚部署的与Istio相关的资源,它们包括Istio Gateway,四个Istio VirtualService和两个Istio ServiceEntry资源。
15.png

接着是在集群上运行此平台的工作负载(Kubernetes Deployment资源)。在这我们可以看到每个工作负载有两个Pod,共有18个Pod,在dev命名空间中运行。每个Pod都包含已部署的微服务或UI组件,以及Istio的Envoy Proxy的副本。
16.png

下图我们看到dev命名空间中创建了对应的Kubernetes Service资源。
17.png

下图test命令空间中的资源与dev命名空间的类似。
18.png

# 测试该平台
我们想确保平台中的八个基于Go的微服务和Angular UI都能正常工作,相互通信,并与外部的MongoDB Atlas和CloudAMQP RabbitMQ集群进行通信。最简单的方式就是直接在浏览器查看Augular UI。
19.png

UI界面要求你输入服务A的主机名,即API的边缘服务。由于你无法使用我的子域,并且JavaScript代码是在你的Web浏览器本地运行,因此该选项允许你提供自己的主机域。这与你在VirtualService中为UI配置的域名相同。此域名将API调用路由到dev命名空间中运行的Service A服务的FQDN service-a.dev.svc.cluster.local,或test命名空间service-a.test.svc.cluster.local
20.png

你还可以使用性能测试工具对平台进行负载测试。很多问题在平台出现负载前都很难发现。最近我开始使用`hey`,一个现代化的负载生成工具,作为Apache Bench的替代品,它不像ab,hey支持HTTP/2端点,这是测试运行在包含了Istio组件的GKE集群上的平台工作所必需的。下面我直接在Google Cloud Shell使用`hey`工具,将模拟25个并发用户,为服务A生成总共1000个基于HTTP/2的GET请求。
21.png

# 故障排除
如果由于某些原因导致UI无法显示或者是从UI发起的调用请求失败,并且假设所有Kubernetes和Istio资源都运行在GKE集群上,则最常见的解释通常就是以下的资源存在错误配置:

  1. 四个DNS记录中存在错误,它们不是解析到负载均衡器的前端IP地址上
  2. 没有为四个Istio的VirtualService资源配置正确的子域名
  3. 基于Go的微服务无法访问外部MongoDB Atlas和CloudAMQP RabbiqMQ集群。可能是Kuberetes Secret资源结构不对或者是两个ServiceEntry中包含了那些到外部集群的错误的主机信息

我建议通过使用cURL或Postman工具直接调用服务A(API的边缘服务)来开始排障。如果你能看到类似下图的JSON格式的响应,那则表明问题在于UI而非API。
22.png

接下来,确认为服务D、F、G和H创建了四个MongoDB数据库。另外确保新文档被正确写入数据库。
23.png

另外使用CloudAMQP RabbitMQ管理控制台确认已创建新的RabbitMQ队列。服务D产生信息,服务F从队列中取出并消费。
24.png

最后查看Stackdriver日志以查看是否存在任何明显错误。
25.png

# 未完待续
在此系列的第二部分中,我们将详细探索每个可观测性工具,并了解它们如何帮助我们管理GKE集群以及运行在上面的相关平台。
26.png

由于集群只需几分钟即可完成创建和部署资源,如果需要清除集群请运行part6_tear_down.sh脚本。
27.png

以上所有仅代表我个人观点,与现任、前任雇主和客户无关。

原文链接:Kubernetes-based Microservice Observability with Istio Service Mesh: Part 1(翻译:冯旭松)

生产环境里的Istio和Kubernetes(二):Tracing

崔婧雯 发表了文章 • 0 个评论 • 695 次浏览 • 2019-03-25 23:27 • 来自相关话题

在上一篇博文里,我们介绍了Service Mesh(服务网格)Istio的组成部分,并回答了Istio新手经常会问的问题。本文会研究如何整理这些在网络上收集到的tracing信息。 在听到Service Mesh这个新概念的时候,开发 ...查看全部
在上一篇博文里,我们介绍了Service Mesh(服务网格)Istio的组成部分,并回答了Istio新手经常会问的问题。本文会研究如何整理这些在网络上收集到的tracing信息。

在听到Service Mesh这个新概念的时候,开发人员和系统管理员首先考虑的事情是tracing。我们会为每个微服务添加特定的代理服务器来处理所有TCP流量。你可能会自然地认为很容易收集所有网络事件的信息。但不幸的是,实际需要考虑很多细节。让我们一起研究一下。
#一大误解是可以轻松得到网络流量上的网络交互数据
实际上,相对容易的仅仅是得到由箭头连接的系统节点图,以及服务间的数据速率(实际上,仅仅是单位时间内的比特数)。但是,绝大多数情况下,服务通过应用层协议来通信,比如HTTP,gRPC,Redis等。当然,我们想看到这些协议的tracing信息,想看到应用级别请求的速率,而不是单纯的数据速率。另外,我们想知道协议的请求延时。最终,则想看到从用户输入触发的请求到收到回复这之间的全路径。不过这可不是一件容易的事情。

首先,从Istio的架构角度看怎么发送tracing信息。上文提到,Istio有一个特定的组件收集Telemetry,称为Mixer。但是,在当前的1.1.*的版本里,代理服务器,也就是Envoy代理,直接发送tracing span。Envoy代理支持使用Zipkin协议发送tracing span。其他协议则要求单独的插件。Istio自带预编译并且预先配置好的Envoy代理,仅支持Zipkin协议。比如,如果用户想使用Jaeger协议并通过UDP发送tracing span,那么他需要构建自定义的istio-proxy镜像。Istio-proxy的确支持自定义插件,但是,还仅仅有alpha版本。因此,如果想避免多个自定义的设置,那么接受并存储tracing span的方案里并没有太多的选择。可以使用最受欢迎的协议,Zipkin或者Jaeger,但是如果使用后者,所有东西都需要使用Zipkin兼容的协议(性能会差一些)来上传。Zipkin协议通过HTTP协议将所有tracing信息发送给收集器,消耗更大。

如上文所说,我们需要跟踪应用层协议。这意味着每个服务旁的代理服务器必须理解当时发生的网络事件。Istio默认所有端口使用plain TCP,这意味着不会发送trace。要发送trace,首先需要在main mesh config里启用相关的配置,然后依据服务内协议的实现来命名所有Kubernetes服务实体的所有端口。比如:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: nginx

还可以使用组合名称,比如http-magic(Istio能够识别http并且将端口识别为http端口)。

为了避免修补多个配置来定义协议,有如下workaround:在Pilot组件执行协议决策逻辑的时候修改它的配置。然后,当然需要切回标准逻辑并且切换所有端口的命名惯例。

为了理解协议是否定义正确,可以从Envoy代理进入任意Sidecar容器,从location/config_dump发送请求给Envoy接口的admin端口。在最终的配置里,检查相应服务的Operation字段。在Istio里,它就相当于请求目的地的标识。在Istio里自定义这个参数(之后可以在tracing系统里看到),启动Sidecar容器的时候设置serviceCluster标记。比如,它可以从Kubernetes API得到的变量里计算出来:
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's/-[a-z0-9][i]-[a-z0-9][/i]$//g')


这里很好地解释了Envoy的trace是如何工作的。

在Envoy代理的启动标记里必须指定发送tracing span的端口,比如:`—-zipkinAddress tracing-collector.tracing:9411`。
#另一个误解是用户可以轻松获取系统内请求的所有trace
不幸的是事实并非如此。实现的复杂度取决于服务是如何交互的。为什么是这样呢?

问题在于要让Istio代理理解服务的入站和出站请求的匹配关系,仅仅截获所有流量是不够的。你需要某种匹配标识符。HTTP Envoy代理使用特别的header,这样Envoy能够准确理解服务的哪个请求生成对其他服务的特定请求。这些header包括:

- x-request-id
- x-b3-spanid
- x-b3-parentspanid
- x-b3-sampled
- x-b3-flags
- x-ot-span-context

如果你只有一个单点,比如,一个基础的客户端,这里可以加入逻辑,然后需要做的就是等待library在所有客户端里更新完毕。但是如果你面对的是一个复杂的异构系统,没有统一的服务-服务的网络流量,那么很可能就会有问题。不加这样的逻辑,所有的tracing信息都是单层级的。你可以得到所有服务-服务的交互,但是却无法形成网络流量链。
#结论
Istio提供了方便的工具收集网络上的所有tracing信息,但是它的实现要求系统的变更,要考虑到Istio的实现的独特性。这是要解决的两大问题:定义应用层的协议(Envoy代理必须支持)以及设置转发信息,匹配入站和出站请求(如果是HTTP协议的话,使用header)。如果这两大问题都解决了,那么你就有了强大的工具,可以从网络上透明地收集信息,即使这是个高度异构的系统,可能由多种语言使用多种架构组成。

下一篇博文里,我们会讨论Istio最大的挑战之一——每个Sidecar代理容器所带来的高RAM使用率的问题——并且讨论如何解决这个问题。

原文链接:Istio and Kubernetes in production. Part 2. Tracing(翻译:崔婧雯)
===========================
译者介绍
崔婧雯,现就职于IBM,高级软件工程师,负责IBM WebSphere业务流程管理软件的系统测试工作。曾就职于VMware从事桌面虚拟化产品的质量保证工作。对虚拟化,中间件技术,业务流程管理有浓厚的兴趣。

Istio 1.1正式发布!

大卫 发表了文章 • 0 个评论 • 548 次浏览 • 2019-03-20 08:29 • 来自相关话题

自从去年7月发布1.0版本以来,我们已经进行了大量工作以帮助用户将Istio引入生产环境。在此期间,我们也一直在推出更多后续补丁以完善相关功能(先后发布了6个补丁),同时致力于进一步丰富Istio的功能要素。 Istio 1.1版本的 ...查看全部
自从去年7月发布1.0版本以来,我们已经进行了大量工作以帮助用户将Istio引入生产环境。在此期间,我们也一直在推出更多后续补丁以完善相关功能(先后发布了6个补丁),同时致力于进一步丰富Istio的功能要素。

Istio 1.1版本的主题在于企业就绪。我们也很高兴看到正有越来越多的企业在生产环境中使用Istio。不过随着部分大型公司对Istio的尝试,项目中的一些局限开始暴露了出来。

在新版本中,我们关注的主要方向之一正是性能与可扩展性。随着人们将Istio投入生产,包括匹配规模更大的集群以更高容量运行更多服务,项目的扩展与性能问题亦暴露无遗。sidecar占用了太多资源并显著提升了延迟水平,此外控制平面(特别是Pilot)亦存在过度耗费资源的问题。

我们投入了大量精力以提升数据平面与控制平面的执行效率。在我们的1.1版本性能测试当中,如今sidecar在处理1000 rps时仅需要半个vCPU的资源来支撑。另外,单一Pilot实例已经能够在配合1.5个vCPU与2 GB RAM的前提下顺利处理1000项服务(以及总计2000个Pod)。sidecar在半数情况下仅增加5 ms延迟,在99%的情况下增加10 ms延迟(强制执行策略将提高延迟水平)。

我们还完成了命名空间的隔离工作。这意味着大家可以使用Kubernetes命名空间对边界进行强制控制,进而确保您的各个团队之间不致相互干扰。

我们也改进了多集群的功能性与可用性。我们认真听取了来自社区的意见,并改进了流量控制与策略的默认设置。我们引入一款名为Galley的新组件。Galley负责验证YAML以降低发生配置错误的可能性。另外,Galley还能够在多集群设置当中发挥作用,从各个Kubernetes集群当中收集服务发现信息。再有,我们还支持其它多集群拓扑结构,包括在无需扁平网络的前提下实现单一控制平面与多个同步控制平面。

除此之外,新版本还带来更多新的特性与提升,具体细节请参阅我们的发布说明

Istio项目的提升远不止于此。相信大家都了解,Istio当中包含众多活动组件,因此实际使用也存在不少门槛。为了解决这个问题,我们最近组织了Usability Working Group(欢迎大家随时加入)。我们也有计划通过社区会议(本四周上午11点)与Working Group持续发布更多指导信息。如果您还没有加入discuss.istio.io会话,我们建议您尽快参与进来——只需要使用GitHub凭证即可登录,欢迎各位莅临指导!

我们感谢过去几个月当中,各位在支持Istio项目时付出的不懈努力,包括对1.0版本的完善以及对1.1项目的贡献,特别是新版本的功能增加与测试。与此同时,我们也要诚挚感谢那些与我们能力合作,安装并升级早期版本以帮助我们在发布前找寻问题的企业与个人用户。

总而言之,现在就是最好的时机!1.1版本已经正式来临,欢迎大家参阅更新文档并实际安装……预祝大家在服务网格的道路上勇猛精进!

原文链接:Announcing Istio 1.1

为什么 Service Meshes,容器编排工具是云原生部署的必然选择?

samzhang 发表了文章 • 0 个评论 • 551 次浏览 • 2019-03-11 09:31 • 来自相关话题

【编者的话】Service Mesh 通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。随着规模和复杂性的增长,服务网格越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、指标收集和监控以及通常更加复杂的运维需求,例如 A/B 测试、金丝 ...查看全部
【编者的话】Service Mesh 通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。随着规模和复杂性的增长,服务网格越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、指标收集和监控以及通常更加复杂的运维需求,例如 A/B 测试、金丝雀发布、限流、访问控制和端到端认证等。Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,而不需要对服务的代码做任何改动。

独立,短暂的微服务过程带来了一些重大好处,但是保持跟踪每一个单独的微服务是一个挑战,特别是尝试去弄清楚当一个微服务下线后,剩下的服务会受到什么样的影响。最终的结果是,如果你正在一个微服务架构下运营或开发,那么你的一部分时间将会被消耗在搞清楚你的服务到底是什么上。

随着微服务的采用,大型系统中存在大量服务,因此出现问题不可避免。诸如,安全,负载均衡,监控和限速这些问题,过去不得不同意解决,而现在,不得不单独为每个服务一一解决。

幸好工程师乐于这样的挑战。而且每当微服务产生新的问题时,他们都会通过新兴的微服务工具和技术来定位这些问题。也许微服务的出现只是工程师确保饭碗的智能游戏。

如今Cloud Native的宠儿Kubernetes,缓解了微服务带来的许多挑战。自动调度,横向扩展和服务发现,解决了大多在微服务中构建和部署服务将遇到的问题。

Kubernetes 留下了一些尚未解决的容器化应用环境的问题。这就是 Service Mesh 的介入点。让我们看一下 Kubernetes 提供了什么,和 Istio 如何增强 Kubernetes 解决微服务运行环境的问题。
#Kubernetes 解决了构建和部署的挑战
容器编排工具,诸如 Kubernetes,解决了许多来自于容器化应用的构建和部署的挑战。

Kubernetes 支持微服务架构,使开发者能够抽象出一组 Pod 的功能,并且通过明确的 API 来曝露服务给其他开发者。Kubernetes 支持四层负载均衡,但是不能解决更高层的问题,例如,七层指标、流量分流、限速和断路。
#Service Mesh 解决了运行时管理流量的挑战
Service Mesh 有助于解决最终用户使用应用程序时出现的许多挑战。能够监控哪些服务相互通信,他们的通信是否安全和是否能够控制你的集群中服务和服务间的通信,这是确保你的应用安全和弹性运行的关键。

通过在整个过程中生成统一的度量标准,Istio 可以在微服务架构中提供一致的视图。它消除了协调各种运行时代理发出的不同类型的度量标准的需要,或添加任意代理来收集旧的未检测应用程序的度量标准。它在您的多语言服务和集群中增加了一定程度的可观察性,这在任何其他工具的细粒度水平上是无法实现的。

Istio 还增加了更深层次的安全性。Kubernetes 仅提供基本的秘密分发和控制平面证书管理,但是 Istio 提供 mTLS 功能,因此您可以对线路流量进行加密,以确保您的服务间通信是安全的。
#完美的匹配
将 Kubernetes 与 Istio 配对可以为您提供两全其美的优势,而且由于 Istio 是在 Kubernetes 上运行的,因此两者可以无缝协作。您可以使用 Kubernetes 来管理所有构建和部署需求,Istio 负责处理重要的运行时问题。

Kubernetes 已经成熟到大多数企业都将其用于集装箱编排。目前,有 74 家 CNCF 认证的服务提供商,这证明了市场规模庞大且不断增长。我认为 Istio 是 Kubernetes 的延伸,为了解决更多挑战。

Istio 已经快速成熟,并开始在企业中更多地采用。可能在 2019 年,我们将看到 Istio 成为企业的服务网格标准,就像 Kubernetes 作为集装箱编排的标准一样。

原文链接:Why Service Meshes, Orchestrators Are Do or Die for Cloud Native Deployments(翻译:Sam)

在生产环境运行Istio(一)

崔婧雯 发表了文章 • 0 个评论 • 1152 次浏览 • 2019-03-10 10:44 • 来自相关话题

Istio是什么?Istio是服务网格技术,在网络上添加一层抽象层。它截获Kubernetes集群里的所有或者部分流量,并在之上执行一系列操作。支持哪些操作呢?比如,搭建智能路由或实现断路器方案,进行“金丝雀部署”等。另外,Istio还可以限制外部交互并且控制 ...查看全部
Istio是什么?Istio是服务网格技术,在网络上添加一层抽象层。它截获Kubernetes集群里的所有或者部分流量,并在之上执行一系列操作。支持哪些操作呢?比如,搭建智能路由或实现断路器方案,进行“金丝雀部署”等。另外,Istio还可以限制外部交互并且控制集群和外部网络的所有路由。而且,Istio支持配置策略规则来控制不同微服务之间的交互。最终,我们可以生成完整的网络交互图,并且得到对于应用来说完全透明的指标集。

官方文档里有Istio的详细介绍。本文介绍Istio上微服务交互背后的基本原理,展示Istio的确是解决各种问题的相当强大的工具。本文尝试回答Istio初学者经常会问的各种问题,帮助大家更有效率地使用Istio。

在介绍安装之前,先介绍一些核心观点,总体看一下Istio的组件和组件间交互的原理。
#工作原理
Istio由两大组件组成——控制面板和数据面板。控制面板包含基础组件,确保和其他组件之间的正确交互。在当前的1.0版本里,控制面板有三个组件:Pilot,Mixer和Citadel。这里不讨论Citadel,因为在生成证书来进行服务间的双向TLS通信时才需要它。我们先了解一下Pilot和Mixer的设计和目标。
review.png

Pilot是主要的控制组件,它负责分发集群内的所有信息——服务,它们的端点以及路由规则(比如,金丝雀发布规则或者断流器规则)。

Mixer是可选的控制面板组件,它负责收集指标、日志以及其他网络交互的信息。它还监控是否符合策略规则以及是否符合速率限制。

数据面板的组件使用sidecar代理容器来实现。默认使用强大的代理服务器Envoy。为了确保Istio对于应用来说是彻底透明的,这里使用了自动注入系统。最新的实现支持Kubernetes 1.9或更新版本(mutational admission webhook)。对于Kubernetes 1.7,1.8版本,可以是用Initializer。

Sidecar容器通过GRPC协议连接Pilot,优化集群内变更的pushdown模型。Envoy从1.6版本就开始使用GRPC;Istio则从0.8版本开始使用,它是pilot-agent——Envoy之上GO的封装,用来配置启动参数。

Pilot和Mixer是纯粹的无状态组件,所有的状态都保存在应用程序的内存里。它们的配置由Kubernetes的Custom Resource定义,存储在etcd里。Istio-agent得到Pilot的地址,并打开GRPC连接。

正如我所说,Istio在对应用完全透明的前提下实现了所有功能。让我们一起看看是怎么实现的。算法原理如下:

1. 我们部署服务的一个新版本。
2. 取决于sidecar容器的注入类型,在配置阶段添加istio-init容器和istio-agent容器(Envoy),或者手动插入到Kubernetes实体的Pod描述里。
3. istio-init容器是一些脚本,为Pod设置iptables规则。有两种方式配置流量重定向到istio-agent容器里:使用直接的iptables规则或者TPROXY。撰写本文时,默认使用的是重定向规则。在istio-init里,可以配置截获哪些流量并发送给istio-agent。比如,为了截获所有入站和出站流量,用户需要将参数`-i`和`-b`设置为`*`。用户也可以指定截获特定端口的流量。为了避免截获特定子网的流量,可以使用`-x`参数。
4. 在init运行后,会启动容器,包括pilot-agent(Envoy)。它通过GRPC连接上已经部署的Pilot,得到集群内所有已有服务以及路由策略的信息。根据接收到的数据,它配置集群,将这些流量直接映射到Kubernetes集群里的应用程序端口。重要的地方是:Envoy动态配置监听器(IP,端口对)开始监听。因此,当请求进入Pod,并且使用iptables规则重定向到sidecar时,Envoy已经准备好处理这些连接,并且知道将这些代理流量转发到哪里去。这一步里,信息发送给Mixer,下文会详细介绍。

最终,我们得到Envoy代理服务器的所有网络,可以从一点(Pilot)完成配置。最终,所有inbound和outbound请求都会通过Envoy。更为重要的是,只截获TCP流量。这意味着仍旧是使用UDP上的kube-dns来解析Kubernetes服务IP,这点没有变化。然后,在resolver之后,outbound请求被envoy截获并处理,它决定请求发送到哪个端点(或者不发送,当访问策略禁止或者触发了断流算法时)。

现在我们已经熟悉了Pilot,接下来研究Mixer是怎么工作的,以及为什么我们需要Mixer。Mixer的官方文档在这里

Mixer有两个组件:istio-telemetry,isito-policy(0.8版本之前使用单个组件istio-mixer)。它们都是Mixer。Istio telemetry接收sidecar容器的GPRC,并且汇报服务交互和参数信息。Istio-policy接收到检查请求,确保满足Policy规则。这些策略检查在客户端(sidecar里)缓存一段时间。报告检查是批量发送的。这里介绍怎么配置以及需要设置哪些参数。

Mixer应该是高可用组件,提供telemetry数据的不间断收集和处理。整个系统是一个多层缓存器。最初,数据缓存在容器的sidecar里,然后在Mixer,最终发送到Mixer后台。因此,如果任意系统组件发生故障,buffer会增长,之后当系统恢复时,会flush。Mixer后台是发送telemetry数据的端点:statsd,newrelic等等。编写自定义后台很简单,之后我会给大家介绍。
mixer.png

总结一下,使用istio-telemetry的工作流如下:

1. 服务1发送请求给服务2
2. 在已有的服务1里,请求重定向到sidecar
3. Sidecar Envoy监控到给服务2的请求,并准备所需信息
4. 然后它使用Report请求发送给istio-telemetry。
5. Istio-telemetry决定是否将Report发送给后台,这里也负责发送请求以及请求内容。

现在看看如何搭建包含两大基础组件Pilot和sidecar envoy的Istio系统。如下是Pilot读取的基础配置(Mesh):
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
labels:
app: istio
service: istio
data:
mesh: |-
# disable tracing mechanism for now
enableTracing: false
# do not specify mixer endpoints, so that sidecar containers do not send the information
#mixerCheckServer: istio-policy.istio-system:15004
#mixerReportServer: istio-telemetry.istio-system:15004
# interval for envoy to check Pilot
rdsRefreshDelay: 5s
# default config for envoy sidecar
defaultConfig:
# like rdsRefreshDelay
discoveryRefreshDelay: 5s
# path to envoy executable
configPath: "/etc/istio/proxy"
binaryPath: "/usr/local/bin/envoy"
# default name for sidecar container
serviceCluster: istio-proxy
# time for envoy to wait before it shuts down all existing connections
drainDuration: 45s
parentShutdownDuration: 1m0s
# by default, REDIRECT rule for iptables is used. TPROXY can be used as well.
#interceptionMode: REDIRECT
# port for sidecar container admin panel
proxyAdminPort: 15000
# address for sending traces using zipkin protocol (not used as turned off in enableTracing option)
zipkinAddress: tracing-collector.tracing:9411
# statsd address for envoy containers metrics
# statsdUdpAddress: aggregator:8126
# turn off Mutual TLS
controlPlaneAuthPolicy: NONE
# istio-pilot listen port to report service discovery information to sidecars
discoveryAddress: istio-pilot.istio-system:15007

让我们将所有主要控制组件(控制面板)放到Kubernetes的istio-system命名空间里。

最小的配置仅仅要求Pilot的部署。我们使用如下配置。并且手动配置sidecar容器的注入。

Init容器配置:
initContainers:
- name: istio-init
args:
- -p
- "15001"
- -u
- "1337"
- -m
- REDIRECT
- -i
- '*'
- -b
- '*'
- -d
- ""
image: istio/proxy_init:1.0.0
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 128Mi
securityContext:
capabilities:
add:
- NET_ADMIN

sidecar配置:
       - name: istio-proxy
command:
- "bash"
- "-c"
- |
exec /usr/local/bin/pilot-agent proxy sidecar \
--configPath \
/etc/istio/proxy \
--binaryPath \
/usr/local/bin/envoy \
--serviceCluster \
service-name \
--drainDuration \
45s \
--parentShutdownDuration \
1m0s \
--discoveryAddress \
istio-pilot.istio-system:15007 \
--discoveryRefreshDelay \
1s \
--connectTimeout \
10s \
--proxyAdminPort \
"15000" \
--controlPlaneAuthPolicy \
NONE
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: ISTIO_META_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: ISTIO_META_INTERCEPTION_MODE
value: REDIRECT
image: istio/proxyv2:1.0.0
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 2048Mi
securityContext:
privileged: false
readOnlyRootFilesystem: true
runAsUser: 1337
volumeMounts:
- mountPath: /etc/istio/proxy
name: istio-envoy

为了成功部署,需要为Pilot创建ServiceAccount,ClusterRole,ClusterRoleBinding,CRD;更多详细信息在这里。之后,带有注入的sidecar和Envoy的服务就启动了,会从Pilot获取所有数据并且处理请求。

最重要的一点是所有控制面板组件都是无状态的应用程序,都可以轻松地水平扩展。所有数据都以Kubernetes资源的自定义描述存储在etcd里。

此外,也可以在集群外运行Istio(实验用途),并且在几个Kubernetes集群之间监控并共享服务发现。更多的相关信息在这里。在多集群安装里,要考虑到如下限制:

1. CIDR Pod和Service CIDR必须在所有集群里都是唯一的,不能重叠。
2. 集群间的任意Pod CIDR必须能够访问所有CIDR Pod。
3. 所有Kubernetes API server都必须能够相互访问。

本文让你开始了解Istio。但是,后续文章会接着讨论现有的问题。我们会讨论外部流量路由的特性,探讨最常见的sidecar debug和Profile的方法。最终,我们会创建跟踪系统并且仔细介绍它和Envoy是如何交互的。

原文链接:Running Istio on kubernetes in production. Part I.(翻译:崔婧雯 )
===========================
译者介绍
崔婧雯,现就职于IBM,高级软件工程师,负责IBM WebSphere业务流程管理软件的系统测试工作。曾就职于VMware从事桌面虚拟化产品的质量保证工作。对虚拟化,中间件技术,业务流程管理有浓厚的兴趣。

2019年三大Service Mesh发展动向解析

Andy_Lee 发表了文章 • 0 个评论 • 2278 次浏览 • 2019-02-08 19:15 • 来自相关话题

【编者的话】过去的一年,可以说是关于Service Mesh评估、试验乃至炒作的一年。 虽然Service Mesh作为一种新兴的技术模式引发了人们的广泛关注,但对其的重视仍然主要停留在评估阶段,而尚未触及真正的广泛采用。具备实际功能 ...查看全部
【编者的话】过去的一年,可以说是关于Service Mesh评估、试验乃至炒作的一年。

虽然Service Mesh作为一种新兴的技术模式引发了人们的广泛关注,但对其的重视仍然主要停留在评估阶段,而尚未触及真正的广泛采用。具备实际功能的Service Mesh在普及之后,将有望在运行时帮助运营人员更轻松地管理基于微服务架构的应用程序。然而,在全面步入生产采用之前,这项技术仍然需要逐步发展成熟。

但好消息是,根据我们的预测,今年之内Service Mesh将有望从炒作阶段过渡至真正的应用层面。

那么,关于Service Mesh我们能够在2019年看到怎样的发展趋势?

1. Service Mesh将作为一种技术模式迎来演进与合并;
2. Istio的发展将逐步帮助企业选择切实可行的服务网络实现方式;
3. 明确的用例将为后续的广泛采用指明前进道路。

#Service Mesh的演进之旅
Service Mesh的架构化选项层面已经存在多种可行的解决方案,但毫无疑问,边车架构将在2019年之内得到最为广泛的应用。在这种场景下,边车代理将作为架构模式存在。更具体地讲,作为核心技术方案,Envoy已经成为大多数人实现Service Mesh的首选技术方法。

着眼于控制平面Service Mesh,我们已经看到边车代理领域呈现出合并的趋势。Linkerd与Conduit的合并催生出Linkerd 2的发布,这也成为边车大军中的又一股新生力量。而作为边车控制平面网格领域的元老,Istio在云原生领域内仍然拥有着最为强劲的生命力。下面一起来看Istio GitHub repo的当前状态:

* 14500颗星评;
* 6400次提交;
* 300位贡献者。

如果这些数字还不能明确的展示这一项目的旺盛生命力,那么接下来我们再看看围绕Istio项目参与Service Mesh推动的知名企业:

* Aspen Mesh;
* Avi Networks;
* 思科;
* OpenShift;
* NGINX;
* Rancher;
* Tufin Orca;
* Tigera;
* Twistlock;
* VMware。

#Istio的演进之旅
接下来的最大问题在于,Istio项目将在2019年迎来怎样的发展方向?这里我先要提一句免责声明,接下来的结论纯属个人猜测。虽然与之相关的素材都来自知情人士,但猜测就是猜测,仅供大家参考。
##社区成长
现在,Istio项目已经迎来了1.0版本,而除核心谷歌与IBM团队之外的外部贡献者数量也开始快速增长。我猜想,Istio项目将在今年6月或者7月左右迎来稳定的1.3版本。而一旦达到这一发展阶段,其即可在生产环境当中大规模使用,这也将成为其真正起飞的历史性节点。
##新兴供应商持续涌现
在Aspen Mesh公司,我们从18个月前开始将Istio项目视为Service Mesh中最重要的技术成果。在接下来的一年中,事态也逐渐趋于明朗——Istio将在Service Mesh领域赢下头把交椅,正如Kubernetes已经在容器编排层面夺得桂冠一样。

Istio项目是一套功能强大的工具箱,能够直接解决众多与微服务相关的实际挑战——在此之前,这些挑战只能通过繁琐的手动流程加以解决,其中一些甚至根本没有解决办法。此外,围绕Istio项目建立起的活跃开源社区也成为推动其普及的一大重要因素。更重要的是,这些良好趋势目前仍得到了保持甚至加强,因此以Istio为基础以及将Istio集成作为发展方向的企业在数量上必将不断增长。
##Istio项目将加入云原生计算基金会
在这里我要大胆做出猜测,甚至敢打赌在2019年年内,Istio项目将正式成为云原生计算基金会的一员。通过以往的经历来看,云原生计算基金会正是云原生开源项目最好的归宿与托管者。我认为这也将成为Istio项目得到广泛采用,进而获得长期成功当中至关重要的一步棋。虽然事态的最终发展仍然要由该项目的缔造者们决定,但可以肯定的是只要Istio项目正式加入这个大家庭,每一位相关者都将从中获得收益。
#真实用例将成为推动广泛采用的核心驱动力
Service Mesh目前仍然属于一个新兴市场,在未来的12到24个月内,我们认为相关扩张将大部分体现在市场早期采用者群体当中。但对于那些长期关注这一技术的朋友们来说,Service Mesh的存在理由已经拥有了比较明确的答案。虽然这一答案还将不断演变,但就目前而言,Service Mesh的立足依据已经不再是问题。在我看来,践行这一理由的过程也正在逐步落地,而且2019年之内将有更多真实用例共同支撑起Service Mesh的生存空间。

我认为,目前仍然困扰着Service Mesh的难题在于“如果将其引入实践流程,用户会看到怎样切实可靠的收益?”很明显,这是一个困扰着所有新兴技术的老问题,因此对于这个问题的答案探索过程同样有章可循:通过真实用例。没错,真实用例代表一切。只有真实用例,才能真正说服心怀疑虑的潜在用户。

Service Mesh是一款功能强大的工具箱,但只有一小部分受众会真正关注技术本身有多么酷炫先进。对于大多数人来讲,它能够解决什么问题才是最重要的关注点。

在我看来,2019年将成为Service Mesh用例爆发的一年。而且这一切将随着采用者数量的增加而水到渠成,用户们也将更热烈地相互讨论他们通过Service Mesh获得的实际价值。
#总结陈词
如果您已经在使用Service Mesh,您一定已经体会到它所带来的价值。如果您正在考虑使用Service Mesh,请密切关注这一领域发生的最新动态以及真实用例——这将让此项新兴技术的价值主张变得更为清晰可信。而如果您尚未想好是否应该投身Service Mesh的怀抱,我建议您参阅Gartner451以及IDC发布的微服务相关报告——一切调查结果都表明,对于一切已经开始在生产体系中运行微服务架构的组织而言,Service Mesh都将在2020年掀起一股不可扼止的洪流。

原文链接:Top 3 Service Mesh Developments in 2019

使用 Istio 实现基于 Kubernetes 的微服务应用

JetLee 发表了文章 • 0 个评论 • 1573 次浏览 • 2019-01-23 21:33 • 来自相关话题

【编者的话】近两年,随着容器、Kubernetes 等技术的兴起,微服务被广泛提及并被大量使用。本文旨在让读者了解 Istio,通过它与 Kubernetes 相结合,大幅降低微服务的复杂度,以便让开发人员更关注于代码本身。 #Istio 的架构分 ...查看全部
【编者的话】近两年,随着容器、Kubernetes 等技术的兴起,微服务被广泛提及并被大量使用。本文旨在让读者了解 Istio,通过它与 Kubernetes 相结合,大幅降低微服务的复杂度,以便让开发人员更关注于代码本身。
#Istio 的架构分析
##Istio 介绍
Istio 被称为 Service Mesh 架构,该开源项目由 Google 和 IBM 主导,根据 http://stackalytics.com 网站的统计,该社区代码 Commits 厂商排名如下:
image001.png

图 1. Istio 各厂商代码贡献量图示

image002.png

图 2. Istio 各厂商代码贡献量排名

在 GitHub 上,Istio 项目受关注的程度非常高,您可进一步了解。接下来,我们详细介绍 Istio 的技术架构。
##Istio 的架构
Istio 分为两个平面:数据平面和控制平面。

数据平面:

数据平面由一组 Sidecar 的代理(Envoy)组成。这些代理调解和控制微服务之间的所有网络通信,并且与控制平面的 Mixer 通讯,接受调度策略。

控制平面:

控制平面通过管理和配置 Envoy 来管理流量。此外,控制平面配置 Mixers 来实施路由策略并收集检测到的监控数据。
image003.png

图 3. Istio 的架构图

在介绍了 Istio 的两个平面以后,我们详细介绍 Istio 的各个组件。

Envoy 是一个用 C ++开发的高性能代理,用于管理 Service Mesh 中所有服务的所有入站和出站流量。 Istio 利用 Envoy 的许多内置功能,例如:

* 动态服务发现
* 负载均衡
* TLS 终止
* HTTP / 2 和 gRPC 代理
* 断路器
* 健康检查
* 流量分割
* 故障注入
* 监控指标

我们知道,在 Kubernetes 中集群中,Pod 是最小的计算资源调度单位。一个 pod 可以包含一个或者多个容器,但通常是一个。而使用 Istio 的时候,需要在 Pod 中主容器旁注入一个 Sidecar,也就是上面提到的代理(Envoy)。

举一个例子,我们查看一个被注入了 Envoy 的 Pod,从下图结果可以看到,这个 Pod 包含两个容器:
image004.png

图 4. 查看 Pod 中的 Container

在 Istio 中,每一个 Pod 中都必须要部署一个 Sidecar。

Mixer 是一个独立于平台的组件,负责在整个 Service Mesh 中执行访问控制和使用策略,并从 Envoy 代理和其他服务收集监控到的数据。

Pilot 为 Envoy 提供服务发现;为高级路由(例如,A / B 测试,金丝雀部署等)提供流量管理功能;以及异常控制,如:超时,重试,断路器等。

Citadel 通过内置身份和凭证管理,提供强大的服务到服务和最终用户身份验证。我们可以使用 Citadel 升级 Service Mesh 中的未加密流量。我们可以使用 Istio 的授权功能来控制谁可以访问服务。
##Istio 路由规则的实现
在 Istio 中,和路由相关的有四个概念:Virtual Services 、Destination Rules、ServiceEntry、Gateways。

Virtual Services 的作用是:定义了针对 Istio 中的一个微服务的请求的路由规则。Virtual Services 既可以将请求路由到一个应用的不同版本,也可以将请求路由到完全不同的应用。

在如下的示例配置中,发给微服务的请求,将会被路由到 Productpage,端口号为 9080。
route:
- destination:
host: productpage
port:
number: 9080

清单 1. Virtual Services 规则

在下面的示例配置中,定义了熔断策略。
spec:
host: productpage
subsets:
- labels:
version: v1
name: v1
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
tcp:
maxConnections: 1
tls:

清单 2. Destination 规则

ServiceEntry 用于将 Istio 外部的服务注册到 Istio 的内部服务注册表,以便 Istio 内部的服务可以访问这些外部的服务,如 Istio 外部的 Web API。

在如下的示例配置中,定义了 Istio 外部的 Mongo Cluster 与 Istio 内部的访问规则。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-svc-mongocluster
spec:
hosts:
- mymongodb.somedomain # not used
addresses:
- 192.192.192.192/24 # VIPs
ports:
- number: 27018
name: mongodb
protocol: MONGO
location: MESH_INTERNAL
resolution: STATIC
endpoints:
- address: 2.2.2.2
- address: 3.3.3.3

清单 3. ServiceEntry 规则

Gateway:定义了 Istio 边缘的负载均衡器。所谓边缘,就是 Istio 的入口和出口。这个负载均衡器用于接收传入或传出 Istio 的 HTTP / TCP 连接。在 Istio 中会有 Ingress Gateway 和 Egress Gateway,前者负责入口流量,后者负责出口流量。

在如下的示例配置中,定义了 Istio 的入口流量。
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP

清单 4. Gateway 规则
#Istio 的技术实现
##基于 Kubernetes 部署的 Istio
在本文中,我们基于 Kubernetes 1.11 部署 Istio 1.04。由于篇幅有限,具体的部署步骤可以参考 Quick Start with Kubernetes

查看 Kubernetes 版本:
image005.png

图 5. 查看 Kubernetes 集群的版本

查看 Kubernetes 集群:
image006.png

图 6. 查看 Kubernetes 集群的节点

查看部署好的 Istio。

Istio 以一个项目的形式部署到 Kubernetes 集群中。我们可以看到,部署好的 Pod 中,除了有 istio-citadel、istio-egressgateway、istio-ingressgateway、istio-pilot 等 Istio 本身的功能组件,还集成了微服务相关的监控工具,如:Grafana、jaeger-agent、Kiali、Prometheus。正是这些功能丰富且强大的监控工具,帮助 Istio 实现了微服务的可视化管理。
image007.png

图 7. 查看 Kubernetes 中的 Istio

查看 istio 版本:1.0.4:
image008.png

图 8. 查看 Istio 版本

接下来,我们将会对 Isito 集成的工具进行介绍。本文最后的实验展现环节,我们将会使用这些工具进行微服务的监控和管理。
##Istio 的工具集:Grafana
Grafana 是一个非常著名的开源项目。它是一个 Web 应用,可以提供丰富的监控仪表盘。它的后端支持 Graphite、 InfluxDB 或 OpenTSDB。

通过浏览器访问 Istio 中部署好的 Grafana。

登录 Grafana 后,首页面如下:
image009.png

图 9. Grafana 首页面

查看已有的 Dashboard:
image010.png

图 10. Grafana 上的 Istio Dashboard

我们查看 Pilot Dashboard,可以看到丰富的资源统计。
image011.png

图 11. Grafana 上的 Istio Dashboard 查看
##Istio 的工具集:Prometheus
Prometheus 是一个开源监控系统。它具有维度数据模型;具备灵活的查询语言、高效的时间序列数据库,并提供灵活的警报方法。

在 Istio 中,Prometheus 收到的数据,会被汇总到 Grafana 进行统一展现。

访问 Istio 中部署好的 Prometheus:
image012.png

图 12. Prometheus 的 UI

我们可以看到有多达上百个监测点:
image013.png

图 13. Prometheus 的监测点

例如我们选择 Container_memory_cache,点击 Execute。
image014.png

图 14. 执行监测点

然后可以生成图形化界面展示,并且我们也可以调整时间间隔(图中是 60 分钟)。
image015.png

图 15. 监控图
##Istio 的工具集:Kiali
Kiali 作为一个开源项目,可以为 Istio 提供可视化服务网格拓扑、断路器或请求率等功能。此外 Kiali 还包括 Jaeger Tracing,可以提供开箱即用的分布式跟踪功能。

我们看一下 Istio 中部署的 Kiali:
image016.png

图 16. Kiali 的 UI 首页

它可以查看在 Istio 上部署的微服务的拓扑结构:
image017.png

图 17. Kiali 查看微服务的拓扑
##Istio 的工具集:Jaeger
Jaeger 是一个开源项目,用于微服务的分布式跟踪。它实现的功能有:

* 分布式事务监控
* 服务调用问题根因分析
* 服务依赖性分析
* 性能/延迟优化

Jaeger 工具已经集成到 Istio 中,部署以后可以通过浏览器访问。

下图是 Jeager 追踪 Productpage 这个服务在过去三个小时的所有调用:
image018.png

图 18. Jaeger 查看 API 调用

我们可以展开看详细的调用层级:
image019.png

图 19. Jaeger 查看 API 详细调用
#Istio 管理微服务的实验展现
在本小节中,我们将在 Istio 上部署一个名为 bookinfo 的微服务应用。为了方便读者理解,我们先分析这个应用的源代码。然后展示 Istio 如何管理这套微服务。
##bookinfo 微服务源码分析
bookinfo 应用程序显示的有关书籍的信息,类似于在线书店的单个商品。应用页面上显示的是书籍的描述、书籍详细信息(ISBN,页数等)以及书评。

bookinfo 应用一共包含四个微服务:Productpage、Details、Reviews、Ratings。

* Productpage 使用 Python 开发,负责展示书籍的名称和书籍的简介。
* Details 使用 Ruby 开发,负责展示书籍的详细信息。
* Reviews 使用 Java 开发,负责显示书评。
* Ratings 使用 Node.js 开发,负责显示书籍的评星。

其拓扑关系见下图。
image020.png

图 20. bookinfo 应用拓扑架构

我们看一下 bookinfo 微服务部署完毕的展示效果:
image021.png

图 21. bookinfo 应用页面展示效果

Productpage 微服务包含两部分内容:

* 书籍的名称:"The Comedy of Errors",翻译成中文是《错误的喜剧》。
* 书籍的简介:Summary。翻译成中文是:《错误的喜剧》是威廉·莎士比亚早期剧作之一。这是他最短的、也是他最喜欢的喜剧之一,除了双关语和文字游戏之外,幽默的主要部分来自于打闹和错误的身份。

Details 微服务包含的内容是书籍的详细信息,内容如下。
Type:
paperback
Pages:
200
Publisher:
PublisherA
Language:
English
ISBN-10:
1234567890
ISBN-13:
123-1234567890

清单 5. Details 微服务显示内容

Reviews 微服务包含的信息是书评内容:
An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!
Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.

清单 6. 书评内容

Ratings 微服务包含的内容将展示为评星部分(下图黑框中的部分)。
image022.png

图 22. 评星图

接下来,我们访问 GitHub 上查看 bookinfo 源码,通过源码分析,理解业务的实现逻辑。

首先查看 Productpage 的源码(部分内容):
def getProducts():
return [
{
'id': 0,
'title': 'The Comedy of Errors',
'descriptionHtml': 'Wikipedia Summary: The Comedy of Errors is one of < b>William Shakespeare\'s< /b> early plays. It is his shortest and one of his most farcical comedies, with a major part of the humour coming from slapstick and mistaken identity, in addition to puns and word play.'
}

清单 7. Productpage 源码

我们可以很明显看出,以上代码就是 bookinfo 页面显示的书籍的名称和简介。

查看 Productpage 的另外一部分源码。
details = {
"name" : "http://details{0}:9080".format(servicesDomain),
"endpoint" : "details",
"children" : []
}


ratings = {
"name" : "http://ratings{0}:9080".format(servicesDomain),
"endpoint" : "ratings",
"children" : []
}


reviews = {
"name" : "http://reviews{0}:9080".format(servicesDomain),
"endpoint" : "reviews",
"children" : [ratings]
}


productpage = {
"name" : "http://details{0}:9080".format(servicesDomain),
"endpoint" : "details",
"children" : [details, reviews]
}


service_dict = {
"productpage" : productpage,
"details" : details,
"reviews" : reviews,
}

清单 8. Productpage 源码

上面代码定义了四个微服务的 name、endpoint、children。endpoint 代表这个微服务后端的 Kubernetes 集群中 service 名称、children 代表本微服务调用的 Kubernetes 集群中的微服务 service 名称。

以 Productpage 举例,它的 endpoint 是 details、children 是 details 和 reviews。所以,被发送到 Productpage 请求,将会调用 details、reviews 这两个服务。

接下来,查看 reviews 微服务的源码,代码使用 Java 编写的。
private String getJsonResponse (String productId, int starsReviewer1, int starsReviewer2) {
String result = "{";
result += "\"id\": \"" + productId + "\",";
result += "\"reviews\": [";

// reviewer 1:
result += "{";
result += " \"reviewer\": \"Reviewer1\",";
result += " \"text\": \"An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!\"";
if (ratings_enabled) {
if (starsReviewer1 != -1) {
result += ", \"rating\": {\"stars\": " + starsReviewer1 + ", \"color\": \"" + star_color + "\"}";
}
else {
result += ", \"rating\": {\"error\": \"Ratings service is currently unavailable\"}";
}
}
result += "},";

// reviewer 2:
result += "{";
result += " \"reviewer\": \"Reviewer2\",";
result += " \"text\": \"Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.\"";
if (ratings_enabled) {
if (starsReviewer2 != -1) {
result += ", \"rating\": {\"stars\": " + starsReviewer2 + ", \"color\": \"" + star_color + "\"}";
}
else {
result += ", \"rating\": {\"error\": \"Ratings service is currently unavailable\"}";
}
}
result += "}";

result += "]";
result += "}";

return result;
}

清单 9. reviews 服务源码

上面的这段代码,定义的是两个 Reviewer,以及书评的内容。书评的内容正是 bookinfo 页面展示的内容。

在上面的代码中,我们注意到有两个重要的变量 star_color 和 ratings_enabled。

* star_color 表示评星的颜色(黑色和红色)。
* ratings_enabled 表示是否启用评星。

查看 reviews 微服务的源码的另外一部分内容:
private final static String star_color = System.getenv("STAR_COLOR") == null ? "black" : System.getenv("STAR_COLOR");

清单 10. reviews 服务源码

上面代码显示:在应用构建时:

* 如果不指定 STAR_COLOR 变量且 ratings_enabled 为 true,那么评星默认为黑色。
* 如果指定 STAR_COLOR 变量且 ratings_enabled 为 true,那么评星颜色为传入的颜色。
* 如果不指定 ratings_enabled 为 true,那么将不会显示评星。

那么,STAR_COLOR 这个变量,在应用构建时,有没有传入呢?我们查看:build-services.sh
#java build the app.
docker run --rm -v "$(pwd)":/home/gradle/project -w /home/gradle/project gradle:4.8.1 gradle clean build
pushd reviews-wlpcfg
#plain build -- no ratings
docker build -t "istio/examples-bookinfo-reviews-v1:${VERSION}" -t istio/examples-bookinfo-reviews-v1:latest --build-arg service_version=v1 .
#with ratings black stars
docker build -t "istio/examples-bookinfo-reviews-v2:${VERSION}" -t istio/examples-bookinfo-reviews-v2:latest --build-arg service_version=v2 \
--build-arg enable_ratings=true .
#with ratings red stars
docker build -t "istio/examples-bookinfo-reviews-v3:${VERSION}" -t istio/examples-bookinfo-reviews-v3:latest --build-arg service_version=v3 \
--build-arg enable_ratings=true --build-arg star_color=red .

清单 11. build-services.sh 内容

上面代码显示,运行该脚本是,将会构建三个版本 Reviews 的 docker image:

* V1:没有评星(未指定 enable_ratings=true)。
* V2:评星为黑色(指定 enable_ratings=true;未指定 star_color 的变量,代码中默认的颜色为黑色)。
* V3:评星为红色(指定 enable_ratings=true;指定 star_color 的变量为 red)。

在 bookinfo 的源代码中,还有两个数据库的定义 Mongodb 和 MySQL。

接下来,我们看这个应用中两个数据库的内容。

先看 MongoDB 的 script.sh,内容如下:
#!/bin/sh
set -e
mongoimport --host localhost --db test --collection ratings --drop --file /app/data/ratings_data.json

清单 12. MongoDB 的 script.sh

也就是说,MongoDB 数据库在初始化时,会将 ratings_data.json 文件中的信息导入到数据库中。

再看 ratings_data.json:
{rating: 5}
{rating: 4}

清单 13. ratings_data.json 文件

也就是说,当应用部署完毕后,MongoDB 将包含五星和四星。

查看 MySQL 的初始化文件:mysqldb-init.sql。
# Initialize a mysql db with a 'test' db and be able test productpage with it.
# mysql -h 127.0.0.1 -ppassword < mysqldb-init.sql

CREATE DATABASE test;
USE test;

CREATE TABLE `ratings` (
`ReviewID` INT NOT NULL,
`Rating` INT,
PRIMARY KEY (`ReviewID`)
);
INSERT INTO ratings (ReviewID, Rating) VALUES (1, 5);
INSERT INTO ratings (ReviewID, Rating) VALUES (2, 4);

清单 14. mysqldb-init.sql 内容

我们可以看出,上面的初始化脚本是创建一个名为 Ratings 的数据库表,插入的数据效果如下:
B1.png

表 1. 数据库表示意

查看 Ratings 的源代码,该代码使用 Node.JS 书写。
* We default to using mongodb, if DB_TYPE is not set to mysql.
*/
if (process.env.SERVICE_VERSION === 'v2') {
if (process.env.DB_TYPE === 'mysql') {
var mysql = require('mysql')
var hostName = process.env.MYSQL_DB_HOST
var portNumber = process.env.MYSQL_DB_PORT
var username = process.env.MYSQL_DB_USER
var password = process.env.MYSQL_DB_PASSWORD
} else {
var MongoClient = require('mongodb').MongoClient
var url = process.env.MONGO_DB_URL
}
}

dispatcher.onGet(/^\/ratings\/[0-9]*/, function (req, res) {
var productIdStr = req.url.split('/').pop()
var productId = parseInt(productIdStr)

if (Number.isNaN(productId)) {
res.writeHead(400, {'Content-type': 'application/json'})
res.end(JSON.stringify({error: 'please provide numeric product ID'}))
} else if (process.env.SERVICE_VERSION === 'v2') {
var firstRating = 0
var secondRating = 0

if (process.env.DB_TYPE === 'mysql') {
var connection = mysql.createConnection({
host: hostName,
port: portNumber,
user: username,
password: password,
database: 'test'
})

connection.connect()
connection.query('SELECT Rating FROM ratings', function (err, results, fields) {
if (err) {
res.writeHead(500, {'Content-type': 'application/json'})
res.end(JSON.stringify({error: 'could not connect to ratings database'}))
} else {
if (results[0]) {
firstRating = results[0].Rating
}
if (results[1]) {
secondRating = results[1].Rating
}
var result = {
id: productId,
ratings: {
Reviewer1: firstRating,
Reviewer2: secondRating
}
}
res.writeHead(200, {'Content-type': 'application/json'})
res.end(JSON.stringify(result))
}
})

清单 15. Ratings 的源代码

以上代码主要实现:如果不指定 DB_TYPE 的变量,将默认使用 MongoDB 数据库。

当微服务 Reviews 的版本是 V2 时,将连接数据库 MySQL 或 MongoDB(根据环境变量传入的 DB_TYPE)。当 Reviews 的版本是 V3 时,访问 MongoDB 数据库。

但从上面的数据库分析我们可以知道,无论 Reviews 连接哪个数据库,得到的数据都是第一个评论者五星、第二个评论者四星。也就是说,只要是 Reviews 的 V2 和 V3 版本,访问数据库得到的评星结果是一样的;只不过 Reviews 为 V2 时评星为黑色、Reviews 为 V3 时评星为红色。
##微服务的部署
我们在 Kubernetes 集群中部署 bookinfo 应用。
image023.png

图 23. 在 Kubernetes 集群部署 bookinfo

Pod 创建成功:
image024.png

图 24. 查看 bookinfo 的 Pod

接下来,通过浏览器对 bookinfo 发起多次访问,页面呈现三种显示。

* 第一种:访问 bookinfo 时(Productpage 调用的 Review V1),页面没有评星;
* 第二种:访问 bookinfo 时(Productpage 调用的 Review V2),页面是黑色的评星;
* 第三种:访问 bookinfo 时(Productpage 调用的 Review V3),页面是红色的评星。

image025.png

图 25. bookinfo 第一种展现

image026.png

图 26. bookinfo 第二种展现

image027.png

图 27. bookinfo 第三种展现

过了几秒后:Kiali 收集到之前几次对 bookinfo 的访问流量,并进行动态展示。我们可以看到,Productpage 随机访问 Reviews V1、V2、V3。
image028.png

图 28. Kiali 展示微服务流量

Productpage 轮询访问 Review V1 和 V2 的原因是:我们没有设置针对 Reviews 的特定策略,而 Productpage 的源码中,指定了 Product 服务调用 Reviews 服务的业务逻辑,但并未指定版本。因此,Product 服务会随机访问 Reviews 的三个版本。
image029.png

图 29. 查看 virtualservice

接下来,我们查看 Virtualservice 的配置文件。
image030.png

30. 查看 Virtualservice 配置文件列表

查看 virtual-service-reviews-v3.yaml 内容。该文件定义发向 Reviews 的请求,全部到 V3 版本。
[root@master networking]# cat virtual-service-reviews-v3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v3 version: v3

清单 16. 查看 virtual-service-reviews-v3.yaml 内容

接下来,应用 Virtualservice 配置。
image031.png

图 31. 应用配置

查看生效的 Virtualservice,reviews 的配置生效。
image032.png

图 32. 查看生效的 Virtualservice

接下来,我们再次对 bookinfo 发起多次访问,可以看到,页面的评星均为红色。
image033.png

图 33. 访问 bookinfo 应用

通过 Kiali 查看流量,可以看到,Productpage 的流量全部访问 Review V3。
image034.png

图 34. Kiali 查看 bookinfo 应用访问流量

接下来,我们继续调整策略,让 Productpage 对 Reviews 的访问,以 V1 和 V2 按照 8:2 比率进行:
[root@master networking]# cat virtual-service-reviews-80-20.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 80
- destination:
host: reviews
subset: v2
weight: 20

清单 17. 查看 virtual-service-reviews-80-20.yaml 内容

image035.png

图 35. 替换之前的 Virtual Services 策略

image036.png

图 36. Kiali 查看 bookinfo 应用访问流量
##Istio 的限速
在了解了 Istio 微服务的路由策略后,接下来我们对微服务组件进行限速的设置。

在默认情况下,Productpage 随机访问 reviews 三个版本,没有流量限制。我们编写两个配置文件,限制 Productpage 到 reviews v3 的访问速度。

speedrule.yaml 限制了从 Productpage 到 reviews v3 的访问速度,最多每秒一个请求。
[root@master ~]# cat speedrule.yaml
apiVersion: "config.istio.io/v1alpha2"
kind: memquota
metadata:
name: handler
namespace: myproject
spec:
quotas:
- name: requestcount.quota.myproject
# default rate limit is 5000qps
maxAmount: 5000
validDuration: 1s
# The first matching override is applied.
# A requestcount instance is checked against override dimensions.
overrides:
- dimensions:
destination: reviews
source: productpage
destinationVersion: v3
maxAmount: 1
validDuration: 1s

recommendation_rate_limit_handler.yml 文件声明了 requestcount quota。

清单 18. 查看 speedrule.yaml

[root@master ~]# cat recommendation_rate_limit_handler.yml
apiVersion: "config.istio.io/v1alpha2"
kind: quota
metadata:
name: requestcount
namespace: myproject
spec:
dimensions:
source: source.labels["app"] | source.service | "unknown"
sourceVersion: source.labels["version"] | "unknown"
destination: destination.labels["app"] | destination.service | "unknown"
destinationVersion: destination.labels["version"] | "unknown"
---
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: quota
namespace: myproject
spec:
actions:
- handler: handler.memquota
instances:
- requestcount.quota
---
apiVersion: config.istio.io/v1alpha2
kind: QuotaSpec
metadata:
creationTimestamp: null
name: request-count
namespace: myproject
spec:
rules:
- quotas:
- charge: 1
quota: RequestCount
---
apiVersion: config.istio.io/v1alpha2
kind: QuotaSpecBinding
metadata:
creationTimestamp: null
name: request-count
namespace: myproject
spec:
quotaSpecs:
- name: request-count
namespace: myproject
services:
- name: productpage
namespace: myproject
- name: details
namespace: myproject
- name: reviews
namespace: myproject

清单 19. 查看 recommendation_rate_limit_handler.yml

应用两个配置:
image037.png

图 37. 应用配置

image038.png

图 38. 应用配置

然后,对 bookinfo 发起高频度请求,访问请求频率为 10 次/秒。
while true; do curl http://istio-ingressgateway-istio-system.apps.example.com/productpage; sleep .1; done

清单 20. 发起高频度访问请求

通过 Kiali,可以看到:
image039.png

图 39. Kiali 显示微服务流量

我们查看 Grafana,可以看到这段时间内,reviews v3 的流量,远低于同期 reviews v1 和 v2 的流量。
image040.png

图 40. Grafana 显示微服务流量统计
##Istio 的熔断
熔断技术,是为了避免"雪崩效应"的产生而出现的。我们都知道"雪球越滚越大"的现象。应用中的雪崩指的由于应用第一个组件的出现问题,造成调用这个组件的第二个组件有无无法调用第一个组件,无法实现业务逻辑,也出现问题;而调用第二个组件第三个组件因此也出现问题,问题迅速传播,从而造成整个应用的瘫痪,我们称之为应用的雪崩效应。

在单体应用中,多个业务的功能模块放在一个应用中,且由于各个功能模块之前是紧耦合,因此不容易出现雪崩情况。但由于微服务松耦合、各个组件调用关系复杂的特点,雪崩现象就较为容易出现。为了避免雪崩情况的发生,就需要有熔断机制,采用断路模式。熔断机制相当于为每个微服务前面加一个"保险丝"。当电流负载过大的时候(如服务访出现故障问超时,并且超过设定的重试次数),保险丝烧断,中断客户端对该应用的访问,而不影响客户端访问其他正常运行的组件。

Spring Cloud 中熔断的实现,需要调用 Hystrix。而 Istio 本身自带熔断的功能。下面,我们进行实现展现。

在初始情况下,未配置熔断。
image041.png

图 41. 配置熔断之前正常访问应用流量

接下来,我们在 Productpage 的 destination rule 中配置熔断策略(trafficPolicy):每个链接最多的请求数量是一个;最多 pending 的 request 是一个、最多的连接数是一个。
spec:
host: productpage
subsets:
- labels:
version: v1
name: v1
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
tcp:
maxConnections: 1
tls:
mode: ISTIO_MUTUAL

清单 21. 在 destination rule 中配置熔断(open.yaml 配置文件部分内容)

接下来,我们先删除旧的配置,应用熔断的配置。
image042.png

图 42. 应用新配置

image043.png

图 43. 发起大并发流量后的熔断

过一会,当问题熔断器打开后,业务恢复正常:
image044.png

图 44. 熔断后的应用访问页面
##Istio 的访问控制
Istio 中的访问控制有白名单和黑名单。白名单是允许从哪个服务到哪个服务的访问;黑名单是不允许从哪个服务到哪个服务之间的访问。两种实现的效果展现是一样的,由于篇幅有限,本小节展示黑名单。

我们将在 details 服务上创建一个黑名单,从 Productpage 发往 details 请求将会返回 403 错误码。
[root@master ~]# cat acl-blacklist.yml
apiVersion: "config.istio.io/v1alpha2"
kind: denier
metadata:
name: denycustomerhandler
spec:
status:
code: 7
message: Not allowed
---
apiVersion: "config.istio.io/v1alpha2"
kind: checknothing
metadata:
name: denycustomerrequests
spec:
---
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: denycustomer
spec:
match: destination.labels["app"] == "details" && source.labels["app"]=="productpage"
actions:
- handler: denycustomerhandler.denier
instances: [ denycustomerrequests.checknothing ]

清单 22. 黑名单配置文件

image045.png

图 45. 应用黑名单

接下来,对 Producepage 发起流量访问。从下图可以看到,从 Productpage 到 details 之间的访问是被拒绝的。
image046.png

图 46. Kali 显示应用流量访问

此时,通过浏览器访问 bookinfo,界面无法显示产品的详细信息,但其他微服务显示正常。
image047.png

图 47. 访问 bookinfo 应用

我们删除黑名单,再访问 bookinfo,对 details 微服务的访问马上正常。
image048.png

图 48. 删除黑名单策略

image049.png

图 49. Kali 显示应用流量访问

image050.png

图 50. 访问 bookinfo 应用
#总结
通过本文,相信读者对微服务的概念和 Istio 的架构有了一定程度的理解。在微服务领域,正是由于 Istio 强大的功能、丰富的界面、可视化的监控,Istio 的使用将会越来越广泛。
##参考

* Istio 系列
* Istio 架构介绍
* bookinfo 应用源代码
* Quick Start with Kubernetes

原文链接:https://www.ibm.com/developerworks/cn/cloud/library/cl-lo-implementing-kubernetes-microservice-using-istio/index.html

istio envoy 服务发现?

回复

tiancai 回复了问题 • 1 人关注 • 2 个回复 • 2997 次浏览 • 2018-04-27 11:04 • 来自相关话题

容器云未来:Kubernetes、Istio 和 Knative

博云BoCloud 发表了文章 • 0 个评论 • 157 次浏览 • 2019-06-03 10:38 • 来自相关话题

导读 目前以Kubernetes为基础构建的容器生态逐渐完善,这其中Kubernetes、Istio、Knative三个独立项目被越来越多的人提及,并且已经开始尝试大规模落地实践,它们恰好构成了容器云的未来拼图。今天与大家一起分享下,这三个项目究 ...查看全部
导读
目前以Kubernetes为基础构建的容器生态逐渐完善,这其中Kubernetes、Istio、Knative三个独立项目被越来越多的人提及,并且已经开始尝试大规模落地实践,它们恰好构成了容器云的未来拼图。今天与大家一起分享下,这三个项目究竟解决了什么问题,为什么它们能够一鸣惊人。


随着微服务理念不断深入人心,越来越多的企业把自己的应用逐步由单体转变成微服务架构,Container容器技术的出现恰恰加速了这个转移过程,因为它有效地解决了N多服务的快速部署问题。但是随着服务数目的增多,越来越多的企业希望能够把相关服务有效地“聚合”在一起,方便统一部署与管理。Kubenretes的出现恰恰解决了大规模微服务编排部署所带来的挑战,让整个行业意识到PaaS的落地可以成为现实。

当随着微服务体系下的服务数目越来越多,服务运维成为必然要解决的问题,于是Istio出现了,基于网络代理与控制相分离的实现策略,允许对服务控制策略进行有效合理的管控。如果你想和更多容器技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

到这里似乎到了很美好的阶段:

微服务:解决应用内聚、臃肿的问题。
Container:解决服务运行环境统一,和部署问题。
Kubernetes:解决大量微服务有效“聚合”部署问题。
Istio:解决服务上线面临的一系列治理问题。

这个阶段乍一看来,构建容器云似乎有了一个完整的链路和解决方式,一切都将变得那么“完美”。

现在让我们回过头来深入分析一下,微服务体系下的服务交互,目前是否存在问题。

首先,无论是http,还是rpc,本质上都是服务与服务的远程调用。开发应用程序中,无法做到服务与服务间的彼此透明。这样会导致一个问题:无论微服务业务拆分多么“精细”,本质上业务单元之间还是不能够独立运行和发展。同时在面向不同开发领域的衍生,无法选择最合适的实现方式。因此我们希望能够基于不同的“模板”+“配置”的方式能够把开发环境标准化处理,同时提供“事件”机制,将服务与服务交互的耦合度降到最低。

其次,服务线上运行的动态伸缩问题。当下kubernetes环境下的弹性伸缩,需要由客户搜集监测数据,并自主手动来实现,但是我们更希望服务线上能够更加自动化和智能化。

最后,服务标准化问题。我们希望服务内部的模型是标准的、能够快速复制和快速构建的;服务通信是标准的:协议标准,格式标准;运行环境是标准的:快速部署,快速迁移。

Knative的出现恰好解决远程直接调用,服务线上自动管理以及一些列标准化问题。

下面我们来看一下三者的关联:


微信图片_20190603102740.png



Kubernetes和Istio相信大家比较熟悉了,这里不做过多介绍,有需要的同学可以关注下我们之前发布的相关文章,这里我们重点来看一下Knative。

Knative是谷歌开源的serverless架构方案,旨在提供一套简单易用的serverless方案,把serverless标准化。目前参与的公司主要是Google、Pivotal、IBM、Red Hat,于2018年7月份对外发布,目前处于快速发展阶段。


Knative组成


Build
构建系统:把用户定义的应用构建成容器镜像,面向kubernetes的标准化构建,区别于Dockerfile镜像构建,重点解决kubernetes环境的构建标准化问题。

Serving
服务系统:利用Istio的部分功能,来配置应用路由,升级以及弹性伸缩。Serving中包括容器生命周期管理,容器外围对象(service,ingres)生成(恰到好处的把服务实例与访问统一在一起),监控应用请求,自动弹性负载,并且利用Virtual service和destination配置服务访问规则。只有这样才能保证服务呈现一致性以及服务运行自动化管理。

Eventing
事件系统:用于自动完成事件的绑定与触发。事件系统与直接调用最大的区别在于响应式设计,它允许运行服务本身不需要屏蔽了调用方与被调用方的关系。从而在业务层面能够实现业务的快速聚合,或许为后续业务编排创新提供事件。

现在我们换一个角度,聚焦应用服务生命周期:
**· Knative 解决应用模板+面向统一环境的标准化构建场景;
· Kubernetes作为基础设施,解决应用编排和运行环境场景;
· 加粗文字Isito作为通信基础设施层,保证应用服务运行可检测、可配置、可追踪问题。**

这三者贯穿应用服务生命周期全过程,容器云恰恰也是管理应用服务的控制平台,这就能够很好地解释,为什么Kubernetes,Istio,Knative在未来会成为构建容器云的三驾马车。

Kubernetes Istio微服务架构部署和使用

翔宇 发表了文章 • 0 个评论 • 190 次浏览 • 2019-05-27 21:40 • 来自相关话题

#什么是Istio Istio是Service Mesh(服务网格)的主流实现方案。该方案降低了与微服务架构相关的复杂性,并提供了负载均衡、服务发现、流量管理、断路器、监控、故障注入和智能路由等功能特性。 其中,Si ...查看全部
#什么是Istio

Istio是Service Mesh(服务网格)的主流实现方案。该方案降低了与微服务架构相关的复杂性,并提供了负载均衡、服务发现、流量管理、断路器、监控、故障注入和智能路由等功能特性。

其中,Sidecar模式是一种将应用功能从应用本身剥离出来作为单独进程的方式。该模式允许我们向应用无侵入添加多种功能,避免了为满足第三方组件需求而向应用添加额外的配置代码。从某种意义上来说,服务对于网络是无感知的,只知道所附加的sidecar代理,它将网络依赖抽象成了Sidecar。

在Service Mesh中,我们需要了解Data Plane和Control Plane两个概念:

* Data Plane:作用是处理网格内服务间的通信,并完成服务发现、负载均衡、流量管理、健康检查等功能;
* Control Plane:作用是管理和配置智能代理用于路由流量,同时配置Mixers来应用策略、收集指标。

Istio核心组件:

* Envoy:Istio 使用 Envoy调解服务网格中所有服务的入站和出站流量。属于数据平面。
* Mixer:负责在服务网格上执行访问控制和使用策略,以及收集从Envoy和其他服务自动监控到的数据。
* Pilot:为 Envoy sidecar 提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能。属于控制平面。
* Citadel:提供访问控制和用户身份认证功能。

Istio可视化管理组件:

* Vistio:用于近乎实时地监控应用程序和集群之间的网络流量。可以参考:https://www.yangcs.net/posts/vistio-visualize-your-istio-mesh-using-netflixs-vizceral/
* Kiali:提供可视化服务网格拓扑、断路器和请求率等功能。Kiali还包括 Jaeger Tracing,可以提供开箱即用的分布式跟踪功能。可以参考:https://jimmysong.io/istio-handbook/setup/istio-observability-tool-kiali.html
* Jaeger:用于展示Istio微服务调用链关系,以及微服务工作状态监测。注意,在生产环境中,你应当使用Elasticsearch或Cassandra持久化存储Jaeger数据。可以参考:https://blog.csdn.net/ywq935/article/details/80599297
https://mathspanda.github.io/2018/09/19/jaeger-deploy/
https://blog.frognew.com/2017/12/opentracing-jaeger-3.html

其中,Kiali、Jaeger、Prometheus、Grafana管理工具,将和Istio一并部署。如果你想和更多Istio技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
#使用Helm部署Istio

依赖环境:

* Helm > 2.10
* Kubernetes > 1.9

下载并解压缩istio的发布包
wget https://github.com/istio/istio/releases/download/1.0.6/istio-1.0.6-linux.tar.gz
tar -zxvf istio-1.0.6-linux.tar.gz
cd istio-1.0.6

Istio的Chart在istio-1.0.6/install/kubernetes/helm目录中,这个Chart包含了下面的代码文件。
# tree install/kubernetes/helm/istio
......
......
31 directories, 139 files

如果安装的Helm版本高于2.10,就不再需要手动使用kubectl安装Istio的CRD。反之,则需要执行如下命令安装。
kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml

查看安装的CRD。
kubectl get CustomResourceDefinition

通过各个组件在vaule file的enabled flag启用或禁用,下面创建名称为istio.yaml的vaule file,将几个默认禁用的组件也启用。
tracing:
enabled: true
servicegraph:
enabled: true
kiali:
enabled: true
grafana:
enabled: true

首先,创建名称为kiali的secret。
# echo -n 'admin' | base64
YWRtaW4=

# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

# cat <
apiVersion: v1
kind: Secret
metadata:
name: kiali
namespace: istio-system
labels:
app: kiali
type: Opaque
data:
username: YWRtaW4=
passphrase: MWYyZDFlMmU2N2Rm
EOF

执行helm安装命令。
helm install install/kubernetes/helm/istio --name istio --namespace istio-system -f istio.yaml

安装完成后确认各个组件的Pod正常运行。
# kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-59b8896965-5f9j2 1/1 Running 0 23m
istio-citadel-6f444d9999-s9jrc 1/1 Running 0 23m
istio-egressgateway-6d79447874-ssbc4 1/1 Running 0 23m
istio-galley-685bb48846-mvf5w 1/1 Running 0 23m
istio-grafana-post-install-6m256 0/1 Completed 0 23m
istio-ingressgateway-5b64fffc9f-mrl9t 1/1 Running 0 23m
istio-pilot-8645f5655b-k6fcz 2/2 Running 0 23m
istio-policy-547d64b8d7-6dgkp 2/2 Running 0 23m
istio-sidecar-injector-5d8dd9448d-zfdsb 1/1 Running 0 23m
istio-telemetry-c5488fc49-qwwcv 2/2 Running 0 23m
istio-tracing-6b994895fd-4vjfx 1/1 Running 0 23m
kiali-5f9ffff7cf-jqk8p 1/1 Running 0 23m
prometheus-76b7745b64-xjzmm 1/1 Running 0 23m
servicegraph-cb9b94c-mlhjm 1/1 Running 0 23m

Istio以一个项目的形式部署到Kubernetes集群中。我们可以看到,部署好的Pod中,除了有istio-citadel、istio-egressgateway、istio-ingressgateway、istio-pilot等Istio本身的功能组件,还集成了微服务相关的监控工具,如:Grafana、jaeger-agent、kiali、Prometheus。正是这些功能丰富且强大的监控工具,帮助Istio实现了微服务的可视化管理。
#运行示例Bookinfo

您可以部署自己的应用或者示例应用程序如Bookinfo。 注意:应用程序必须使用HTTP/1.1或HTTP/2.0协议来传递HTTP流量,因为HTTP/1.0已经不再支持。

如果运行Pod的namespace被标记为istio-injection=enabled的话,Istio-Initializer会向应用程序的Pod中自动注入Envoy容器:
kubectl label namespace  istio-injection=enabled
kubectl create -n -f .yaml

如果您没有安装Istio-initializer-injector的话,您必须使用istioctl kube-inject命令在部署应用之前向应用程序的Pod中手动注入Envoy容器:
kubectl create -f <(istioctl kube-inject -f .yaml)

Bookinfo应用由四个单独的微服务构成,用来演示多种Istio特性,包含:

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

reviews微服务有 3 个版本:

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

下图展示了这个应用的端到端架构。
1.png

运行示例bookinfo,并开启Sidecar自动注入。
# kubectl label namespace default istio-injection=enabled
# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
# kubectl apply -f samples/bookinfo/platform/consul/destination-rule-all.yaml

访问productpage:http://172.16.0.180:31380/productpage
2.png

31380端口可以通过命令获取:
kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.spec.ports[0].nodePort}'

#使用Ingress暴露管理服务

完成Istio的安装后,可以看到安装的组件除了Istio架构中的数据平面和控制平面的各个核心组件,还部署了Prometheus、Grafana、Jaeger、Kiali等辅助组件。 在云原生生态中,我们已经对这些组件很熟悉了。

* Prometheus:监控系统,收集Istio的监控数据
* Grafana:监控信息的图表展现,Istio部署的Grafana为我们内置了各个组件相关的Dashboard
* Jaeger:分布式跟踪系统,Istio中集成Jaeger可以对基于Istio的微服务实现调用链跟踪、依赖分析,为性能优化和故障排查提供支持
* kiali:kiali作为Istio的可视化管理工具,可以认为是Istio的UI,可以展现服务的网络拓扑、服务的容错情况(超时、重试、短路等)、分布式跟踪等

这些辅助组件都有自己的web界面,这里我们使用ingress的方式将这些组件暴露到集群外,以便在集群外部访问。Istio支持使用自带的istio-ingressgateway将服务暴露到集群外部,这个和Kubernetes中暴露Ingress Controller类似,有很多种方式,如NodePort,LoadBalancer,或直接开启hostNetwork: true等等。为了便于统一管理Kubernetes集群中的服务暴露,笔者更倾向使用Traefik Ingress。

使用Ingress暴露Istio服务。

编写ingress yaml文件,如下
# cat istio-ingress.yaml 
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: jaeger-query
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.jaeger-query.com
http:
paths:
- path: /
backend:
serviceName: jaeger-query
servicePort: 16686

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: prometheus
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.prometheus.com
http:
paths:
- path: /
backend:
serviceName: prometheus
servicePort: 9090

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: grafana
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.grafana.com
http:
paths:
- path: /
backend:
serviceName: grafana
servicePort: 3000

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kiali
namespace: istio-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: istio.kiali.com
http:
paths:
- path: /
backend:
serviceName: kiali
servicePort: 20001

执行部署命令:
kubectl apply -f istio-ingress.yaml

外部客户端,配置hosts地址解析,如下:
172.16.0.180 istio.prometheus.com
172.16.0.180 istio.jaeger-query.com
172.16.0.180 istio.grafana.com
172.16.0.180 istio.kiali.com

##访问Jaeger

浏览器访问Jaeger之前可以多次刷新productpage页面以便产生访问请求等。选择productpage.default可以查看整个调用链。使用istio.jaeger-query.com域名访问,结果展示:
3.png

##访问kiali

使用域名istio.kiali.com访问kiali页面。用户名admin,密码1f2d1e2e67df。
4.png

##访问Prometheus

使用域名istio.prometheus.com访问Prometheus页面。
5.png

##访问Grafana

使用域名istio.grafana.com访问Prometheus页面。
6.png

##Istio对Pod和服务的要求

要成为服务网格的一部分,Kubernetes 集群中的 Pod 和服务必须满足以下几个要求:

* 需要给端口正确命名:服务端口必须进行命名。端口名称只允许是<协议>[-<后缀>-]模式;
* Pod必须关联到 Kubernetes服务:如果一个 Pod 属于多个服务,这些服务不能再同一端口上使用不同协议,例如 HTTP 和 TCP。
* Deployment应带有app以及version标签:每个 Deployment 都应该有一个有意义的 app 标签和一个用于标识 Deployment 版本的 version 标签。Istio 会用 app 和 version 标签来给监控指标数据加入上下文信息。

#总结

本文实践了使用istio官方提供的helm chart在Kubernetes上部署Istio 1.0.6的过程,并使用Traefik Ingress将Istio集成的Prometheus、Grafana、Jaeger、Kiali等辅助组件暴露到集群外部,并对进入集群的流量进行管理。

在生产环境中,如果是基于公有云,如阿里云、AWS等运行Istio,建议Ingress的IP地址使用ELB地址;如果是自建的平台,则建议使用HAproxy+Keepalived提供的VIP地址,作为Ingress的IP地址,实现高可用。

如果Ingress服务,需要暴露在公网,应当使用CA认证机构颁发的证书https化(如使用cert-manager)。此外建议使用NFS、Ceph等方案实现Istio监控以及微服务应用的数据持久化存储。

Istio参考资料:

* https://istio.io/zh/docs/
* https://jimmysong.io/istio-handbook/
* http://www.servicemesher.com/

原文链接:Kubernetes Istio微服务架构部署和使用

如何为服务网格选择入口网关?

阿娇 发表了文章 • 0 个评论 • 205 次浏览 • 2019-05-21 23:02 • 来自相关话题

在启用了Istio服务网格的Kubernetes集群中,缺省情况下只能在集群内部访问网格中的服务,要如何才能从外部网络访问这些服务呢? Kubernetes和Istio提供了NodePort,LoadBalancer,Kubernetes Ingress,Is ...查看全部
在启用了Istio服务网格的Kubernetes集群中,缺省情况下只能在集群内部访问网格中的服务,要如何才能从外部网络访问这些服务呢? Kubernetes和Istio提供了NodePort,LoadBalancer,Kubernetes Ingress,Istio Gateway等多种外部流量入口的方式,面对这么多种方式,我们在产品部署中应该如何选择?

本文将对Kubernetes和Istio对外提供服务的各种方式进行详细介绍和对比分析,并根据分析结果提出一个可用于产品部署的解决方案。如果你想和更多Istio技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

说明:阅读本文要求读者了解Kubernetes和Istio的基本概念,包括Pod、Service、NodePort、LoadBalancer、Ingress、Gateway、VirtualService等。如对这些概念不熟悉,可以在阅读过程中参考文后的相关链接。
#内部服务间的通信
首先,我们来回顾一下Kubernetes集群内部各个服务之间相互访问的方法。
##Cluster IP
Kubernetes以Pod作为应用部署的最小单位。kubernetes会根据Pod的声明对其进行调度,包括创建、销毁、迁移、水平伸缩等,因此Pod 的IP地址不是固定的,不方便直接采用Pod IP对服务进行访问。

为解决该问题,Kubernetes提供了Service资源,Service对提供同一个服务的多个Pod进行聚合。一个Service提供一个虚拟的Cluster IP,后端对应一个或者多个提供服务的Pod。在集群中访问该Service时,采用Cluster IP即可,Kube-proxy负责将发送到Cluster IP的请求转发到后端的Pod上。

Kube-proxy是一个运行在每个节点上的Go应用程序,支持三种工作模式:

1、Userspace

该模式下kube-proxy会为每一个Service创建一个监听端口。发向Cluster IP的请求被Iptables规则重定向到Kube-proxy监听的端口上,Kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。

该模式下,Kube-proxy充当了一个四层Load balancer的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加两次内核和用户空间之间的数据拷贝,效率较另外两种模式低一些;好处是当后端的Pod不可用时,kube-proxy可以重试其他Pod。
1.png

Kube-proxy userspace模式(来自Kubernetes官网文档

2、iptables

为了避免增加内核和用户空间的数据拷贝操作,提高转发效率,Kube-proxy提供了iptables模式。在该模式下,Kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。

该模式下Kube-proxy不承担四层代理的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
2.png

Kube-proxy iptables模式(来自Kubernetes官网文档

3、IPVS
该模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs rules。IPVS也是在kernel模式下通过netfilter实现的,但采用了hash table来存储规则,因此在规则较多的情况下,IPVS相对iptables转发效率更高。除此以外,IPVS支持更多的LB算法。如果要设置kube-proxy为IPVS模式,必须在操作系统中安装IPVS内核模块。
3.png

Kube-proxy ipvs模式(来自Kubernetes官网文档
##Istio Sidecar Proxy
Cluster IP解决了服务之间相互访问的问题,但从上面Kube-proxy的三种模式可以看到,Cluster IP的方式只提供了服务发现和基本的LB功能。如果要为服务间的通信应用灵活的路由规则以及提供Metrics collection,distributed tracing等服务管控功能,就必须得依靠Istio提供的服务网格能力了。

在Kubernetes中部署Istio后,Istio通过iptables和Sidecar Proxy接管服务之间的通信,服务间的相互通信不再通过Kube-proxy,而是通过Istio的Sidecar Proxy进行。请求流程是这样的:Client发起的请求被iptables重定向到Sidecar Proxy,Sidecar Proxy根据从控制面获取的服务发现信息和路由规则,选择一个后端的Server Pod创建链接,代理并转发Client的请求。

Istio Sidecar Proxy和Kube-proxy的userspace模式的工作机制类似,都是通过在用户空间的一个代理来实现客户端请求的转发和后端多个Pod之间的负载均衡。两者的不同点是:Kube-Proxy工作在四层,而Sidecar Proxy则是一个七层代理,可以针对HTTP,GRPS等应用层的语义进行处理和转发,因此功能更为强大,可以配合控制面实现更为灵活的路由规则和服务管控功能。
4.jpg

Istio Sidecar Proxy
#如何从外部网络访问
Kubernetes的Pod IP和Cluster IP都只能在集群内部访问,而我们通常需要从外部网络上访问集群中的某些服务,Kubernetes提供了下述几种方式来为集群提供外部流量入口。
##NodePort
NodePort在集群中的主机节点上为Service提供一个代理端口,以允许从主机网络上对Service进行访问。Kubernetes官网文档只介绍了NodePort的功能,并未对其实现原理进行解释。下面我们通过实验来分析NodePort的实现机制。

www.katacoda.com这个网站提供了一个交互式的Kubernetes playground,注册即可免费实验Kubernetes的相关功能,下面我们就使用Katacoda来分析Nodeport的实现原理。

在浏览器中输入这个网址:https://www.katacoda.com/courses/kubernetes/networking-introduction, 打开后会提供了一个实验用的Kubernetes集群,并可以通过网元模拟Terminal连接到集群的Master节点。

执行下面的命令创建一个NodePort类型的Service。
kubectl apply -f nodeport.yaml

查看创建的Service,可以看到Kubernetes创建了一个名为webapp-nodeport-svc的Service,并为该Service在主机节点上创建了30080这个NodePort。
master $ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 36m
webapp1-nodeport-svc NodePort 10.103.188.73 80:30080/TCP 3m

webapp-nodeport-svc后端对应两个Pod,其Pod的IP分别为10.32.0.3和10.32.0.5。
master $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IPNODE NOMINATED NODE
webapp1-nodeport-deployment-785989576b-cjc5b 1/1 Running 0 2m 10.32.0.3
webapp1-nodeport-deployment-785989576b-tpfqr 1/1 Running 0 2m 10.32.0.5

通过netstat命令可以看到Kube-proxy在主机网络上创建了30080监听端口,用于接收从主机网络进入的外部流量。
master $ netstat -lnp|grep 30080
tcp6 0 0 :::30080 :::* LISTEN 7427/kube-proxy

下面是Kube-proxy创建的相关iptables规则以及对应的说明。可以看到Kube-proxy为NodePort创建了相应的IPtable规则,将发向30080这个主机端口上的流量重定向到了后端的两个Pod IP上。
iptables-save > iptables-dump
# Generated by iptables-save v1.6.0 on Thu Mar 28 07:33:57 2019
*nat
# Nodeport规则链
:KUBE-NODEPORTS - [0:0]
# Service规则链
:KUBE-SERVICES - [0:0]
# Nodeport和Service共用的规则链
:KUBE-SVC-J2DWGRZTH4C2LPA4 - [0:0]
:KUBE-SEP-4CGFRVESQ3AECDE7 - [0:0]
:KUBE-SEP-YLXG4RMKAICGY2B3 - [0:0]

# 将host上30080端口的外部tcp流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp --dport 30080 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到Cluster IP 10.103.188.73的内部流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
KUBE-SERVICES -d 10.103.188.73/32 -p tcp -m comment --comment "default/webapp1-nodeport-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到webapp1-nodeport-svc的流量转交到第一个Pod(10.32.0.3)相关的规则链上,比例为50%
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YLXG4RMKAICGY2B3
#将发送到webapp1-nodeport-svc的流量转交到第二个Pod(10.32.0.5)相关的规则链上
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -j KUBE-SEP-4CGFRVESQ3AECDE7

#将请求重定向到Pod 10.32.0.3
-A KUBE-SEP-YLXG4RMKAICGY2B3 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.3:80
#将请求重定向到Pod 10.32.0.5
-A KUBE-SEP-4CGFRVESQ3AECDE7 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.5:80

从上面的实验可以看到,通过将一个Service定义为NodePort类型,Kubernetes会通过集群中Node上的Kube-proxy为该Service在主机网络上创建一个监听端口。Kube-proxy并不会直接接收该主机端口进入的流量,而是会创建相应的Iptables规则,并通过Iptables将从该端口收到的流量直接转发到后端的Pod中。

NodePort的流量转发机制和Cluster IP的iptables模式类似,唯一不同之处是在主机网络上开了一个“NodePort”来接受外部流量。从上面的规则也可以看出,在创建Nodeport时,Kube-proxy也会同时为Service创建Cluster IP相关的iptables规则。

备注:除采用iptables进行流量转发,NodePort应该也可以提供userspace模式以及ipvs模式,这里未就这两种模式进行实验验证。



从分析得知,在NodePort模式下,集群内外部的通讯如下图所示:
5.jpg

NodePort
##LoadBalancer
NodePort提供了一种从外部网络访问Kubernetes集群内部Service的方法,但该方法存在下面一些限制,导致这种方式主要适用于程序开发,不适合用于产品部署。

* Kubernetes cluster host的IP必须是一个well-known IP,即客户端必须知道该IP。但Cluster中的host是被作为资源池看待的,可以增加删除,每个host的IP一般也是动态分配的,因此并不能认为host IP对客户端而言是well-known IP。
* 客户端访问某一个固定的host IP的方式存在单点故障。假如一台host宕机了,Kubernetes cluster会把应用reload到另一节点上,但客户端就无法通过该host的NodePort访问应用了。
* 通过一个主机节点作为网络入口,在网络流量较大时存在性能瓶颈。

为了解决这些问题,Kubernetes支持将Service定义为LoadBalancer类型。 Cloud Provider Controller监听Service的变化消息,当LoadBalancer类型的Service创建后,Cloud Provider Controller会将配置下发到Cloud Provider网络中的一个四层负载均衡器,该四层负载均衡器负责将外部网络流量分发到后面的多个节点的NodePort端口上。

下图展示了Kubernetes如何通过LoadBalancer方式对外提供流量入口,图中LoadBalancer后面接入了两个主机节点上的NodePort,后端部署了三个Pod提供服务。根据集群的规模,可以在LoadBalancer后面可以接入更多的主机节点,以进行负荷分担。
6.jpg

NodeBalancer

备注:LoadBalancer类型需要云服务提供商的支持,Service中的定义只是在Kubernetes配置文件中提出了一个要求,即为该Service创建Load Balancer,至于如何创建则是由Google Cloud或Amazon Cloud等云服务商提供的,创建的Load Balancer的过程不在Kubernetes Cluster的管理范围中。



目前AWS,Azure,CloudStack,GCE和OpenStack等主流的公有云和私有云提供商都可以为Kubernetes提供Load Balancer。一般来说,公有云提供商还会为Load Balancer提供一个External IP,以提供Internet接入。如果你的产品没有使用云提供商,而是自建Kubernetes Cluster,则需要自己提供LoadBalancer。
##Ingress
LoadBalancer类型的Service提供的是四层负载均衡器,当只需要向外暴露一个服务的时候,采用这种方式是没有问题的。但当一个应用需要对外提供多个服务时,采用该方式则要求为每一个四层服务(IP+Port)都创建一个外部load balancer。

一般来说,同一个应用的多个服务/资源会放在同一个域名下,在这种情况下,创建多个Load balancer是完全没有必要的,反而带来了额外的开销和管理成本。另外直接将服务暴露给外部用户也会导致了前端和后端的耦合,影响了后端架构的灵活性,如果以后由于业务需求对服务进行调整会直接影响到客户端。

在这种情况下,我们可以通过使用Kubernetes Ingress来统一网络入口。Kubernetes Ingress声明了一个应用层(OSI七层)的负载均衡器,可以根据HTTP请求的内容将来自同一个TCP端口的请求分发到不同的Kubernetes Service,其功能包括:

* 按HTTP请求的URL进行路由,同一个TCP端口进来的流量可以根据URL路由到Cluster中的不同服务,如下图所示:
7.png

Simple fanout

* 按HTTP请求的Host进行路由,同一个IP进来的流量可以根据HTTP请求的Host路由到Cluster中的不同服务,如下图所示:
8.png

Name based virtual hosting

Ingress规则定义了对七层网关的要求,包括URL分发规则,基于不同域名的虚拟主机,SSL证书等。Kubernetes使用Ingress Controller 来监控Ingress规则,并通过一个七层网关来实现这些要求,一般可以使用Nginx,HAProxy,Envoy等。

虽然Ingress Controller通过七层网关为后端的多个Service提供了统一的入口,但由于其部署在集群中,因此并不能直接对外提供服务。实际上Ingress需要配合NodePort和LoadBalancer才能提供对外的流量入口,如下图所示:
9.png

采用Ingress,NodePortal和LoadBalancer提供外部流量入口的拓扑结构
上图描述了如何采用Ingress配合NodePort和Load Balancer为集群提供外部流量入口,从该拓扑图中可以看到该架构的伸缩性非常好,在NodePort,Ingress,Pod等不同的接入层面都可以对系统进行水平扩展,以应对不同的外部流量要求。

上图只展示了逻辑架构,下面的图展示了具体的实现原理:
10.png

采用Ingress,NodePortal和LoadBalancer提供外部流量入口的实现原理
流量从外部网络到达Pod的完整路径如下:

  1. 外部请求先通过四层Load Balancer进入内部网络
  2. Load Balancer将流量分发到后端多个主机节点上的NodePort(userspace转发)
  3. 请求从NodePort进入到Ingress Controller(iptabes规则,Ingress Controller本身是一个NodePort类型的Service)
  4. Ingress Controller根据Ingress rule进行七层分发,根据HTTP的URL和Host将请求分发给不同的Service(userspace转发)
  5. Service将请求最终导入到后端提供服务的Pod中(iptabes规则)

从前面的介绍可以看到,Kubernetes Ingress提供了一个基础的七层网关功能的抽象定义,其作用是对外提供一个七层服务的统一入口,并根据URL/HOST将请求路由到集群内部不同的服务上。
#如何为服务网格选择入口网关?
在Istio服务网格中,通过为每个Service部署一个Sidecar代理,Istio接管了Service之间的请求流量。控制面可以对网格中的所有sidecar代理进行统一配置,实现了对网格内部流量的路由控制,从而可以实现灰度发布,流量镜像,故障注入等服务管控功能。但是,Istio并没有为入口网关提供一个较为完善的解决方案。
##Kubernetes Ingress
在0.8版本以前,Istio缺省采用Kubernetes Ingress来作为Service Mesh的流量入口。Kubernetes Ingress统一了应用的流量入口,但存在两个问题:

* Kubernetes Ingress是独立在Istio体系之外的,需要单独采用Ingress rule进行配置,导致系统入口和内部存在两套互相独立的路由规则配置,运维和管理较为复杂。
* Kubernetes Ingress rule的功能较弱,不能在入口处实现和网格内部类似的路由规则,也不具备网格Sidecar的其它能力,导致难以从整体上为应用系统实现灰度发布、分布式跟踪等服务管控功能。


11.jpg

采用Kubernetes Ingress作为服务网格的流量入口
##Istio Gateway
Istio社区意识到了Ingress和Mesh内部配置割裂的问题,因此从0.8版本开始,社区采用了 Gateway 资源代替K8s Ingress来表示流量入口。

Istio Gateway资源本身只能配置L4-L6的功能,例如暴露的端口,TLS设置等;但Gateway可以和绑定一个VirtualService,在VirtualService 中可以配置七层路由规则,这些七层路由规则包括根据按照服务版本对请求进行导流,故障注入,HTTP重定向,HTTP重写等所有Mesh内部支持的路由规则。

Gateway和VirtualService用于表示Istio Ingress的配置模型,Istio Ingress的缺省实现则采用了和Sidecar相同的Envoy proxy。

通过该方式,Istio控制面用一致的配置模型同时控制了入口网关和内部的sidecar代理。这些配置包括路由规则,策略检查、Telementry收集以及其他服务管控功能。
12.jpg

采用Istio Ingress Gateway作为服务网格的流量入口
##应用对API Gateway的需求
采用Gateway和VirtualService实现的Istio Ingress Gateway提供了网络入口处的基础通信功能,包括可靠的通信和灵活的路由规则。但对于一个服务化应用来说,网络入口除了基础的通讯功能之外,还有一些其他的应用层功能需求,例如:

* 第三方系统对API的访问控制
* 用户对系统的访问控制
* 修改请求/返回数据
* 服务API的生命周期管理
* 服务访问的SLA、限流及计费
* ……


13.png

Kubernetes ingress,Istio Gateway and API Gateway的功能对比

API Gateway需求中很大一部分需要根据不同的应用系统进行定制,目前看来暂时不大可能被纳入Kubernetes Ingress或者Istio Gateway的规范之中。为了满足这些需求,涌现出了各类不同的Kubernetes Ingress Controller以及Istio Ingress Gateway实现,包括Ambassador,Kong,Traefik,Solo等。

这些网关产品在实现在提供基础的Kubernetes Ingress能力的同时,提供了强大的API Gateway功能,但由于缺少统一的标准,这些扩展实现之间相互之间并不兼容。而且遗憾的是,目前这些Ingress Controller都还没有正式提供和Istio 控制面集成的能力。

备注:

* Ambassador将对Istio路由规则的支持纳入了Roadmap https://www.getambassador.io/user-guide/with-istio/
* Istio声称支持Istio-Based Route Rule Discovery(尚处于实验阶段)https://gloo.solo.io/introduction/architecture/

##采用API Gateway + Sidecar Proxy作为服务网格的流量入口
在目前难以找到一个同时具备API Gateway和Isito Ingress能力的网关的情况下,一个可行的方案是使用API Gateway和Sidecar Proxy一起为服务网格提供外部流量入口。

由于API Gateway已经具备七层网关的功能,Mesh Ingress中的Sidecar只需要提供VirtualService资源的路由能力,并不需要提供Gateway资源的网关能力,因此采用Sidecar Proxy即可。网络入口处的Sidecar Proxy和网格内部应用Pod中Sidecar Proxy的唯一一点区别是:该Sidecar只接管API Gateway向Mesh内部的流量,并不接管外部流向API Gateway的流量;而应用Pod中的Sidecar需要接管进入应用的所有流量。
14.png

采用API Gateway + Sidecar Proxy为服务网格提供流量入口

备注:在实际部署时,API Gateway前端需要采用NodePort和LoadBalancer提供外部流量入口。为了突出主题,对上图进行了简化,没有画出NodePort和LoadBalancer。

采用API Gateway和Sidecar Proxy一起作为服务网格的流量入口,既能够通过对网关进行定制开发满足产品对API网关的各种需求,又可以在网络入口处利用服务网格提供的灵活的路由能力和分布式跟踪,策略等管控功能,是服务网格产品入口网关的一个理想方案。

性能方面的考虑:从上图可以看到,采用该方案后,外部请求的处理流程在入口处增加了Sidecar Proxy这一跳,因此该方式会带来少量的性能损失,但该损失是完全可以接受的。

对于请求时延而言,在服务网格中,一个外部请求本来就要经过较多的代理和应用进程的处理,在Ingress处增加一个代理对整体的时延影响基本忽略不计,而且对于绝大多数应用来说,网络转发所占的时间比例本来就很小,99%的耗时都在业务逻辑。如果系统对于增加的该时延非常敏感,则我建议重新考虑是否应该采用微服务架构和服务网格,毕竟任何架构模式都不是万能的,不能因为有了锤子,看什么都像钉子。

对于吞吐量而言,如果入口处的网络吞吐量存在瓶颈,则可以通过对API Gateway + Sidecar Proxy组成的Ingress整体进行水平扩展,来对入口流量进行负荷分担,以提高网格入口的网络吞吐量。

原文链接:如何为服务网格选择入口网关?(作者:赵化冰)

Istio 服务注册插件机制代码解析

老马 发表了文章 • 0 个评论 • 172 次浏览 • 2019-05-21 22:24 • 来自相关话题

集成Istio的Breeze新版本全面发布

wise2c 发表了文章 • 0 个评论 • 160 次浏览 • 2019-05-21 17:49 • 来自相关话题

睿云智合在2018年12月随着官方Kubernetes v1.13版本的推出,在相应Breeze版本里集成了云原生监控工具Prometheus(基于Operator方式部署),作为一款优秀的Kubernetes部署工具,Breeze的核心优势在于: ...查看全部
睿云智合在2018年12月随着官方Kubernetes v1.13版本的推出,在相应Breeze版本里集成了云原生监控工具Prometheus(基于Operator方式部署),作为一款优秀的Kubernetes部署工具,Breeze的核心优势在于:

1、真正的100%离线环境支持(image和rpm保证基于官方未做任何修改);

2、图形化操作降低上手难度;

3、简化K8s繁琐的证书更新管理,避免过期问题导致集群停摆;

4、不仅仅是K8s自身的安装,同时引入了生态链工具的模块安装。


随着ServiceMesh技术的持续火热,我们在近期的各个主要分支版本(v1.11.x / v1.12.x / v1.13.x / v1.14.x)开始集成完整的Istio(包含了Kiali图形化Istio管理工具、分布式追踪Jaeger、基于Prometheus+Grafana的Istio监控)。例如在对应Kubernetes v1.14.2的Breeze v1.14.2,我们集成了最新的Helm v0.24.0 + Istio v1.1.7组件,仍然一如既往的一键式离线部署:


用户只需要选择一台K8s master节点,添加Istio角色并确认各服务暴露的端口,即可将其部署至全新或现有K8s集群中:
图片1.png

图片2.png

图片3.png



部署完成后,对集群进行检查:
图片4.png

图片5.png

图片6.png


登录各服务暴露的端口:

Kiali:

http://任意服务器IP:30201/kiali
图片7.png

图片8.png


Jaeger:

http://任意服务器IP:30280
图片9.png


Prometheus for Istio:

http://任意服务器IP:30290
图片10.png


Grafana for Istio:

http://任意服务器IP:30292
图片11.png



关于睿云智合

深圳睿云智合科技有限公司成立于2012年,总部位于深圳,并分别在成都、深圳设立了研发中心,北京、上海设立了分支机构,核心骨干人员全部为来自金融、科技行业知名企业资深业务专家、技术专家。早期专注于为中国金融保险等大型企业提供创新技术、电子商务、CRM等领域专业咨询服务。

自2016年始,在率先将容器技术引进到中国保险行业客户后,公司组建了专业的容器技术产品研发和实施服务团队,旨在帮助中国金融行业客户将容器创新技术应用于企业信息技术支持业务发展的基础能力改善与提升,成为中国金融保险行业容器技术服务领导品牌。

此外,凭借多年来在呼叫中心领域的业务经验与技术积累,睿云智合率先在业界推出基于开源软交换平台FreeSwitch的微服务架构多媒体数字化业务平台,将语音、视频、webchat、微信、微博等多种客户接触渠道集成,实现客户统一接入、精准识别、智能路由的CRM策略,并以容器化治理来支持平台的全应用生命周期管理,显著提升了数字化业务处理的灵活、高效、弹性、稳定等特性,为帮助传统企业向“以客户为中心”的数字化业务转型提供完美的一站式整体解决方案。

Linkerd or Istio?哪个Service Mesh框架更适合你?

博云BoCloud 发表了文章 • 0 个评论 • 487 次浏览 • 2019-04-30 14:09 • 来自相关话题

翻译 | 宋松 原文 | https://medium.com/solo-io/linkerd-or-istio-6fcd2aad6e42 本周我开始写一篇比较Istio和Linked的帖子,并 ...查看全部
翻译 | 宋松
原文 | https://medium.com/solo-io/linkerd-or-istio-6fcd2aad6e42



本周我开始写一篇比较Istio和Linked的帖子,并且告诉我自己:我将用一个表格来比较两者的特性,这将会很棒,人们会爱上它,这个世界将会幸福几秒钟。我向自己承诺这将是一个公平的比较,没有任何偏见。虽然比较的表格仍然存在,但我转移了文章的终点:目标不再是哪个更好,而是哪个更适合你、你的应用程序和你的组织。

在职业生涯的一段时间中,我曾担任某公司的售前架构师,记得有很多次我们被要求填写产品比较表。我经常需要运用创造力来确保产品看起来很好,几乎不惜一切代价避免表格中令人不愉快的“不支持”的框。考虑到诚信工作,但是有时候不得不这样做。

站在评价者的角度来看,我理解他们(希望)的目的是进行公平的比较,在这种程度上,对比的表格似乎是一种可靠的方式。我们知道一个项目的成功可以预测职业的发展,我们都喜欢这一点。但问题是:如果评估的最终目标是产品对比表格,而不是能让企业更有竞争力的高质量软件,那么这个评估的最后将只是一些“表格”的工作。

产品比较并不是最终目的,通过比较知道哪些对你的用例最好才是最终目的。因此让我们通过七个方面来深入研究Service Mesh,主要是以下几个方面:

  • 流量管理
  • 安全
  • 安装/配置
  • 支持的环境
  • 监测
  • 策略管理
  • 性能
对于上述七个方面中的每一个,我都将发表个人观点,希望我的观点能够帮你做出更接近于简洁的决策。#流量管理需要强调的是,Istio和Linkerd的区别在于数据平面使用了两种不同的代理技术。Istio使用Envoy作为其代理。Envoy是C++编写的,最初是由Lyft构建,以便以非Kubernetes方式促进微服务的流量管理。许多公司已经将Envoy扩展为Kubernetes的ingress技术。Linkerd(v2)使用的是一种名为Linkerd-proxy的专用服务网格代理。这个代理是使用Rust编写的,与该代理一起,许多低级代理(网络客户机与服务器)功能在另一个也是由rust编写名为Tower的项目中实现。Tower依赖于Tokio,Tokio是一个由Rust编写的事件驱动非阻塞I/O库。如果你和我一样欣赏统计学,那么Rust已经连续四年(2016、2017、2018、2019)一直是Stack-overflow最受欢迎的语言。
微信截图_20190429162020.png
Istio是构建与Envoy之上的因此在流量管理方面它是占据优势的,Envoy已经包含了重要的IMHO功能,比如子集路由。用户仍然可以使用Linkerd实现金丝雀/蓝绿/a-b发布,但必须依靠单独的Kubernetes服务和能够分发流量的集群ingress技术,比如Gloo(gloo.solo.io)。Linkerd团队在最近一次社区会议上公开表示,计划在未来的版本中实现更加高级的L7流量管理功能。#安全关于安全,我正在考虑保护通信通道的能力。Istio和Linkerd两者都提供了合理的安全保护功能。
微信截图_20190429162033.png
Istio和Linkerd都依赖于外部根证书,因此两者都能保证进行安全通信。这听起来像是一个很好的周末项目,你觉得呢?#安装和配置
3.png
鉴于Istio可以安装在许多不同的平台上,安装说明可能会存在很大的不同。在写这篇文章的时候,关于Linkerd的安装,我对一些预先需要安装功能的检查印象很深刻。有很多次我在共享的Kubernetes集群中安装一些Linkerd功能时,我不清楚我是否拥有必要的权限。对于Linkerd,pre-check(或check-pre)检查你是否拥有在安装过程中创建Kubernetes所需资源的权限。#环境支持和部署模型对于是选择kubernetes或者是非Kubernetes安装,这是一个很直接的问题,Linkerd2是用基于kubernetes方式构建的,至少目前是这样的,而Istio收到了一下其他的公司的贡献,希望istio能在非kubernetes环境中运行。
4.png
考虑多集群部署,客观来说对于它的解释可能很棘手。从技术上来讲,共享根CA证书的多个不同集群(具有不同的控制平面)上的服务之间可以有效的通信。Istio扩展了上述概念,因为它支持不同情形下的多个集群:
  • 单个控制平面即可满足不同集群之间网络连接和pod之间IP寻址。
  • 通过使用具有单个控制平面的集群边界网关(egress和ingress)即可访问多个集群上的kubernetes API服务器。

在上述两种情况下,包含控制平面的集群将成为mesh管理的SPOF(single point of failure)。在我们这个可以在同一区域下的多个可用区域上部署单个集群的世界中,这将不再是一个问题,但仍然不能完全忽略它。




#监测



5.png




可以说Istio的管理控制台是一个缺失的部分。 Kiali Observability Console确实解决了一些管理员对service mesh所需的一些需求。

Kiali(κιάλι)是一个希腊词,意思是望远镜,从Kiali的网站上可以清楚的看到它打算成为一个可监测性的控制台,而不仅仅是一个Service Mesh管理控制台。

Linkerd控制台还不完整,但是社区决定也要构建一个管理仪表盘的目标是一个优势。

Linkerd未能提供请求追踪。想要以非侵入方式查看请求追踪跨度必须等待Linkerd实现该功能。Istio利用了Envoy支持添加追踪headers的事实。

应该提醒用户,应用程序需要准备好转发跟踪headers,如果没有准备,代理可以生成新的跟踪IDS,这可能会无意中将单个请求分割为多个请求跨度使请求之间失去必要的关联性。大多数开发框架都有转发headers的选项,而无需用户编写大量的代码。



#策略管理

Istio的爱好者,请欢欣鼓舞!Istio的策略管理能力令人印象深刻。

该项目构建了一个可扩展的策略管理机制,允许其他技术可从多个方面与Istio集成,请参阅下面的“template”列表以及一些集成的提供者。你可以认为“template”是一种集成。


6.png



为了突出其他策略类型,Istio也可适用于rating和limiting以及提供对主体身份验证的开箱即用支持。Linkerd用户依赖集群ingress控制器提供rating和limiting。

对于主体身份验证,我一直认为它应该委托给应用程序。请记住#4分布式计算的谬论:网络是安全的。对此持零信任策略。


7.png



Istio令人印象深刻的策略管理能力是需要代价的。考虑到他的广泛性,管理众多的选项增加了本已昂贵的运营成本。

Istio(Mixer)的策略管理组件也增加了显著的性能,我们将在下面详细讨论。



#性能

对比表在哪里?幸运的是,就在最近,发布了两个很棒的博客,对Istio和Linkerd的性能进行了比较,我在下面引用了其中一些结论:

对于这种综合工作负载,Istio的Envoy代理使用比Linkerd多50%的CPU。Linkerd的控制平面使用了一小部分Istio,特别是在考虑“core”组件时。



——Michael Kipper — Benchmarking Istio & Linkerd CPU(https://medium.com/@ihcsim/linkerd-2-0-and-istio-performance-benchmark-df290101c2bb)

And…

在本实验中,与基线设置相比,Linkerd2-meshed设置和Istio-meshed设置都经历了更高的延迟和更低的吞吐量。在Istio-meshed设置中产生的延迟高于在Linkerd2-meshed设置中观察到的延迟。Linkerd2-Meshed设置能够处理比Istio-Meshed设置更高的HTTP和GRPC ping吞吐量。



——Ivan Sim — Linkerd 2.0 and Istio Performance Benchmark(https://medium.com/@ihcsim/linkerd-2-0-and-istio-performance-benchmark-df290101c2bb)

意识到Mixer所增加的处理时间,Istio团队目前正致力于重写Mixer组件:“Mixer将用c++重新并直接嵌入到Envoy中。将不再有任何独立的Mixer服务。这将提高性能并降低运营复杂性。”



—Source Mixer V2 Design Document(https://docs.google.com/document/d/1QKmtem5jU_2F3Lh5SqLp0IuPb80_70J7aJEYu4_gS-s/edit)



#总结



是的,Istio比Linkerd2.3有多的特性。这是很好的,更多的特性意味着处理更复杂和边缘用例的能力增强。这没什么神奇的,更多的特性通常意味着更多的配置,潜在的资源利用率和运营成本的增加,所有这里有三条建议:



如果你不知道80%最常见的工作负载是什么样子的,那么你将很难选择服务网格。如果你不知道这些数字,你的企业可能还没有准备好进行服务网格的使用。如果你只是在探索,那就另当别论了。

如果你想计划解决所有可能的当前和未来的cases(通常叫做comparison spreadsheet),那么你将会有一段糟糕的时间。你很可能会过度获取,这对你购买的任何软件都是如此。

盲目的选择一种技术或另一种会让你过的很糟糕。炒作可能很厉害,但请记住,你并不是在炒作业务(除非真的在炒作)。

试试Istio和Linkerd! Solo SuperGloo是最简单的方式。

我使用SuperGloo是因为它非常简单,可以快速启动两个服务网格,而我几乎不需要做任何努力。我们并没有在生产中使用它,但是它非常适合这样的任务。每个网格实际上是两个命令。

——Michael Kipper — Benchmarking Istio & Linkerd CPU — Shopify(https://medium.com/@michael_87395/benchmarking-istio-linkerd-cpu-c36287e32781)。



微信图片_20190429150753.png




在Solo.io(https://www.solo.io/),我们希望为你的服务网格采用之旅提供便利。 Solo SuperGloo我们的服务Mesh orchestrator可以通过直观简单的命令安装和管理流行的服务网格技术。 正如Michael上面所指出的那样,安装Istio或Linkerd会成为一个单行活动。 SuperGloo并不止于此,它在不同的服务网格技术之上提供了一个抽象,允许对多个网格进行一致且可重复的操作。 SuperGloo是完全开源的,you can try it right now(https://supergloo.solo.io/)。

本文由博云研究院原创翻译发表,转载请注明出处。

DockOne微信分享(二零八):华尔街见闻Istio生产实践

尼古拉斯 发表了文章 • 0 个评论 • 752 次浏览 • 2019-04-24 18:41 • 来自相关话题

【编者的话】随着见闻业务不断增加,所涉及语⾔也越来越多。由于微服务化的引入,就需要为不同语言开发各自的服务发现、监控、链路追踪等组件,更新运维成本较高。同时应用的灰度部署也是见闻在着⼒解决的问题。 Istio通过下沉基础设置,很好的解决了组件跨语言兼容问题, ...查看全部
【编者的话】随着见闻业务不断增加,所涉及语⾔也越来越多。由于微服务化的引入,就需要为不同语言开发各自的服务发现、监控、链路追踪等组件,更新运维成本较高。同时应用的灰度部署也是见闻在着⼒解决的问题。 Istio通过下沉基础设置,很好的解决了组件跨语言兼容问题, 同时带来了智能路由、服务熔断、错误注入等重要的特性。整个搭建过程中也遇到了很多坑和经验,希望和大家分享。

见闻开发团队以Golang为主,同时存在Python,Java服务,这就需要SRE提供更容易接入的微服务基础组件,常见的方案就是为每种语言提供适配的微服务基础组件,但痛点是基础组件更新维护的成本较高。

为了解决痛点,我们将目光放到服务网格,它能利用基础设施下沉来解决多语言基础库依赖的问题,不同的语言不需要再引入各种不同的服务发现、监控等依赖库,只需简单的配置并运行在给定的环境下,就能享有服务发现、流量监控、链路追踪等功能,同时网络作为最重要的通信组件,可以基于它实现很多复杂的功能,譬如智能路由、服务熔断降级等。

我们调研了一些服务网格方案,包括Istio、Linkerd。

对比下来,Istio拥有更多活跃的开源贡献者,迭代速度快,以及Istio架构可行性讨论,我们选择Istio作为实践方案。

服务网格架构图:
1.png

这张图介绍了华尔街见闻典型的服务网格架构,左半图介绍了用户请求是如何处理,右半图介绍运维系统是如何监控服务。
#架构可行性
通过架构图,我们拆分出以下关键组件,经过评估,Istio高度模块化、可拓展,各个组件的可用性、拓展性都有相应的策略达到保障,我们认为Istio是具有可实施性的。
##Istio Ingress高性能,可拓展

性能:Istio Ingress用来处理用户入流量,使用Envoy实现,转发性能高。


可用性:保证实例数量并使用服务探活接口保证服务可用性。


拓展性:挂载在负载均衡后,通过增加实例实现可拓展。


##Istio Proxy随应用部署,轻微性能损耗,可随应用数量拓展

Istio Proxy以Sidecar形式随应用一起部署,增加2次流量转发,存在性能损耗。


性能:4核8G服务器,上面运行Proxy服务和API服务,API服务只返回ok字样。(此测试只测试极限QPS)


单独测试API服务的QPS在59k+,平均延时在1.68ms,CPU占用4核。 通过代理访问的QPS6.8k+,平均延时14.97ms,代理CPU占用2核,API服务CPU占用2核。


CPU消耗以及转发消耗降低了QPS,增加了延时,通过增加机器核数并增加服务部署数量解决该问题,经过测试环境测试,延时可以接受。 


可用性:基于Envoy,我们认为Envoy的可用性高于应用。依赖Pilot Discovery进行服务路由,可用性受Pilot Discovery影响。


拓展性:Sidecar形式,随应用数拓展。


##Istio Policy服务可拓展,但同步调用存在风险

Istio Policy需要在服务调用前访问,是同步请求,会增加服务调用延时,通过拓展服务数量增加处理能力。属于可选服务,华尔街见闻生产环境未使用该组件。 


性能:未测试。


可用性:若开启Policy,必须保证Policy高可用,否则正常服务将不可用。


拓展性:增加实例数量进行拓展。

##Istio Telemetry监控收集服务

性能:从监控上观察Report 5000qps,使用25核,响应时间p99在72ms。异步调用不影响应用的响应时间。


可用性:Telemetry不影响服务可用性。


拓展性:增加实例数量进行拓展。

##Pilot Discovery

性能:服务发现组件(1.0.5版本)经过监控观察,300个Service,1000个Pod,服务变更次数1天100次,平均CPU消耗在0.04核左右,内存占用在1G以内。


可用性:在服务更新时需要保证可用,否则新创建的Pod无法获取最新路由规则,对于已运行Pod由于Proxy存在路由缓存不受Pilot Discovery关闭的影响。


拓展性:增加实例数量可以增加处理量。
#服务监控
Istio通过mixer来搜集上报的遥测数据,并自带Prometheus、Grafana等监控组件,可方便的对服务状态进行监控。见闻目前监控在用Istio自带的,利用Prometheus拉取集群指标,经由Grafana看板展示,可直观展示出各种全局指标及应用服务指标,包括全局QPS、全局调用成功率、各服务延时分布情况、QPS及状态码分布等, 基本满足监控所需。

存储暂未做持久化操作,采用Prometheus的默认的内存存储,数据的存储策略可通过设定Prometheus的启动参数`--storage.tsdb.retention`来设定,见闻生产时间设定为了6h。

Prometheus服务由于数据存储原因会消耗大量内存,所以在部署时建议将Prometheus部署在专有的大内存node节点上,这样如果内存使用过大导致该node节点报错也不会对别的服务造成影响。Istio mixer担负着全网的遥测数据搜集任务,容易成为性能瓶颈,建议和Prometheus一样将其部署在专有节点上, 避免出现问题时对应用服务造成影响。

以下是Mesh汇总面板的Demo:
2.jpg

Service Mesh汇总监控页面
#链路追踪
Envoy原生支持分布式链路追踪, 如Jaeger、Zipkin等,见闻生产选择了Istio自带的Jaeger作为自身链路追踪系统。 默认Jaeger服务为all_in_one形式,包含jaeger-collect、jaeger-query、jaeger-agent等组件,数据存储在内存中。

见闻测试集群采用了此种部署形式。见闻生产环境基于性能与数据持久性考虑,基于Cassandra存储搭建了单独的jaeger-collect、jaeger-query服务。Jaeger兼容Zipkin,可以通过设定Istio ConfigMap中的`zipkinAddress`参数值为jaeger-collector对应地址,来设置Proxy的trace上报地址。同时通过设置istio-pilot环境变量`PILOT_TRACE_SAMPLING`来设置tracing的采样率,见闻生产采用了1%的采样率。

Tracing不像Istio监控系统一样对业务代码完全无侵入性。Envoy在收发请求时若发现该请求没有相关trace headers,就会为该请求自动创建。tracing的实现需要对业务代码稍作变动,这个变动主要用来传递trace相关的header,以便将一次调用产生的各个span串联起来。

见闻底层采用 grpc 微服务框架,在Gateway层面将trace header 加入到入口grpc调用的context中,从而将trace headers 逐级传递下去。
3.jpg

#Istio探活
Istio通过向Pod注入Sidecar接管流量的形式实现服务治理,那么就会有Sidecar与业务容器状态不同步的可能,从而造成各种的调用问题,如下两方面:

* Sidecar就绪时间晚于业务容器:业务容器此时若发起调用,由于Sidecar还未就绪, 就会出现类似no healthy upstream之类错误。若此时该Pod接收请求,就又会出现类似upstream connect error错误。
* Sidecar就绪时间早于业务容器:例如某业务容器初始化时间过长导致Kubernetes误以为该容器已就绪,Sidecar开始进行处理请求,此时就会出现类似upstream connect error错误。

4.jpg

5.jpg

探活涉及Sidecar、业务容器两部分,只有两部分同时就绪,此Pod才可以正式对外提供服务,分为下面两方面:

* Sidecar探活:v1.0.3及以上版本针对Pilot-agent新增了一个探活接口healthz/ready,涉及statusPort、applicationPorts、adminPort等三个端口。其基本逻辑为在statusPort上启动健康监测服务,监听applicationPorts设定的端口是否至少有一个成功监听,之后通过调用本地adminPort端口获取xDS同步状态。若满足至少一个applicationPort成功监听,且CDS、LDS都进行过同步,则该Sidecar才被标记为Ready。
* 业务容器探活:见闻通过基本库,在所有Golang grpc后端服务中注册了一个用于健康检查的handler, 该handler可由开发人员根据自身业务自定义,最后根据handler返回值来判断业务容器状态(如下图)。

6.jpg

#Istio应用更新
为了实现灰度部署,见闻基于Kubernetes Dashboard进行了二次开发,增加了对Istio相关资源的支持,利用Gateway、VirtualService、DestinationRule等crd实现了应用程序的灰度部署,实际细节如下:

1. 更新流量控制将流量指向已有版本
,利用VirtualService将流量全部指向v1版本(见下动图)。
2. 部署新版本的Deployment
,查找旧的Deployment配置,通过筛选app标签符合应用名的Deployment,运维人员基于该Deployment创建v2版本的Deployment,并向destinationRule中增加v2版本。
3. 更新流量控制将流量指向新版,本
利用VirtualService将ServiceA的服务流量全部指向v2版本。
4. 下线老版本的Deployment并删除对应DestinationRule。

利用Istio Dashboard来实现上述流程:
07.gif

为了方便开发人员服务部署,开发了精简版后台,并对可修改部分进行了限定。最终,SRE提供两个后台,对Istio Dashboard进行精细控制:
08.gif

#实践中的宝贵经验
在Istio实践过程中,有哪些需要注意的问题。
##API server的强依赖,单点故障

Istio对Kubernetes的API有很强的依赖,诸如流量控制(Kubernetes资源)、集群监控(Prometheus通过Kubernetes服务发现查找Pod)、服务权限控制(Mixer Policy)。所以需要保障API server的高可用,我们曾遇到Policy组件疯狂请求Kubernetes API server使API server无法服务,从而导致服务发现等服务无法更新配置。



* 为避免这种请求,建议使用者了解与API server直接通信组件的原理,并尽量减少直接通信的组件数量,增加必要的Rate limit。


* 尽量将与API server通信的服务置于可以随时关闭的环境,这是考虑如果部署在同一Kubernetes集群,如果API server挂掉,无法关闭这些有问题的服务,导致死锁(又想恢复API server,又要依靠API server关闭服务)。

##服务配置的自动化

服务配置是Istio部署后的重头戏,避免使用手动方式更改配置,使用代码更新配置,将常用的几个配置更新操作做到运维后台,相信手动一定会犯错。
##关于Pilot Discovery

Pilot Discovery 1.0.0版本有很大的性能问题,1.0.4有很大的性能提升,但引入了一个新bug,所以请使用1.0.5及以上的版本,我们观察到CPU消耗至少是1.0.0版本的1/10,大大降低了Proxy同步配置的延时。
##关于Mixer Policy 1.0.0

这个组件曾导致API server负载过高(很高的list pods请求),所以我们暂时束之高阁,慎用。
##性能调优

在使用Proxy、Telemetry时,默认它们会打印访问日志,我们选择在生产上关闭该日志。
时刻观察Istio社区的最新版本,查看新版本各个组件的性能优化以及bug修复情况,将Istio当做高度模块化的系统,单独升级某些组件。上面就提到我们在Istio1.0的基础上使用了1.0.5版本的Policy、Telemetry、Pilot Discovery等组件。
##服务平滑更新和关闭

Istio依靠Proxy来帮助APP进行路由,考虑几种情况会出现意外的状态:


* APP启动先于Proxy,并开始调用其它服务,这时Proxy尚未初始化完毕,APP调用失败。


* Service B关闭时,调用者Service A的Proxy尚未同步更新Service B关闭的状态,向Service B发送请求,调用失败。
第一种情况要求APP有重试机制,能适当重试请求,避免启动时的Proxy初始化与APP初始化的时差,Istio提供了retry次数配置,可以考虑使用。 
第二种情况,一种是服务更新时,我们使用新建新服务,再切流量;一种是服务异常退出,这种情况是在客户端重试机制。希望使用Istio的开发人员有更好的解决方案。

#Q&A
Q:学Service Mesh什么用?
A:Service Mesh是最近比较火的一个概念,和微服务、Kubernetes有密切关系。出于以后业务发展需要,可以学习下, 增加知识储备。见闻上Istio的主要目的在文章已说明,主要是基础服务的下沉,解决了语言兼容性问题, 还有一个就是灰度发布。

Q:链路追踪的采集方式是怎样的,比如Nodejs,C++等多语言如何支持的?
A:Envoy本身支持链路追踪,也就是将Envoy会在请求head中增加链路追踪相关的数据头,比如x-b3-traceid,x-b3-spanid等等。业务要做的就是将这些head沿着调用链路传递下去即可。所以多语言的话需要在自己的业务侧实现该逻辑。所以Istio的链路追踪对业务代码还是有很小的侵入性的(这个分享中有说明)。

Q:Istio与Spring Cloud两者的优缺点与今后的发展趋势会是怎么样?
A:见闻技术栈是Golang,所以没太认真对比过两者。从社区活跃度上将,Istio > Spring Cloud,稳定性方面,Spring Cloud是更有优势,更适合Java沉淀较深的企业。但个人感觉对于更多企业来讲,跨越了语言兼容性的Istio未来发展很值得期待。

Q:Docker镜像部署可以做到代码保护吗,比如像Nodejs这种非二进制执行程序的项目?
A:代码保护可以通过将镜像上传至指定云服务商上的镜像仓库中,见闻是将自己的业务镜像提交保存在了腾讯云。如果镜像泄露,那么非二进制执行程序的代码还是有泄露风险的。

Q:选型时为什么没考虑Linkerd?
A:选型之初也调研了Linkerd, 对比下来,Istio拥有更多活跃的开源贡献者,迭代速度快,以及Istio架构相较于见闻有较大可行性,所以选择了Istio作为实践方案。

Q:Istio在做运维部署时没有UI工具,你们如何实现运维人员更加便捷地使用?
A:见闻基于Kubernetes官方的Dashboard, 对内容进行了扩充,增加了对Gateway,VirtualService等Istio crd资源的支持, 同时增加了灰度部署等和见闻运维业务相关的功能,所以一定程度上解决了运维部署的问题。

Q:流量从Sidecar代理势必会对请求响应时间有影响,这个有没有更详细案例的说明性能上的损耗情况?
A:Sidecar的转发其实带来了性能一定的性能损耗。4核8G服务器,上面运行Proxy服务和API服务,API服务只返回ok字样。(此测试只测试极限QPS)单独测试API服务的QPS在59k+,平均延时在1.68ms,CPU占用4核。通过代理访问的QPS6.8k+,平均延时14.97ms,代理CPU占用2核,API服务CPU占用2核。 CPU消耗以及转发消耗降低了QPS,增加了延时,通过增加机器核数并增加服务部署数量缓解该问题,经过测试环境测试,延时可以接受。

Q:Sidecar在生产中资源占用为多少?是否会对集群资源占用很多?
A:以单个Pod为例,见闻业务单个Pod中Sidecar所占资源约占整个Pod所耗资源的1/10。

Q:Jeager你们是进行了代码埋点吗?更为底层代码级别的追踪,有用其他方案吗?
A:Envoy本身对tracing有良好的支持,所以业务端所做的改动只需将其所产生的追踪数据延续下去即可。上Istio之前,见闻在相关微服务中通过在基础库中增加链路追踪逻辑(Zipkin)实现了链路追踪,不过只做了Golang版,多语言兼容开发运维难度较大。

Q:相信咱们的mixer在生产环境中,也出现过瓶颈,咱们从哪几个大方向优化的?如何优化的?方面讲解一下吗?
A:mixer见闻在生产过程中所遇的坑在于Policy组件, 会疯狂的list pod,导致API server负载骤增,之后见闻基于自身业务关闭了Policy。

Q:Istio组件实现了高可用么?
A:Istio本身也是基于Kubernetes,所以可用性还是有较好保证的。

以上内容根据2019年4月23日晚微信群分享内容整理。分享人张安伟,华尔街见闻SRE团队运维工程师,负责公司日常运维开发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

基于Kubernetes的微服务可观测性和Istio服务网格(二)

dummy 发表了文章 • 0 个评论 • 524 次浏览 • 2019-04-22 17:01 • 来自相关话题

在本系列文章中,我们将继续探索可观测性工具集,这些工具集作为最新的Istio服务网格中的一部分,包含了Prometheus和Grafana用于度量指标收集、监控和警报,Jaeger用于分布式跟踪,以及Kiali为Istio提供基于服务网格的微服务可视化。同时结 ...查看全部
在本系列文章中,我们将继续探索可观测性工具集,这些工具集作为最新的Istio服务网格中的一部分,包含了PrometheusGrafana用于度量指标收集、监控和警报,Jaeger用于分布式跟踪,以及Kiali为Istio提供基于服务网格的微服务可视化。同时结合云平台原生的监控和日志记录服务,例如谷歌云平台上Google Kubernetes Engine(GKE)Stackdriver,我们为现代分布式应用程序提供了完整的可观测性解决方案。
# 参考平台
为了演示Istio的可观测性工具,在系列的第一部分中,我们部署一个参考平台,包含了8个基于Go的微服务,以服务A-H来标识,1个Angular 7基于TypeScript的前端,4个MongoDB数据库实例和一个RabbitMQ队列用于基于事件队列的通信。
1.png

该参考平台旨在生成基于HTTP的服务到服务,基于TCP的服务到数据库以及基于TCP的服务到队列再到服务(RabbitMQ)的IPC(进程间通信)。服务A调用服务B和C,服务B调用服务D和E,服务D生产消息到RabbitMQ队列供服务F来消费并写入到MongoDB,依此类推。目标是在将系统部署到Kubernetes时使用Istio的可观测性工具来观察这些分布式通信。
# 日志记录
我们在第一部分说到,日志、指标和跟踪通常被称为可观测性的三大核心支柱。当我们在GCP上使用GKE时,我们能利用谷歌云的Stackdriver Logging产品。据谷歌宣称, Stackdriver Logging允许你存储、搜索、分析、监控和根据来自GCP甚至是AWS的数据和事件来进行告警。虽然Stackdriver Logging不包含在Istio可观测性功能中,但是日志记录是整体可观测性策略的重要核心之一。
## 基于Go语言的微服务日志记录
有效的日志记录策略包含了记录的内容,何时记录以及如何记录。作为我们的日志记录策略的一部分,八个基于Go的微服务使用了Logrus,这是一个流行的结构化记录日志组件。这些微服务同时还实现了Banzai Cloud的logrus-runtime-formatter,关于这个日志插件有一篇优秀的文章:《Golang runtime Logrus Formatter》。这两个日志记录软件包能让我们更好地控制记录的内容,何时记录和如何记录关于我们的微服务的信息。使用这个软件包需要的配置也相当少。
func init() {
formatter := runtime.Formatter{ChildFormatter: &log.JSONFormatter{}}
formatter.Line = true
log.SetFormatter(&formatter)
log.SetOutput(os.Stdout)
level, err := log.ParseLevel(getEnv("LOG_LEVEL", "info"))
if err != nil {
log.Error(err)
}
log.SetLevel(level)
}

Logrus比Go内置的简单的日志包log提供多了几个优点。日志不仅只记录致命性错误,同时我们也不应该在生产环境中输出所有明细的日志。本文中涉及到的微服务利用了Logrus的七种日志级别:Trace、Debug、Info、Warning、Error、Fatal和Panic。我们还将日志级别作为变量,允许在部署时在Kubernetes Deployment资源中轻松更改它。

这些微服务同时还利用了Banzai Cloud的logrus-runtime-formatter。这个格式化工具能自动地给日志消息标记上运行时/堆栈信息,包括函数名和代码行号,这些信息在排除故障时非常有用。我们也使用了Logrus的JSON日志格式。注意下面的日志条目是如何将JSON有效负载包含在消息中的。
2.png

## 客户端层面的UI日志记录
同样地,我们使用NGX Logger增强了Angular UI的日志记录。NGX Logger是一个流行,简单的日志记录模块,目前用于Angular 6和7。它能将控制台输出打印得更好看,并允许将被POST到某个服务端URL的消息记录下来。在这次演示中,我们只将日志打印到控制台。与Logrus类似,NGX Logger也支持多种日志级别:Trace、Debug、Info、Warning、Error、Fatal和关闭。NGX Logger不仅可以输出消息,还允许我们将日志条目以合适的格式输出到Web浏览器的控制台。

日志输出级别取决于不同的环境,生产与非生产。下图我们可以看到在本地开发环境中的日志条目,包括了Debug、Info和Error级别。
3.png

在下图基于GKE的生产环境中我们能看到相同的页面。但是请注意,我们无需修改任何配置,Debug级别的日志条目将不会输出到控制台中。我们不希望暴露包含潜在敏感信息的日志给生产环境的终端用户。
4.png

通过将以下三元运算符添加到app.module.ts文件中来实现控制日志记录级别。
LoggerModule.forRoot({
level: !environment.production ? NgxLoggerLevel.DEBUG : NgxLoggerLevel.INFO,
serverLogLevel: NgxLoggerLevel.INFO
})

# 指标
关于指标,我们来看看PrometheusGrafana。这两个先进的工具已作为Istio部署的一部分被安装。
## Prometheus
Prometheus是一个完全开源和社区型驱动的系统监控和告警工具,大约在2012年SoundCloud创建了这个项目。有趣的是,Prometheus于2016年加入云原生计算基金会(CNCF)作为第二个托管项目,众所周知第一个是Kubernetes

根据Istio文档说明,Istio的Mixer中内置了一个Prometheus适配器,它可以暴露一个用于服务那些生成的度量值的端点。这里所说的Prometheus附加组件是一个预先配置了去收集Mixer端点上暴露的指标的Prometheus服务器。它提供了持久存储和查询Istio指标的机制。

GKE集群已跑起来,Istio也已安装,平台已部署,那怎么访问Prometheus?最简单的方法是使用`kubectl port-forward`来连接到Prometheus服务器。根据Google的说法,Kubernetes的端口转发从v1.10版本以后允许使用资源名称(例如服务名称)来选择匹配的Pod。我们将本地端口转发到Prometheus Pod上的端口。
5.png

你可以使用Google Cloud Shell进行连接,也可以将命令复制粘贴到本地shell以从本地端口进行连接。以下是本文中使用的端口转发命令。
# Grafana
kubectl port-forward -n istio-system \
$(kubectl get pod -n istio-system -l app=grafana \
-o jsonpath='{.items[0].metadata.name}') 3000:3000 &

# Prometheus
kubectl -n istio-system port-forward \
$(kubectl -n istio-system get pod -l app=prometheus \
-o jsonpath='{.items[0].metadata.name}') 9090:9090 &

# Jaeger
kubectl port-forward -n istio-system \
$(kubectl get pod -n istio-system -l app=jaeger \
-o jsonpath='{.items[0].metadata.name}') 16686:16686 &

# Kiali
kubectl -n istio-system port-forward \
$(kubectl -n istio-system get pod -l app=kiali \
-o jsonpath='{.items[0].metadata.name}') 20001:20001 &

Prometheus文档中写道,用户可使用名为PromQL(Prometheus查询语言)的函数查询语言来实时选择和汇总时间序列数据。查询表达式的结果可在Prometheus的Web UI中显示为表格数据并绘制为图形,也可以通过Prometheus的HTTP API由外部系统使用。Web UI界面包含了一个下拉菜单,其中包含所有可用指标作为构建查询的基础。下面显示的是本文中使用的一些PromQL示例。
up{namespace="dev",pod_name=~"service-.*"}
container_memory_max_usage_bytes{namespace="dev",container_name=~"service-.*"}
container_memory_max_usage_bytes{namespace="dev",container_name="service-f"}
container_network_transmit_packets_total{namespace="dev",pod_name=~"service-e-.*"}
istio_requests_total{destination_service_namespace="dev",connection_security_policy="mutual_tls",destination_app="service-a"}
istio_response_bytes_count{destination_service_namespace="dev",connection_security_policy="mutual_tls",source_app="service-a"}

在下图显示的Prometheus控制台中,我们看到了部署到GKE的八个基于Go的微服务的示例图。该图显示了五分钟内的容器内存使用情况。在一半的时间内,服务处于休息状态。另一半时间区域,服务使用了`hey`工具来模拟负载。查看负载下服务的内存简况可以帮助我们确定容器内存最小值和限制,这会影响Kubernetes在GKE集群上的工作负载调度。诸如此类的度量标准也可能会发现内存泄漏或路由问题,例如下面的服务,它似乎比同类服务消耗的内存多25-50%。
6.png

下面的另一个例子,这个图表表示系统处于负载状态下`dev`命名空间中对服务A的总的Istio请求。
7.png

比较上面的图表视图与控制台视图中显示的相同指标,多个指标显示了在检测的五分钟周期内,`dev`命名空间里的服务A的多个实例。各个度量标准元素中的值指出了收集到的最新度量标准。
8.png

Prometheus同时还收集有关Istio组件,Kubernetes组件和GKE集群的基本指标。下面我们可以查看GKE集群中每个n1-standard-2虚机节点的总内存。
9.png

## Grafana
Grafana自称是一个先进的时间序列分析开源软件。根据Grafana Labs的说法,Grafana允许你查询,可视化,提醒和了解熟悉你的指标,无论它们是存放在哪里。你可以轻松创建,浏览并共享具有丰富视觉效果的以数据驱动的仪表板。Grafana还能直观地让你为那些最重要的指标定义警报规则,它将不断评估规则并发送通知。

Istio文档中写到,Grafana附加组件其实是一个预先配置好的Grafana实例。Grafana的容器基础镜像已被修改为支持Prometheus数据源和适配到Istio仪表板。Istio的基本安装文件,特别是Mixer,包含了一个默认的全局的(用于每个服务)度量标准的配置。预配置的Istio仪表板可与默认的Istio指标配置和Prometheus后端结合使用。

我们在下图可以看到预先配置的Istio负载仪表板。较大的仪表板的特定部分已过滤用于显示在GKE集群中`dev`命名空间中的出站服务指标。
10.png

同样,在下面我们看到预先配置的Istio服务仪表板。较大的仪表板的特定部分已过滤用以显示GKE集群中Istio Ingress Gateway的客户端工作负载指标。
11.png

最后,我们看到预配置的Istio网格仪表板。此仪表板同样已过滤用以显示部署到GKE集群的组件的度量标准的表格视图。
12.png

有效的可观测性策略一定不仅仅包括可视化结果的能力,还必须包括异常检测并通知(警报)合适的资源或直接采取行动以解决事件的能力。像Prometheus一样,Grafana能够发出警报和通知。你可以直观地为关键指标定义警报规则。Grafana将根据规则不断评估指标,并在违反预定义阈值时发送通知。

Grafana支持多种流行的通知渠道,包括PagerDuty、HipChat、Email、Kafka和Slack。下面是一个新的通知频道,它向Slack支持频道发送警报通知。
13.png

Grafana能够发送详细的基于文本和视图的通知。
14.png

# 链路跟踪
根据Open Tracing网站介绍,分布式跟踪(也称为分布式请求跟踪)是一种用于分析和监控应用程序的方法,尤其是那些使用微服务架构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。

Istio中说到,尽管Istio中的代理程序能够自动发送span信息,但应用程序需要能传播适当的HTTP头信息,这样当代理发送span时,该span可以正确地关联到单个跟踪中。为此,应用程序需要收集传入请求中的以下头部并将其传播到任何传出的请求。

  • `x-request-id`
  • `x-b3-traceid`
  • `x-b3-spanid`
  • `x-b3-parentspanid`
  • `x-b3-sampled`
  • `x-b3-flags`
  • `x-ot-span-context`

`x-b3`头部一开始作为Zipkin项目的一部分。标题的B3部分以Zipkin的原始名称BigBrotherBird命名。在服务调用之间传递这些标头称为B3传播。根据Zipkin文档,这些属性在进程间传播,最终在下游(通常通过HTTP头)传播,以确保来自同一根的所有活动被收集在一起。

为了演示Jaeger的分布式跟踪,我修改了服务A,服务B和服务E,这三个服务会向其他上游服务发出HTTP请求。我添加了以下代码以便将标头从一个服务传播到下一个服务。Istio的边车代理,即Envoy生成第一个报头。至关重要的是,你只需传播下游请求中存在且包含值的标头,如下代码所示。传播任何一个空的请求头将破坏分布式跟踪。
headers := []string{
"x-request-id",
"x-b3-traceid",
"x-b3-spanid",
"x-b3-parentspanid",
"x-b3-sampled",
"x-b3-flags",
"x-ot-span-context",
}
for _, header := range headers {
if r.Header.Get(header) != "" {
req.Header.Add(header, r.Header.Get(header))
}
}

下图在高亮的Stackdriver日志条目的JSON有效负载中,我们看到从根span传播所需的头部,其中包含一个值,在上游请求中从服务A传递到服务C。
15.png

## Jaeger
Jaeger是受DapperOpenZipkin启发,是Uber科技开源的一套分布式跟踪系统。它用于监控和为基于微服务的分布式系统提供故障排除功能,包括了分布式上下文传播、分布式事务监控、根源分析、服务依赖性分析以及性能和延迟优化。Jaeger网站对Jaeger的架构和通用的跟踪相关术语进行了很好的概述。

下面我们看到Jaeger UI的Traces(跟踪)页面。其显示在大约四十分钟时间内搜索Istio Ingress Gateway服务的结果。我们在顶部看到了跟踪时间线,下面是跟踪结果列表。正如Jaeger网站上所讨论的,跟踪由span组成。span表示Jaeger中具有操作名称的逻辑工作单元。一次跟踪代表了通过系统的执行路径,可以被认为是有向无环图(DAG)或span。如果你曾使用过类似Apache Spark这样的系统,那么你可能已经很熟悉DAG是什么。
16.png

下面我们看到Jaeger UI的Trace Detail(跟踪详情)页面。该示例跟踪包含16个span,其中包含八个服务,七个基于Go的服务和一个Istio Ingress Gateway。跟踪和span都有各自的时间记录。跟踪中的根span是Istio Ingress Gateway。在终端用户的Web浏览器中加载的Angular UI通过Istio Ingress Gateway调用网格边缘服务A。从这一步开始,我们看到了服务到服务间IPC的预期流程。服务A调用服务B和C,服务B调用服务E,E又调用服务G和服务H。在该演示中,跟踪不贯穿RabbitMQ消息队列。这意味着你不能从RabbitMQ中看到包含从服务D到服务F的调用的跟踪。
17.png

在Jaeger UI跟踪详情页中,你还可以定位到包含其他元数据的单个范围。元数据包括被调用的URL、HTTP方法、响应状态和其他几个头部信息。
18.png

Jaeger的最新版本还包括Compare(对比)功能和两个Dependencies(依赖)视图,力导向图和DAG。我发现这两种视图与Kiali相比比较原始,与Service Graph更相似。在Kiali成为可能之前,这些作为依赖图来说非常有用。
19.png

# Kiali:微服务观测
Kiali网站上,我们大部分人对服务网格存在的问题得到了解答:我的Istio服务网格中有哪些微服务,它们是如何连接的?这里通过一个通用的Kubernetes Secret对象来控制对Kiali API和UI的访问。默认登录名是`admin`,密码是`1f2d1e2e67df`。
20.png

登录到Kiali后,我们能看到Overview菜单条目,它提供了Istio服务网格中所有命名空间的全局视图以及每个命名空间中的应用程序数。
21.png

Kiali UI中的图形视图是在Istio服务网格中运行的组件的直观展示。下面,对集群的`dev`命名空间进行过滤,我们可以观察到Kiali映射了8个应用程序(工作负载),10个服务和24个边界(图形术语)。具体来说,我们看到服务网格边缘的Istio Ingress代理、Angular UI、八个基于Go的微服务及其处理流量的Envoy代理边车(在此示例中服务F没有从其他服务直接获取流量),外部MongoDB Atlas集群和外部CloudAMQP集群。注意服务到服务的流量走向,通过Istio是如何从服务流向其边车代理再流向另一个服务的边车代理,最后到达其他服务。
22.png

下面,我们看到了服务网格的类似视图,但此时Istio Ingress网关和服务A之间存在故障,以红色显示。我们还可以观察HTTP流量的总体指标,例如每分钟共多少请求,错误和状态代码。
23.png

Kiali还可以显示图表中每个边界的平均请求时间和其他指标(即两个组件之间的通信)。
24.png

Kiali还可以显示部署的应用程序版本,如下所示,微服务中包含了版本1.3和1.4。
25.png

再说到外部的MongoDB Atlas集群,Kiali还允许我们查看在服务网格中的四个服务与外部集群的TCP流量。
26.png

“Applications(应用)”菜单列表列出了所有应用程序及其错误率,可以按命名空间和时间间隔进行筛选。在这里,我们看到Angular UI以16.67%的速率产生错误。
27.png

在Applications跟Workloads菜单条目中,我们可以深入查看组件以查看其详细信息,包括总体运行状况,Pod数量,服务和目标服务。下面我们可以查看在`dev`命名空间中服务B的详细信息。
28.png

Workloads详细视图还包括入站和出站指标。下面是`dev`命名空间中服务A的出站流量,持续时间和大小度量标准。
29.png

最后,Kiali还提供了一个Istio Config菜单。Istio Config菜单显示用户环境中存在的所有可用Istio配置对象的列表。
30.png

通常情况下,Kiali是我在解决平台问题时的第一个工具。一旦我确定了有问题的特定组件或通信路径,我就可以搜索Stackdriver日志和通过Grafana仪表板搜索Prometheus指标。
# 结论
在本系列文中,我们探索了当前最新版本的Istio服务网格中的一部分,可观测性工具集。它包括了Prometheus和Grafana,用于度量指标收集,监控和警报,Jaeger用于分布式跟踪,以及Kiali提供给Istio基于服务网格的微服务可视化。结合云平台本地监控和日志记录服务,例如谷歌云平台(GCP)上的Google Kubernetes Engine(GKE)Stackdriver,我们为现代分布式应用程序提供了完整的可观测性解决方案。

原文链接:Kubernetes-based Microservice Observability with Istio Service Mesh: Part 2(翻译:冯旭松)

基于Kubernetes的微服务可观测性与Istio服务网格(一)

dummy 发表了文章 • 0 个评论 • 783 次浏览 • 2019-04-19 15:40 • 来自相关话题

本系列文章将分为两部分,在此我们将探讨Istio服务网格中一部分,即可观测性工具集。这些工具包含了Jaeger、Kiali、Prometheus以及Grafana。为辅助我们此行探索,我们将在GCP上部署基于Go的微服务参考平台到GKE上去。 ...查看全部
本系列文章将分为两部分,在此我们将探讨Istio服务网格中一部分,即可观测性工具集。这些工具包含了Jaeger、Kiali、Prometheus以及Grafana。为辅助我们此行探索,我们将在GCP上部署基于Go的微服务参考平台到GKE上去。
1.png

# 什么是可观测性
与区块链、无服务器、AI和机器学习、聊天机器人、网络安全和服务网格类似,可观测性现在是IT行业中的一大热门话题。根据维基百科记录,可观测性指的是如何从外部输出来推断衡量系统内部状态。日志、指标和跟踪通常被成为可观测性的三大核心支柱。这些是我们可观察到的系统的外部输出。

由Cindy Sridharan撰写,O’Reilly出版的分布式系统可观测性一书在第四章节中详细地介绍了“可观测性的三大支柱”。在继续下文之前,我强烈建议你阅读下这篇在线摘录。关于可观测性资讯的另一大来源是honeycomb.io,一个生产系统可观测性工具的开发商,由知名的行业思想领袖Charity Majors领导。这个站点上面发布了很多关于可观测性的文章、博文、白皮书和博客。

随着现代分布式系统变得越发复杂,想具备观察这些系统的能力需要同样在设计之初就考虑到适配如此复杂环境的现代化的工具。传统的日志记录和监控系统通常与当今的混合和多云、基于多种语言、事件驱动、基于容器和无服务器、可无限扩展的、临时计算的平台相竞争。

Istio服务网格这类工具试图通过提供与几种同类最佳的开源遥测工具的原生集成方案来解决可观测性带来的挑战。Istio的集成包括Jaeger用于分布式跟踪,Kiali用于分布式系统可视化,PrometheusGrafana用于度量指标收集、监控和警报。同时结合云平台原生的监控和日志服务,例如谷歌云平台上Google Kubernetes Engine(GKE)Stackdriver,我们为现代化的分布式应用打造完整的可观测平台。
# 一个供参考的微服务平台
为了演示与最新版本的Istio服务网格集成的可观测性工具,我们将部署一个具备参考意义的,使用Go编写的微服务平台到GKE上面去。我开发了相关参考服务平台来演示涉及到的概念,例如API管理、服务网格、可观测性、DevOps和混沌工程等。该平台由14个组件组成,包含了8个基于Go的微服务,以服务A-H来标记,一个Augular 7,基于TypeScript的前端,4个MongoDB数据库实例,一个RabbitMQ队列用于基于事件队列的通信。该平台以及所有代码都已开源。

该参考平台旨在生成基于HTTP的服务到服务,基于TCP的服务到数据库以及基于TCP的服务到队列再到服务(RabbitMQ)的IPC(进程间通信)。服务A调用服务B和C,服务B调用服务D和E,服务D生产消息到RabbitMQ队列供服务F来消费并写入到MongoDB,依此类推。当这个系统部署到运行Istio服务网格的Kubernetes集群中时,可以使用Istio的可观测性工具来观察这些分布式通信。
## 服务响应
在该平台上,每个上游服务通过返回一个小的JSON信息负载(在源码中称为问候语)来响应下游服务的请求。
2.png

这些请求响应在调用链中聚合,进而产生给边缘服务的一系列服务响应,并返回给UI界面,最终展示在用户的浏览器中。响应聚合功能只是简单验证服务到服务间通信,Istio组件和遥测工具都能否正常工作。
3.png

所有的Go微服务都包含一个`/ping`和`/health`端点。`/health`端点用于配置Kubernetes的存活以及就绪探针。此外,边缘服务A使用响应头`access-control-allow-origin: *`用来配置Cross-Origin Resource Sharing(CORS)。CORS允许用于浏览器来调用位于与UI不同子域的`/ping`端点。相关服务A的源码可以在此查看。

在本次演示中,MongoDB数据库将被托管到GCP的外部,即MongoDB Atlas,它是一个基于云的MongoDB即服务平台。同样的,RabbitMQ队列服务将被托管到CloudAMQP,这是一个基于云的RabbitMQ即服务平台。我曾在之前的几篇文章中使用过这两种Saas供应商。使用外部服务将帮助我们了解Istio和它的可观测性工具是如何为位于Kubernetes集群中和外部系统的通信提供遥测的。

服务F消费来自RabbitMQ队列的消息,服务D将消息写入队列并写入到MongoDB中,这些服务都能通过对应链接打开直接查看源码。
# 源码
所有本文涉及到的源码都可以在GitHub的两个项目中找到。基于Go的微服务的源码,所有的Kubernetes资源和部署脚本都位于k8s-istio-observe-backend这个项目仓库中。Angular UI前端项目源码位于k8s-istio-observe-frontend中。此次演示中你将不需要下载前端项目。
git clone --branch master --single-branch --depth 1 --no-tags \
https://github.com/garystafford/k8s-istio-observe-backend.git

Kubernetes资源中引用到的相关Go服务和UI界面的容器镜像,都可以在Docker Hub上找到。Go服务镜像是使用官方的Golang Alpine来作为基础镜像,包含了Go 1.12.0版本。使用Alpine镜像来编译源码将能保证容器镜像尽可能地小并且包含更小的可攻击面。
# 系统要求
文章接下来的部分,你需要将最新版本的`gcloud`的客户端工具(最小版本要求为239.0.0)、Helm和刚刚发布的Istio 1.1.0版本安装并配置在你的本地或者是构建机器上。
4.png

# 配置和安装
为了将该微服务平台部署到GKE,我们将按以下步骤进行:

  1. 创建MongoDB Atlas数据库集群
  2. 创建CloudAMQP RabbitMQ集群
  3. 根据自己的环境调整Kubernetes的资源文件和脚本
  4. 在GCP上创建GKE集群
  5. 使用Helm在GKE集群中部署Istio 1.1.0版本
  6. 为平台中需要暴露访问的资源创建DNS记录
  7. 部署所有Go微服务,Angular UI和与GKE相关联的资源
  8. 测试或为你的平台排障
  9. 在第二篇中查看观察的结果

# MongoDB Atlas集群
MongoDB Atlas是一个完全托管的MongoDB即服务,可在AWS、Azure和GCP上使用。Atlas是一款成熟的SaaS产品,提供高可用性,有保证的正常运行时间SLA,弹性可扩展性,跨区域复制,企业级安全性,LDAP集成,BI连接器等等。

MongoDB Atlas目前提供有四种定价方案,包含免费版、基础版、高级版和企业版。这些方案范围从最小的共享内存和512MB存储的M0规模的MongoDB集群,到最高具有488GB内存和3TB存储的大型M400 MongoDB集群。

在本文中,我在GCP的us-central1地区创建了一个M2大小的MongoDB集群,并为该演示创建了一个数据库账户,该帐户将用于连接GKE上运行的八个基于Go的微服务的其中四个。
5.png

最初我使用了一个M0大小的集群,但发现计算资源不足以支撑来自这些Go语言的微服务。在此我建议至少使用M2大小乃至更大的集群。
# CloudAMQP RabbitMQ集群
CloudAMQP在所有主流云供应商和应用程序平台上提供完全托管的RabbitMQ集群。RabbitMQ将支持一部分基于Go的微服务的解耦,最终一致的基于消息的架构。在本文中,我同样在GCP的us-central1区域创建了一个RabbitMQ集群,与我们的GKE集群和MongoDB Atlas集群相同,我选择了一个最低配置的RabbitMQ免费版本。CloudAMQP还提供强大的多节点RabbitMQ集群以供生产级别环境使用。
# 修改配置
在GitHub项目中的Kubernetes资源文件和Bash部署脚本中你需要对应调整部分配置设置。
## 配置MongoDB Atlas的Istio ServiceEntry
external-mesh-mongodb-atlas.yaml文件中添加MongoDB Atlas主机地址。此文件允许从GKE上的四个微服务到外部MongoDB Atlas集群的出口流量。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: mongodb-atlas-external-mesh
spec:
hosts:
- {{ your_host_goes_here }}
ports:
- name: mongo
number: 27017
protocol: MONGO
location: MESH_EXTERNAL
resolution: NONE

## 配置CloudAMQP RabbitMQ的Istio ServiceEntry
external-mesh-cloudamqp.yaml文件中添加CloudAMQP主机地址,此文件允许从两个微服务到CloudAMQP群集的出口流量。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: cloudamqp-external-mesh
spec:
hosts:
- {{ your_host_goes_here }}
ports:
- name: rabbitmq
number: 5672
protocol: TCP
location: MESH_EXTERNAL
resolution: NONE

## Istio Gateway和VirtualService
通过Istio你可以有许多策略用于配置路由流量。此文中我使用了example-api.com这个域名,还有4组子域名。一组子域用于Angular UI,分别是dev命名空间(ui.dev.example-api.com)和test命名空间(ui.test.example-api.com)。另一组子域用于边缘API微服务,即被UI界面调用的服务A(api.dev.example-api.comapi.test.example-api.com)。流量将根据URL路由到特定的Kubernetes服务去。

Istio中所定义的Gateway对象描述了一个在网格边缘操作的负载均衡器,它负责接收传入或传出的HTTP/TCP连接。修改Istio ingress Gateway,在该hosts部分中插入你自己的域名或子域,这些是端口80上允许进入网格的主机。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: demo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- ui.dev.example-api.com
- ui.test.example-api.com
- api.dev.example-api.com
- api.test.example-api.com

Istio中的VirtualService定义了一组主机域名被寻址时应用的流量路由规则。一个VirtualServiceGateway绑定来控制到达特定主机和端口的流量的转发。修改项目中的4个VirtualServices,将你的域名或子域添加进去。以下是在istio-gateway.yaml中一个VirtualService的例子。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: angular-ui-dev
spec:
hosts:
- ui.dev.example-api.com
gateways:
- demo-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
host: angular-ui.dev.svc.cluster.local

## Kubernetes Secret
该项目中包含了一个Kubernetes Secret对象,go-srv-demo.yaml文件中指定了两个键值,一个用于MongoDB Atlas的连接,一个用于CloudAMQP,Kubernetes中的Secret的值需要经过`base64`加密。
apiVersion: v1
kind: Secret
metadata:
name: go-srv-config
type: Opaque
data:
mongodb.conn: {{ your_base64_encoded_secret }}
rabbitmq.conn: {{ your_base64_encoded_secret }}

在Linux和Mac上,你能直接使用`base64`程序来对此连接字符串进行编码。
> echo -n "mongodb+srv://username:password@atlas-cluster.gcp.mongodb.net/test?retryWrites=true" | base64
bW9uZ29kYitzcnY6Ly91c2VybmFtZTpwYXNzd29yZEBhdGxhcy1jbHVzdGVyLmdjcC5tb25nb2RiLm5ldC90ZXN0P3JldHJ5V3JpdGVzPXRydWU=

[quote] echo -n "amqp://username:password@rmq.cloudamqp.com/cluster" | base64
YW1xcDovL3VzZXJuYW1lOnBhc3N3b3JkQHJtcS5jbG91ZGFtcXAuY29tL2NsdXN0ZXI=

## Bash脚本变量
脚本part3_create_gke_cluster.sh包含了一系列环境变量。你至少需要更改所有脚本中的PROJECT变量为你的GCP项目名。
# 对应修改这些常量
readonly PROJECT='{{ your_gcp_project_goes_here }}'
readonly CLUSTER='go-srv-demo-cluster'
readonly REGION='us-central1'
readonly MASTER_AUTH_NETS='72.231.208.0/24'
readonly GKE_VERSION='1.12.5-gke.5'
readonly MACHINE_TYPE='n1-standard-2'

脚本part4_install_istio.sh中包含了ISTIO_HOME这个变量,该值应与你本地的Istio 1.1.0的路径一致。下面是在我本地的Mac上的值:
readonly ISTIO_HOME='/Applications/istio-1.1.0'

# 部署GKE集群
接下来使用脚本part3_create_gke_cluster.sh来部署GKE集群。这一步将创建一个区域,多可用区的3节点的GKE集群。该集群将会被部署到与MongoDB Atlas和CloudAMQP集群相同的区域,即us-central1(Iowa)。规划云资源所处的位置,对于Saas供应商和主流云供应商而言,能最大限度地减少网络I/O密集型应用程序的延迟。
6.png

# 使用Helm部署Istio
等待GKE集群和相关的基础设施就绪后,我们将部署Istio。此文中,我推荐选择使用Helm部署Istio的部署方式。要使用该种方式,请使用脚本part4_install_istio.sh
7.png

该脚本使用本地Istio 1.1.0中`install/kubernetes/helm/istio`目录中的Helm Chart安装Istio。该安装脚本使用`--set`命令行标志覆写了Istio Helm Chart中的多个默认值。相关可用的配置项在GitHub project中有详细说明。这些选项启用了Istio的可观测性功能,包含Kiali、Grafana、Prometheus和Jaeger,这些我们将在本系列的第二篇中探索。
helm install ${ISTIO_HOME}/install/kubernetes/helm/istio-init \
--name istio-init \
--namespace istio-system[/quote]

helm install ${ISTIO_HOME}/install/kubernetes/helm/istio \
--name istio \
--namespace istio-system \
--set prometheus.enabled=true \
--set grafana.enabled=true \
--set kiali.enabled=true \
--set tracing.enabled=true

kubectl apply --namespace istio-system \
-f ./resources/secrets/kiali.yaml

如下图,我们可以看到与Istio相关联的负载已经运行在集群中,包含了可观测性工具集。
8.png

同样,我们能看到集群中相应的Istio相关的Service资源。
9.png

# 修改DNS记录
我们将使用DNS,而非使用IP地址来路由GKE集群及其应用程序的流量。如上所述,我使用了example-api.com这个域名和四个子域。一个子域用于devtest命名空间的Angular UI服务,其他被用于API调用的边缘微服务A。流量基于URL路由到特定的Kubernetes Service资源。

部署GKE集群和Istio会触发创建一个Google Load Balancer,四个IP地址和所有必要的防火墙规则。与转发规则相关联的四个IP地址之一(如下所示)将与负载均衡器的前端相关联。
10.png

如下所示,我们能看到一个新的负载均衡器,包含了前端IP地址和三个GKE集群工作节点的后端VM池。每个节点都被分配了一个IP地址。
11.png

接着我使用了Google Cloud DNS创建了四个子域并将所有子域与负载均衡器前端的IP绑定。到这些地址的入口流量将通过Istio ingress Gateway和四个Istio VirtualService然后路由到适当的Kubernetes Service资源去。使用你选定的DNS管理工具来创建四个A类型的DNS记录。
12.png

# 部署整个参考平台
接下来,将八个基于Go的微服务,Angular UI以及相关的Kubernetes和Istio资源部署到GKE集群。请使用脚本part5a_deploy_resources.sh来部署平台。如果任何操作失败并且在不破坏GKE集群或Istio的情况下,你想要删除现有资源并重新部署,则可以使用part5b_delete_resources.sh删除脚本。
14.png

部署脚本将所有资源部署到两个Kubernetes命名空间,分别是devtest。这将使我们能够在使用可观测性工具时区分不同的命名空间。

下图展示刚刚部署的与Istio相关的资源,它们包括Istio Gateway,四个Istio VirtualService和两个Istio ServiceEntry资源。
15.png

接着是在集群上运行此平台的工作负载(Kubernetes Deployment资源)。在这我们可以看到每个工作负载有两个Pod,共有18个Pod,在dev命名空间中运行。每个Pod都包含已部署的微服务或UI组件,以及Istio的Envoy Proxy的副本。
16.png

下图我们看到dev命名空间中创建了对应的Kubernetes Service资源。
17.png

下图test命令空间中的资源与dev命名空间的类似。
18.png

# 测试该平台
我们想确保平台中的八个基于Go的微服务和Angular UI都能正常工作,相互通信,并与外部的MongoDB Atlas和CloudAMQP RabbitMQ集群进行通信。最简单的方式就是直接在浏览器查看Augular UI。
19.png

UI界面要求你输入服务A的主机名,即API的边缘服务。由于你无法使用我的子域,并且JavaScript代码是在你的Web浏览器本地运行,因此该选项允许你提供自己的主机域。这与你在VirtualService中为UI配置的域名相同。此域名将API调用路由到dev命名空间中运行的Service A服务的FQDN service-a.dev.svc.cluster.local,或test命名空间service-a.test.svc.cluster.local
20.png

你还可以使用性能测试工具对平台进行负载测试。很多问题在平台出现负载前都很难发现。最近我开始使用`hey`,一个现代化的负载生成工具,作为Apache Bench的替代品,它不像ab,hey支持HTTP/2端点,这是测试运行在包含了Istio组件的GKE集群上的平台工作所必需的。下面我直接在Google Cloud Shell使用`hey`工具,将模拟25个并发用户,为服务A生成总共1000个基于HTTP/2的GET请求。
21.png

# 故障排除
如果由于某些原因导致UI无法显示或者是从UI发起的调用请求失败,并且假设所有Kubernetes和Istio资源都运行在GKE集群上,则最常见的解释通常就是以下的资源存在错误配置:

  1. 四个DNS记录中存在错误,它们不是解析到负载均衡器的前端IP地址上
  2. 没有为四个Istio的VirtualService资源配置正确的子域名
  3. 基于Go的微服务无法访问外部MongoDB Atlas和CloudAMQP RabbiqMQ集群。可能是Kuberetes Secret资源结构不对或者是两个ServiceEntry中包含了那些到外部集群的错误的主机信息

我建议通过使用cURL或Postman工具直接调用服务A(API的边缘服务)来开始排障。如果你能看到类似下图的JSON格式的响应,那则表明问题在于UI而非API。
22.png

接下来,确认为服务D、F、G和H创建了四个MongoDB数据库。另外确保新文档被正确写入数据库。
23.png

另外使用CloudAMQP RabbitMQ管理控制台确认已创建新的RabbitMQ队列。服务D产生信息,服务F从队列中取出并消费。
24.png

最后查看Stackdriver日志以查看是否存在任何明显错误。
25.png

# 未完待续
在此系列的第二部分中,我们将详细探索每个可观测性工具,并了解它们如何帮助我们管理GKE集群以及运行在上面的相关平台。
26.png

由于集群只需几分钟即可完成创建和部署资源,如果需要清除集群请运行part6_tear_down.sh脚本。
27.png

以上所有仅代表我个人观点,与现任、前任雇主和客户无关。

原文链接:Kubernetes-based Microservice Observability with Istio Service Mesh: Part 1(翻译:冯旭松)

华为云和开源Istio运维管理对比样例应用部署

CCE_SWR 发表了文章 • 0 个评论 • 446 次浏览 • 2019-04-15 17:34 • 来自相关话题

前言 在公有云方面,华为云已经率先将 Istio 作为产品投入到公有云中进行商业应用中,保持和开源istio高度兼容,做了商业化的运维管理界面,同时进行了性能优化。这里我们做一次验证测试。 ...查看全部
前言

在公有云方面,华为云已经率先将 Istio 作为产品投入到公有云中进行商业应用中,保持和开源istio高度兼容,做了商业化的运维管理界面,同时进行了性能优化。这里我们做一次验证测试。




Bookinfo 应用

这里我们部署一个demo,由四个单独的微服务构成(注意这里的四个微服务是由不同的语言编写的),用来演示多种 Istio 特性。这个应用模仿在线书店的一个分类,显示一本书的信息。页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。



Bookinfo 应用分为四个单独的微服务:



productpage:productpage微服务会调用details和reviews两个微服务,用来生成页面。

details:这个微服务包含了书籍的信息。

reviews:这个微服务包含了书籍相关的评论。它还会调用 ratings 微服务。

ratings:ratings 微服务中包含了由书籍评价组成的评级信息。



这里主要使用reviews来演示 Istio 特性,reviews微服务有 3 个版本:



v1 版本不会调用ratings服务。

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

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



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




0415_1.jpg



Istio 注入之前的 Bookinfo 应用



Bookinfo 是一个异构应用,几个微服务是由不同的语言编写的。这些服务对 Istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。





部署应用

这里 Istio 的安装部署就不在赘述了。



值得注意的是:如果使用的是开源K8s服务安装的 Istio ,要配置负载均衡。



在 Istio 中运行这一应用,无需对应用自身做出任何改变。我们只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个服务之中。这个过程所需的具体命令和配置方法由运行时环境决定,而部署结果较为一致,如下图所示:




0415_2.jpg



Bookinfo 应用



所有的微服务都和 Envoysidecar 集成在一起,被集成服务所有的出入流量都被 sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用 Istio 控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。

下载安装



到 GitHub 中 istio 的 release 中下载相应版本的 istio包,下载后将 bin目录配置到环境变量 PATH中 export PATH="/istio/bin:$PATH",这里我们使用的是 istio 1.0.5版本



Bookinfo 这个应用就在samples/目录下





在华为云(CCE)上运行


华为云率先将 Istio 作为产品投入到公有云中进行商业应用,开通方式十分简单,只要在华为云CCE上创建集群,然后申请 Istio 公测即可。



为了方便测试Bookinfo 应用在华为云上提供了一键体验应用,点击即可省去刚刚那一系列的kubectl操作




0415_3.jpg



一键创建体验应用


0415_4.jpg



点击灰度发布即可


0415_5.jpg



创建金丝雀发布


0415_6.jpg



选择灰度发布的组件


0415_7.jpg



填写版本号


0415_8.jpg



选择镜像版本


0415_9.jpg



版本创建完成后配置灰度策略


0415_10.jpg



选择相应策略,策略下发即可



总的来说,华为云的Istio 确实已经是商业化应用,这里只是展示了部分灰度发布的功能。其他比如流量治理,流量监控等功能还没展示,这些功能做的十分细致,值得尝试。


参考

基于ISTIO服务网格的灰度发布

https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_0012.html