一、背景
随着单片应用程序向分布式微服务架构过渡 ,特别是服务之间呈现拓扑状的复杂关系,service mesh的提出就是为了简化管理微服务之间的通信问题。为了实现微服务 Service Mesh 模式和诸多理念,Google , IBM 和 Lyft 这三家公司协同研发,并于 2017 年 6 月 8 日( 根据 Github 最后一次提交的时间 )发布了 Istio 的第一个发行版——Istio 0.1 版本。
二、istio架构
istio分为控制面和数据面,架构如下图所示。
![](/tmp/5de067fab481934666d3bb44090fadad/istio
- 数据面:由一组sidecar组成,对应具体的组件为envoy;通过给每个应用启动一个轻量级的网络代理,来执行对网络通信的控制和调整,Sidecar和外围代理,实现客户端和服务器之间的安全通信;
- 控制面:负责管理和配置代理流量。具体通过mixer组件下发策略给envoy,执行策略并对各个sidecar收集数据。 Citadel用于密钥和证书管理;pilot将身份验证策略和安全命名信息分发到代理;mixer用于管理授权和审核。
三、核心功能
流量管理:
下图显示了pilot的服务发现过程。
istio根据Kubernetes的适配器发现并注册service后,流量规则会由pilot解析成envoy理解的格式传送给Sidecar,进而控制服务间的流量和 API 调用。Istio 简化了断路器、超时和重试等服务级别属性的配置,并且可以轻松设置 A/B 测试、金丝雀部署和基于百分比的流量分割的分阶段部署等重要任务。
安全:
Istio提供底层安全通信通道,使开发人员可以专注于应用程序级别的安全,并提供大规模管理服务通信的身份验证、授权和加密。使用Istio,服务通信在默认情况下是安全的,可以跨不同的协议和运行时一致地实施策略,所有这些都只需很少或根本不需要更改应用程序。
安全涉及的几个组件及架构如下图所示:
Citadel:用于密钥和证书管理。
Sidecar和外围代理:实现客户端和服务器之间的安全通信。
pilot:将身份验证策略和安全命名信息分发到代理。
mixer:用于管理授权和审核。
策略定制: 为应用程序配置自定义策略,以在运行时强制执行规则,如动态限制服务的通信量,通过名单限制对服务的访问,也可以创建自己的策略适配器,添加自定义授权行为。
可观察性: Istio强大的跟踪、监控和日志记录功能可让人深入了解服务网格的部署。通过Istio的监控功能,可以真正了解服务性能对上下游的影响,同时其定制的仪表盘可查看所有服务的性能,并了解该性能对其他流程有何影响。
四、基本功能验证
本环境基于Kubernets1.14和istio1.13版本进行验证。其中下面的例子都在官方链接的samples目录中,官方链接[1]istio官方例子
1、流量管理:
为了填充自己的服务注册表,Istio连接到服务发现系统,而在Kubernetes集群上安装了Istio,Istio会自动检测该集群中的服务和端点,使用此服务注册表,代理就可以将流量定向到相关服务。默认情况下同一工作负载多个实例,流量会平均分发,而作为A/B测试的一部分,也可以将特定百分比的流量定向到服务的新版本,或者对特定服务实例子集的流量应用不同的负载平衡策略。还可以对进出Mesh的流量应用特殊规则,或者将Mesh的外部依赖项添加到服务注册表。
以官方的bookinfo为例,使用对同一程序多版本的流量管理,具体配置如下:
自注入使能
kubectl label namespace default istio-injection=enabled
部署bookinfo到default namespaces,bookinfo服务之间默认的调用关系如下图:
可创建virtualService全部流量导向reviews-v1,yaml文件中host指向的是reviews service,只指定了v1版本,因此流量全导向reviews v1。
virtualService yaml如下:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
结果如下图,可以看到图中绿色部分就是当前流量的走向,全部走向previews v1:
2、安全,主要提供服务网格之间安全访问,这里以enable TLS为例。
创建meshPolicy全局enable tls
kubectl apply -f - <
因为使能了TLS,所以不带证书访问会报错,直接http访问结果如下:
for from in "foo" "bar"; do for to in "foo" "bar"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 503
sleep.foo to httpbin.bar: 503
sleep.bar to httpbin.foo: 503
sleep.bar to httpbin.bar: 503
创建 destination rules使能TLS,目标是所有的集群内部的服务,然后服务之间就可以正常的访问了,使能TLS的操作如下:
kubectl apply -f - <
根据destination rules,访问所有集群内部服务都会带上TLS证书进行访问,使能TLS的访问结果:
for from in "foo" "bar"; do for to in "foo" "bar"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
除了全局指定tls,也可以单独指定namespace使能TLS,操作如下:
kubectl apply -f - <
指定特定service tls,操作如下:
cat <
3、策略
这里还是以官方的bookinfo为例,指定应用拒绝访问。
首先修改istio configmap修改disablePolicyChecks为false,使能policy;然后制定策略拒绝v3版本的访问版本,匹配源为reviews v3和目的ratings制定rule对应handler为拒绝访问,yaml如下:
apiVersion: "config.istio.io/v1alpha2"
kind: handler
metadata:
name: denyreviewsv3handler
spec:
compiledAdapter: denier
params:
status:
code: 7
message: Not allowed
---
apiVersion: "config.istio.io/v1alpha2"
kind: instance
metadata:
name: denyreviewsv3request
spec:
compiledTemplate: checknothing
---
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: denyreviewsv3
spec:
match: destination.labels["app"] == "ratings" && source.labels["app"]=="reviews" && source.labels["version"] == "v3"
actions:
- handler: denyreviewsv3handler
instances: [ denyreviewsv3request ]
4、可观察性
Istio为网格内的所有服务通信生成详细的telemetry信息。此telemetry提供服务行为的可观察性,使运维人员能够对应用程序进行故障排除、维护和优化, 具体通过三个方面表现,第一个是metrics即指标,Istio根据监控的四个维度(延迟、流量、错误和饱和度)生成一组服务指标,暴露给proetheus。第二个是访问日志,当流量流入网格内的服务时,Istio可以生成每个请求的完整记录,包括源和目标元数据。此信息使操作员能够审核服务行为,直至各个工作负载实例级别。 第三个是分布式跟踪, Istio提供了一种通过监视流经网格的各个请求来监视和了解行为的方法,了解服务网状网内的服务依赖关系和延迟来源。
以bookinfo为例,配置istio自动收集服务指标,每次调用网格内的服务,都会有相应的指标生成。
配置收集metrics的yaml文件如下:
# Configuration for metric instances
apiVersion: config.istio.io/v1alpha2
kind: instance
metadata:
name: doublerequestcount
namespace: istio-system
spec:
compiledTemplate: metric
params:
value: "2" # count each request twice
dimensions:
reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server")
source: source.workload.name | "unknown"
destination: destination.workload.name | "unknown"
message: '"twice the fun!"'
monitored_resource_type: '"UNSPECIFIED"'
---
# Configuration for a Prometheus handler
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
name: doublehandler
namespace: istio-system
spec:
compiledAdapter: prometheus
params:
metrics:
- name: double_request_count # Prometheus metric name
instance_name: doublerequestcount.instance.istio-system # Mixer instance name (fully-qualified)
kind: COUNTER
label_names:
- reporter
- source
- destination
- message
---
# Rule to send metric instances to a Prometheus handler
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: doubleprom
namespace: istio-system
spec:
actions:
- handler: doublehandler
instances: [ doublerequestcount ]
在prometheus graph界面搜索istio_double_request_count,结果如下:
日志功能,使用资源instance,handler,rule创建,具体内容如下:
# Configuration for logentry instances
apiVersion: config.istio.io/v1alpha2
kind: instance
metadata:
name: newlog
namespace: istio-system
spec:
compiledTemplate: logentry
params:
severity: '"warning"'
timestamp: request.time
variables:
source: source.labels["app"] | source.workload.name | "unknown"
user: source.user | "unknown"
destination: destination.labels["app"] | destination.workload.name | "unknown"
responseCode: response.code | 0
responseSize: response.size | 0
latency: response.duration | "0ms"
monitored_resource_type: '"UNSPECIFIED"'
---
# Configuration for a stdio handler
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
name: newloghandler
namespace: istio-system
spec:
compiledAdapter: stdio
params:
severity_levels:
warning: 1 # Params.Level.WARNING
outputAsJson: true
---
# Rule to send logentry instances to a stdio handler
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: newlogstdio
namespace: istio-system
spec:
match: "true" # match for all requests
actions:
- handler: newloghandler
instances:
- newlog
访问productpage,可以看到有对应的日志生成,操作如下:
kubectl logs -n istio-system -l istio-mixer-type=telemetry -c mixer | grep "newlog" | grep -v '"destination":"telemetry"' | grep -v '"destination":"pilot"' | grep -v '"destination":"policy"' | grep -v '"destination":"unknown"'
{"level":"warn","time":"2019-12-16T16:45:53.950607Z","instance":"newlog.instance.istio-system","destination":"ratings","latency":"1.494269ms","responseCode":200,"responseSize":48,"source":"reviews","user":"unknown"}
分布式跟踪,使用jaeger进行trace, 默认采样率为1%。至少需要发送100个请求,才能看到一个跟踪,访问productpage操作:
for i in `seq 1 100`; do curl -s -o /dev/null http://$GATEWAY_URL/productpage; done
可以在jaeger dashboard看到对应跟踪信息,如下图: