Istio是一个用于连接、管理以及安全化微服务的开放平台, 提供了一种简单的方式用于创建微服务网络,并提供负载均衡/服务间认证/监控等能力,关键的是并不需要修改服务本身. 主要提供以下功能:
- Traffic Management: 控制服务之间调用的流量和API调用;
- Observability: 获取服务之间的依赖,以及服务调用的流量走向;
- Policy Enforcement: 控制服务的访问策略,不需要改动服务本身;
- Service Identity and Security: 服务身份与安全相关的功能;
架构
智能代理Envoy
Envoy 是一个面向服务架构的L7代理和通信总线而设计的,这个项目诞生是出于以下目标:
- 外置进程架构:Envoy是一个独立的进程,与应用程序一起运行。
- 跨语言: Envoy可以与任何语言开发的应用一起工作。
- 基于新C++11编码
- L3/L4过滤器:Envoy其核心是一个L3/L4网络代理,能够作为一个可编程过滤器实现不同TCP代理任务,插入到主服务当中。
- HTTP L7过滤器:在现代应用架构中,HTTP是非常关键的部件,Envoy支持一个额外的HTTP L7过滤层。HTTP过滤器作为一个插件,插入到HTTP链接管理子系统中,从而执行不同的任务,如缓冲,速率限制,路由/转发,嗅探Amazon的DynamoDB等等。
- 支持HTTP/2
- HTTP L7路由:在HTTP模式下运行时,Envoy支持根据content type、runtime values等,基于path的路由和重定向。当服务构建到服务网格时,Envoy为前端/边缘代理,这个功能是非常有用的。
- 支持gRPC:gRPC是一个来自谷歌的RPC框架,使用HTTP/2作为底层的多路传输。HTTP/2承载的gRPC请求和应答,都可以使用Envoy的路由和LB能力。所以两个系统非常互补。
- 支持MongoDB L7
- 支持DynamoDB L7:
- 服务发现:服务发现是面向服务体系架构的重要组成部分。Envoy支持多种服务发现方法,包括异步DNS解析和通过REST调用服务发现(Service discovery)服务。
- 健康检查:构建Envoy网格的推荐方法,是将服务发现视为一个最终一致的方法。Envoy含有一个健康检查子系统,它可以对上游服务集群进行主动的健康检查。然后,Envoy联合服务发现、健康检查信息来判定健康的LB对象。Envoy作为一个外置健康检查子系统,也支持被动健康检查。
- 高级LB:在分布式系统中,不同组件之间LB也是一个复杂的问题。Envoy是一个独立的代理进程,不是一个lib库,所以他能够在一个地方实现高级LB,并且能够被任何应用程序访问。目前,包括自动重试、断路器,全局限速,阻隔请求,异常检测。将来还会支持按计划进行请求速率控制。
- 前端代理:虽然Envoy作为服务间的通信系统而设计,但是(调试,管理、服务发现、LB算法等)同样可以适用于前端,Envoy提供足够的特性,能够作为绝大多数Web应用的前端代理,包括TLS、HTTP/1.1、HTTP/2,以及HTTP L7路由。
- 极好的可观察性:如上所述,Envoy目标是使得网络更加透明。而然,无论是网络层还是应用层,都可能会出现问题。Envoy包括对所有子系统,提供了可靠的统计能力。目前只支持statsd以及兼容的统计库,虽然支持另一种并不复杂。还可以通过管理端口查看统计信息,Envoy还支持第三方的分布式跟踪机制。
- 动态配置:Envoy提供分层的动态配置API,用户可以使用这些API构建复杂的集中管理部署。
Envoy将作为一个独立的sidecar与相关微服务部署在同一个Kubernetes的pod上,并提供一系列的属性给Mixer。Mixer以此作为依据执行策略,并发送到监控系统.
这种sidecar代理模型不需要改变任何服务本身的逻辑,并能增加一系列的功能.
Mixer
后端的基础设施常常被设计用于提供建立服务支持的功能,包括访问控制系统、遥测数据捕获系统、配额执行系统以及计费系统等。传统服务会直接和这些后端系统打交道,和后端紧密耦合,并集成其中的个性化语义以及用法。
Mixer的设计目的是改变层次之间的边界,以此来降低总体的复杂性。从服务代码中剔除策略逻辑,改由运维人员进行控制。
Mixer架构
- 前提条件检查 允许服务在响应来自服务消费者的传入请求之前验证一些前提条件。前提条件可以包括服务使用者是否被正确认证,是否在服务的白名单上,是否通过ACL检查等等。
- 配额管理 使服务能够在分配和释放多个维度上的配额,配额这一简单的资源管理工具可以在服务消费者对有限资源发生争用时,提供相对公平的竞争手段。限流控制就是配额的一个实例。
- 遥测报告 使服务能够上报日志和监控,以及还将启用针对服务生产者以及服务消费者的跟踪和计费流。
这些机制的应用是基于一组 属性 的,每个请求都会将这些属性呈现给Mixer。在Istio中,这些属性来自于Sidecar代理(Envoy)的每一次请求。
request.path: xyz/abc
request.size: 234
request.time: 12:34:56.789 04/17/2017
source.ip: 192.168.0.1
target.service: example基于适配器与模板的配置
- Handler:Handlers就是一个配置完成的适配器。适配器的构造器参数就是Handler的配置。
- 实例:一个(请求)实例就是请求属性到一个模板的映射结果。这种映射来自于实例的配置。
- 规则:规则确定了何时使用一个特定的模板配置来调用一个Handler。
Handler
这里的例子配置了一个类型为 listchecker 的适配器。listchecker适配器使用一个列表来检查输入。如果配置的是白名单模式且输入值存在于列表之中,就会返回成功的结果。
apiVersion: config.istio.io/v1alpha2
kind: listchecker
metadata:
name: staticversion
namespace: istio-system
spec:
providerUrl: http://white_list_registry/
blacklist: false实例
配置实例将请求中的属性映射成为适配器的输入, 注意Handler配置中需要的所有维度都定义在这一映射之中。
apiVersion: config.istio.io/v1alpha2
kind: metric
metadata:
name: requestduration
namespace: istio-system
spec:
value: response.duration | "0ms"
dimensions:
destination_service: destination.service | "unknown"
destination_version: destination.labels["version"] | "unknown"
response_code: response.code | 200
monitored_resource_type: '"UNSPECIFIED"'规则
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: promhttp
namespace: istio-system
spec:
match: destination.service == "service1.ns.svc.cluster.local" && request.headers["xuser"] == "user1"
actions:
- handler: handler.prometheus
instances:
- requestduration.metric.istio-systemPilot (原Istio-Manager)
Service Model服务模型
例如,k8s中,一个服务foo就会有一个域名foo.default.svc.cluster.local hostname,虚拟IP10.0.1.1以及可能的监听端口。
Configuration Model配置模型
Istio的规则配置提供了一个基于pb的模式定义。这些规则内容存储在一个KVstore中,pilot订阅了这些配置信息的变化,以便更新istio其他组件的配置内容。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
route:
- labels:
version: v1
weight: 100代理控制器
- proxy agent 一套用于从抽象服务模型和规则配置生成envoy配置信息的脚本命令,同时也会触发proxy的重启;
- discovery service 实现了envoy的服务发现API,从而可以发布信息到envoy代理;
GET /v1/registration/(string: service_name)
请求发现服务返回指定service_name的所有主机, 返回以下JSON格式的响应:
{
"hosts": []
}
const std::string Json::Schema::SDS_SCHEMA(R"EOF(
{
"$schema": "http://json-schema.org/schema#",
"definitions" : {
"host" : {
"type" : "object",
"properties" : {
"ip_address" : {"type" : "string"},
"port" : {"type" : "integer"},
"tags" : {
"type" : "object",
"properties" : {
"az" : {"type" : "string"},
"canary" : {"type" : "boolean"},
"load_balancing_weight": {
"type" : "integer",
"minimum" : 1,
"maximum" : 100
}
}
}
},
"required" : ["ip_address", "port"]
}
},
"type" : "object",
"properties" : {
"hosts" : {
"type" : "array",
"items" : {"$ref" : "#/definitions/host"}
}
},
"required" : ["hosts"]
}
)EOF");这儿不得不提的是pilot的 proxy injection 能力,你可能已经想到了它是基于iptable规则来实现的。这样所有的服务交互都会被pilot捕获并重新转发。
Istio-Auth
提供服务间以及用户之间的认证,确保不需要修改服务code的前提下增强服务之间的安全性. 主要包括以下3个组件:
分布式跟踪
Istio的分布式跟踪是基于Twitter开源的zipkin分布式跟踪系统,理论模型来自于Google Dapper 论文.
启动zipkin
安装Istio时会启动zipkin addon,当然也可以使用如下命令启动:
kubectl apply -f install/kubernetes/addons/zipkin.yaml访问zipkin
访问zipkin dashboard: http://localhost:9411
kubectl port-forward $(kubectl get pod -l app=zipkin -o jsonpath='{.items[0].metadata.name}') 9411:9411在服务中enable trace
服务本身实现需要做一定的改动,即从最初始的HTTP请求中获取以下header并传递给其他的请求:
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context启用Ingress
在Kubernetes环境下, Istio使用了内置的Ingress来暴露服务,目前支持HTTP和HTTPS两种方式. 具体的Ingress,参见Kubernetes Ingress.
配置HTTP服务
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: simple-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
rules:
- http:
paths:
- path: /headers
backend:
serviceName: httpbin
servicePort: 8000
- path: /delay/.*
backend:
serviceName: httpbin
servicePort: 8000
EOF配置HTTPS服务
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: secured-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
tls:
- secretName: ingress-secret
rules:
- http:
paths:
- path: /ip
backend:
serviceName: httpbin
servicePort: 8000
EOF启用Egress
配置外部服务
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
name: externalbin
spec:
type: ExternalName
externalName: httpbin.org
ports:
- port: 80
# important to set protocol name
name: http
EOFcat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
name: securegoogle
spec:
type: ExternalName
externalName: www.google.com
ports:
- port: 443
# important to set protocol name
name: https
EOF其中, metadata.name 就是内部服务所需要访问的外部服务的名称, spec.externalName则是外部服务的DNS名称.
export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it $SOURCE_POD -c sleep bash
curl http://externalbin/headers
curl http://securegoogle:443直接访问外部服务
kubectl apply -f <(istioctl kube-inject -f samples/apps/sleep/sleep.yaml --includeIPRanges=10.0.0.1/24)配置请求路由
默认配置下,Istio会将所有的请求路由到同一个服务的所有版本上.此外,Istio提供了根据请求内容的路由规则,如下规则描述了所有的请求都会指向服务的版本v1:
type: route-rule
name: ratings-default
namespace: default
spec:
destination: ratings.default.svc.cluster.local
precedence: 1
route:
- tags:
version: v1
weight: 100
---
type: route-rule
name: reviews-default
namespace: default
spec:
destination: reviews.default.svc.cluster.local
precedence: 1
route:
- tags:
version: v1
weight: 100
---
type: route-rule
name: details-default
namespace: default
spec:
destination: details.default.svc.cluster.local
precedence: 1
route:
- tags:
version: v1
weight: 100
---
type: route-rule
name: productpage-default
namespace: default
spec:
destination: productpage.default.svc.cluster.local
precedence: 1
route:
- tags:
version: v1
weight: 100
---如果需要将某些请求指向其他版本的服务,如根据请求的cookie进行路由:
destination: reviews.default.svc.cluster.local
match:
httpHeaders:
cookie:
regex: ^(.*?;)?(user=jason)(;.*)?$
precedence: 2
route:
- tags:
version: v2其他具体的规则,参见: https://istio.io/docs/reference/config/traffic-rules/routing-rules.html#routerule
错误注入
destination: ratings.default.svc.cluster.local
httpFault:
delay:
fixedDelay: 7s
percent: 100
match:
httpHeaders:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
precedence: 2
route:
- tags:
version: v1设置请求超时
HTTP请求超时可以通过在路由规则中设置字段httpReqTimeout实现.
具体例子如下:
cat <<EOF | istioctl replace
type: route-rule
name: reviews-default
spec:
destination: reviews.default.svc.cluster.local
route:
- tags:
version: v2
httpReqTimeout:
simpleTimeout:
timeout: 1s
EOF限流
在Istio的mixer中配置限流规则,如下ratelimit.yaml:
rules:
- selector: source.labels["app"]=="reviews" && source.labels["version"] == "v3"
- aspects:
- kind: quotas
params:
quotas:
- descriptorName: RequestCount
maxAmount: 5000
expiration: 5s
labels:
label1: target.service如果target.service=rating, 那么计数器的key则为:
$aspect_id;RequestCount;maxAmount=5000;expiration=5s;label1=ratings执行如下命令可以使得rating服务的请求控制在每5秒5000次(限定在reviews v3服务在调用时生效):
istioctl mixer rule create global ratings.default.svc.cluster.local -f ratelimit.yaml简单的访问控制
使用denials属性
rules:
- aspects:
- kind: denials
selector: source.labels["app"]=="reviews" && source.labels["version"] == "v3"执行如下命令可以使rating服务拒绝来自reviews v3服务的任何请求.
使用黑白名单
- name: versionList
impl: genericListChecker
params:
listEntries: ["v1", "v2"]启用白名单时blacklist设置为false,反之为true.
rules:
aspects:
- kind: lists
adapter: versionList
params:
blacklist: false
checkExpression: source.labels["version"]






