服务网格与Istio
一、服务网格
在微服务环境中,可将单一应用程序分解为独立的多个组件,并作为分布式服务进行部署。这些服务通常是无状态的、短暂的、可动态扩展的,运行在容器编排系统(如Kubernetes)中。
服务网格(Service Mesh)是一个专用的基础设施层。服务实例根据需要进行启动、停止、销毁、重建或替换时,通过通信中间件来支持服务的动态发现和自我修复连接能力,从而使得这些服务之间能够以安全、动态和可靠的方式相互通信。
服务网格是一种网络模型,位于TCP/IP之上的抽象层。它假定底层的三四层网络存在并且能够从一点到另一点传送数据,但网络是不可靠的。
服务网格抽象了在服务之间可靠地传递请求的机制,但不关心传送及编码的方式,只负责完成从服务A发送到服务B,并且能够保证故障不会影响服务间的通信的可靠性(通过熔断、延迟感知的负载均衡、最终一致性的服务发现、重试与超时等机制等)。
此外,还提供了一个统一的应用程序控制点,从而将服务通信从不可见的基础设施领域移出,转变为可监控、管理和控制的系统。
服务网格一般由控制平面和数据平面组成:
控制平面是一组运行在专用命名空间中的服务。这些服务负责管理数据平面的执行,包括聚合遥测数据、提供面向用户的API、向数据平面代理提供控制数据等。
数据平面是由一系列运行在每个服务实例旁的透明代理(相当于进程外网络堆栈)构成。这些代理自动处理进出服务的所有流量、向控制平面发送遥测数据并从控制平面接收控制信号。
服务网格的主要功能:
1)通过应用动态路由规则来确定将请求路由到哪个服务。
2)通过服务发现检索相应的实例池。如果结果与实践中观察到的信息不同,那么需要决定信任哪些信息来源。
3)根据各种因素(如观察到的最近请求的延迟数据)选择最有可能返回快速响应的实例。
4)尝试将请求发送到选择的实例,记录响应结果的延迟和响应类型。
5)如果实例没有响应或返回错误,则根据需要在另一个实例上重试该请求。
6)如果实例始终没有响应或返回错误,则将其从负载均衡池中逐出,以便稍后定期重试。
7)如果请求的超时点已过,则会停止进一步重试,主动使请求失败,以防雪崩发生。
8)以度量指标和分布式跟踪的形式捕获上述行为的各个方面,并将这些数据发送到集中式的度量系统或者链路跟踪系统。
二、Istio
1、简介
Istio是服务网格的一种开源实现,支持在Kubernetes上部署的服务、使用Consul注册的服务、在虚拟机上运行的服务等。
主要包括以下组件:
Envoy:每个微服务的sidecar代理,用以处理集群内service间的流量、集群内service访问集群外的流量等
istiod:istio的控制平面,提供了服务发现、配置、证书管理功能,包括:
pilot:用于管理流量,可以控制服务之间的流量流动和API调用
citadel:进行证书和密钥的轮换
Galley:进行配置信息的验证、分发等
Operator:主要是安装istio用的
目前提供了istioctl工具安装、helm工具安装、istio operator自动安装等多种方式
为安装提供了多种profile,不同profile本质上就是用的yaml文件不一样
|
介绍
|
istio-egressgateway
|
istio-ingressgateway
|
istio-ingressgateway
|
default
|
官方推荐
|
|
✔
|
✔
|
demo
|
仅供试用
|
✔
|
✔
|
✔
|
empty
|
什么都不装
一般在其基础上自定义配置
|
|
|
|
external
|
多集群时使用外部控制平面
|
|
|
|
minimal
|
最小化安装
|
|
✔
|
|
openshift
|
|
|
|
|
preview
|
试用istio新功能
|
|
✔
|
✔
|
remote
|
文档没有?
|
|
|
|
2、Istio的安全架构:
在workload与workload通信开始时,两方必须交换身份信息(identity)的凭证以相互验证身份。
客户端,根据安全命名(secure naming)检查服务端的身份,以确定它是否是workload的授权运行者
在服务端,根据授权策略确定客户端可以访问哪些信息,审计谁在什么时间访问了什么。例如可实现按量计费并禁止欠费用户访问。
在不同的平台上,Istio对服务身份信息的标识方法不同
Kubernetes:使用k8s service account
GCE:使用GCE service account
没有服务身份的平台:使用可以对工作负载实例进行分组的其它身份,例如服务名称
主要包括以下环节:
①根证书与集群证书管理
默认istio会自动签发集群证书,但建议用统一的根证书为每个集群签发证书
istio提供了签发证书的工具tools/certs/Makefile.selfsigned.mk
1)签发根证书
$ make -f Makefile.selfsigned.mk root-ca
会生成root-cert.pem、root-key.pem、root-ca.conf、root-cert.csr
2)签发集群证书
$ make -f Makefile.selfsigned.mk cluster1-cacerts
会在cluster1目录下生成ca-cert.pem、ca-key.pem、cert-chain.pem( 指定信任链,包含负载到根CA的所有中间CAs。此处由于仅包含了istio的CA签名证书,因此与ca-cert.pem相同)、root-cert.pem
3)在istio-system下创建名为cacerts的secret
$ kubectl create namespace istio-system $ kubectl create secret generic cacerts -n istio-system \ --from-file=cluster1/ca-cert.pem \ --from-file=cluster1/ca-key.pem \ --from-file=cluster1/root-cert.pem \ --from-file=cluster1/cert-chain.pem
4)最终形成的证书链为:root-cert.pem-->cert-chain.pem(含ca-cert.pem)-->workload-cert.pem
在istio的samples/certs目录下有一套证书作为示例
②身份与workload证书管理
istio agent需要定期为workload进行证书和密钥轮换:
(1)istiod提供了一个gRPC服务来接受CSR。
(2)Istio agent启动时会创建私钥和CSR,然后将CSR及其凭据发送给istiod进行签名。
(3)istiod中的CA验证CSR中携带的凭据。 验证成功后,它会签署CSR以生成证书。
(4)当workload启动时,Envoy通过Envoy SDS(secret discovery service)API从同一容器中的Istio agent请求证书和密钥。
(5)Istio agent通过 Envoy SDS API将从istiod收到的证书和私钥发送给Envoy。
(6)Istio agent监控工作负载证书的过期时间。
现在,还支持基于k8s的CSR API,由自定义的CA为workload签发证书,详见:https://istio.io/latest/docs/tasks/security/cert-management/custom-ca-k8s/
③双向TLS认证:
④鉴权:
3、遥测信息
Istio生成以下类型的telemetry(遥测信息),以提供整体服务网格可观察性:
-
Metrics
Istio监控了所有进出服务网格以及服务网格内的服务流量,根据latency、traffic、errors 、saturation(饱和度)四个维度为服务生成service-level Metrics,提供了可提供网格内的服务的可观察性。包括:https://istio.io/latest/docs/reference/config/metrics/
Istio根据sidecar代理Envoy自身丰富的metrics统计信息(可参考https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/observability/statistics.html?highlight=statistics)生成了proxy-level Metrics,提供网格本身的可观察性(例如出入sidecar的总流量、Envoy的配置与健康情况)。不过默认只收集了Envoy的一部分统计信息,同时需要为工作负载配置收集哪些Envoy的指标。可以使用proxy-status和proxy-config命令进行相应查看与调整。
默认在Istio代理过滤器中编译telemetry V2。相同的Filter也将编译为WebAssembly(WASM)模块,并随Istio代理一起提供。
Istio本身不再访问k8s元数据,而是由代理服务器统一提供service-level Metrics和proxy-level Metrics。
主要通过Envoy WebAssembly插件丰富Envoy的统计子系统:
元数据交互插件:从请求/响应中的自定义HTTP标头获取连接两侧的客户端/服务器元数据
统计信息插件:统计传入和传出的流量指标
-
Distributed Traces
Istio支持通过Envoy代理来进行服务的分布式追踪,从而使运维人员能够详细了解网格内的服务调用链和服务之间的依赖性
支持的跟踪后端包括Zipkin、Jaeger、Lightstep、Datadog
-
Access Logs
当流量进入网格内的服务时, Istio可以为每个请求生成完整的记录,包含源和目标的metadata。
默认会由Envoy容器打印到标准输出,该信息可以使运维人员审计在单个工作负载的级别上审计服务的行为。
4、k8s上的安装CRD
以k8s上通过istioctl工具部署为例:
默认将控制平面安装在istio-system namespace下
istio-ingressgateway这个svc是LoadBalancer类型的。如果k8s不支持自动分配external ip,仍然需要使用nodeport对外暴露http2和https的端口
除了通过istio ingress gateway,istio还实现了k8s官方的ingress api(IngressClass中controller指定为istio.io/ingress-controller)和sig-network的gateway api(GatewayClass中controller指定为istio.io/ingress-controller)
使用时,为namespace添加istio-injection=enabled的label,同时开启webhook功能,才会为该ns下的Pod自动注入
部署完成后,在k8s上会创建以下CRD:
IstioOperator描述了Istio的期待状态,istio operator会根据其进行istio的安装、更新、卸载等
istioctl工具部署时,也会在istio-system namespace下创建名为installed-state的IstioOperator并维护其状态
VirtualService描述了一个或多个路由规则(用户可寻址目标到网格内实际workload的映射)。Istio按顺序评估它们,将每个给定的请求匹配到指定的实际目标地址。
要将服务网格内的请求路由到实际目标地址,Istio必须借助平台提供的服务发现能力。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v3
fault:
delay:
percentage:
value: 0.1
fixedDelay: 5s
hosts字段列出了虚拟服务的目标主机,即用户指定的目标或路由规则设定的目标
可以是ip地址或域名
可以是可解析为FQDN(fully qualified domain name)的短域名
可以加匹配
gateway字段可以将VirtualService与Gateway绑定,向网格外暴露这些hosts
默认会绑定mesh,表示所有sidecar
指定了绑定的Gateway后,就不再自动绑定mesh,需手动绑定
http字段列出了VirtualService的路由规则,规则越靠前优先级越高
match表示匹配规则,可以根据http头、uri等匹配
fault:测试时用于注入错误,delay可以引发超时错误、aborts可以引发中止错误
route中是http路由目的地,可以根据weight、head等决定destination(实际目标地址)
timeout表示envoy代理等待服务的时间
retries可以指定attempts(总尝试次数)和perTryTimeout(每次尝试的timeout)
mirror和mirrorPercent可以控制将部分流量发送给一个镜像服务
tcp字段列出了tcp流量的路由规则
match表示匹配规则,可以根据port、destinationSubnets等匹配
route中是L4路由目的地,可以根据weight决定destination
DestinationRule配置该目的地的流量发生的情况。
它定义了在路由发生后应用于服务的流量的策略。这些规则指定了负载平衡的配置、 sidecar的连接池大小和异常检测设置,以检测并驱逐负载平衡池中不健康的主机。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: my-destination-rule
spec:
host: my-svc
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
- name: v3
labels:
version: v3
trafficPolicy中指明了流量的规则:
loadBalancer指明负载均衡规则:
simple支持 ROUND_ROBIN、 LEAST_CONN、 RANDOM、 PASSTHROUGH等多种经典算
consistentHash支持基于 httpHeaderName、httpCookie、 useSourceIp、 httpQueryParameterName、 minimumRingSize进行hash
localityLbSetting支持基于流量的来去地点(region、zone、sub-zone)控制流量
通过enabled启用
distribute指明分发规则,failover指明故障转移规则,两者不能共存(为啥)
connectionPool为基于Envoy的circuit breaker提供了连接池配置:
tcp可以配maxConnections、connectTimeout、tcpKeepalive
http可以配http1MaxPendingRequests、http2MaxRequests等
outlierDetection可以控制从负载均衡池驱逐不健康主机的策略
tls是连接时的tls相关配置
portLevelSettings可以用端口级别的流量策略覆盖全局配置
subset是服务端点的集合
可以基于label(例如k8s中Pod的label)对服务端点列表进行筛选
其中声明的trafficPolicy会覆盖全局配置
exportTo指明了此DestinationRules暴露到哪些ns中
gateway描述了一个负载均衡器,该负载均衡器是网格边缘独立运行的Envoy代理,在网格的边缘接收传入或传出的HTTP/TCP连接。
但gateway本身只能配置l4-L6的功能,例如暴露的端口、tls设置等。要为进出Gateway的流量配置相应的路由,必须为同一个host定义一个VirtualService,其配置中的gateways字段绑定该Gateway
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: ext-host-gwy
spec:
selector:
app: my-gateway-controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- ext-host.example.com
tls:
mode: SIMPLE
credentialName: ext-host-cert
selector基于标签选择服务作为gateway
入访时,VirtualService中配置流量方向为external workload/用户-> ingress gateway->sidecar
出访时,VirtualService中配置流量方向为sidecar-> engress gateway->external service(通过ServiceEntry注册)
可以通过ServiceEntry将平台外的服务添加到Istio内部维护的服务注册表中。
添加后,Envoy代理可以将流量发送到该服务,就好像该服务条目是网格中的服务一样
通过配置ServiceEntry,可以管理在网格外部运行的服务的流量。
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: details-svc
spec:
hosts:
- details.bookinfo.com
location: MESH_INTERNAL
ports:
- number: 80
name: http
protocol: HTTP
targetPort: 8080
resolution: STATIC
workloadSelector:
labels:
app: details-legacy
WorkloadEntry用于描述平台外(例如没有部署在k8s上,而是直接部署在虚机或裸金属服务器上)的workload,必须与ServiceEntry同步创建。
这个平台外的workload必须同样具备服务身份、sidecar:
apiVersion: networking.istio.io/v1beta1
kind: WorkloadEntry
metadata:
name: details-svc
spec:
serviceAccount: details-legacy
address: 2.2.2.2
labels:
app: details-legacy
instance-id: vm1
对平台外的workload,通过WorkloadGroup模拟k8s中的sidecar注入规范和部署方式
apiVersion: networking.istio.io/v1alpha3
kind: WorkloadGroup
metadata:
name: reviews
namespace: bookinfo
spec:
metadata:
labels:
app.kubernetes.io/name: reviews
app.kubernetes.io/version: "1.3.4"
template:
ports:
grpc: 3550
http: 8080
serviceAccount: default
probe:
initialDelaySeconds: 5
timeoutSeconds: 3
periodSeconds: 4
successThreshold: 3
failureThreshold: 3
httpGet:
path: /foo/bar
host: 127.0.0.1
port: 3100
scheme: HTTPS
httpHeaders:
- name: Lit-Header
value: Im-The-Best
metadata,尤其是其中的标签,将会被应用于所有workload
template是用于生成对应WorkloadEntry的模板(address和label不可手动设置)
probe用于配置就绪探针,和k8s中的配置方法几乎一样
EnvoyFilter可以用来更新Envoy中的filter的配置,为服务网格控制面提供了更强大的扩展能力,使Envoy中filter chain具备自定义配置的能力。
-
telemetries.telemetry.istio.io
暂时不知道干嘛的
默认情况下,Istio将每个Envoy代理配置为接受其相关工作负载的所有端口上的流量,并在转发流量时到达网格中的每个工作负载。
可使用Sidecar执行以下操作:
微调Envoy代理接受的端口和协议集。
限制Envoy代理可以访问的服务集。
例如,限制xxx命名空间下的服务仅能访问同一命名空间和Istio-system中运行的服务:
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: default
namespace: xxx
spec:
egress:
- hosts:
- "./*"
- "istio-system/*"
即授权策略,可以实现workload/用户→workload的访问控制
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: httpbin
namespace: foo
spec:
action: DENY
rules:
- from:
- source:
namespaces: ["dev"]
to:
- operation:
methods: ["POST"]
selector选择了策略适用的workload,通过selector可以将策略分为mesh级、ns级、workload级
action包括DENY、ALLOW、AUDIT、CUSTOM(转发给扩展程序处理用户请求)
多个策略共存时,CUSTOM>DENY>ALLOW
provider指定扩展程序的名字(action为CUSTOM时生效)
rules包括了:
from中,source可以是(not)ns、ipblock、principals等
to中,operation可以是(not)hosts、ports等
when指定了key/(not)value的条件:https://istio.io/latest/docs/reference/config/security/conditions/
-
peerauthentications.security.istio.io
即peer认证(authentication)策略,配置的是workload-workload双向通信的tls认证策略:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "example-peer-policy"
namespace: "foo"
spec:
selector:
matchLabels:
app: reviews
mtls:
mode: STRICT
selector选择了策略适用的workload,通过selector可以将策略分为mesh级、ns级、workload级
范围越小的优先级越高,范围一样时旧的优先级高
mels.mode指定了workload的双向TLS模式
PERMISSIVE:既支持双向TLS,也运行明文通信
STRICT:必须双向TLS
DISABLE:禁用双向TLS
portLevelMtls.xx.mode则支持为某一个端口专门配置
即request认证(authentication)策略,基于对request中的JWT(JSON Web Token)进行校验来实现认证
selector选择了策略适用的workload,通过selector可以将策略分为mesh级、ns级、workload级
jwtRules中是一条条JWT检查规则,可检查的包括issuer、audiences、jwksUri、jwks(JSON Web Key Set)等
5、示例程序
samples/bookinfo/platform/kube/bookinfo.yaml下提供了一个示例程序
使用istio将其改造成如下架构:
三、其它服务网格产品
目前,很多传统的反向代理也在向服务网格方向发展,例如Nginx构建的nginx Service Mesh、Traefix构建的Trafix Mesh
API网关产品kong也发展了kuma(也是基于Envoy)