Istio 是一个开源服务网格,它透明地分层到现有的分布式应用程序上。 Istio 强大的特性提供了一种统一和更有效的方式来保护、连接和监视服务。 Istio 是实现负载平衡、服务到服务身份验证和监视的路径——只需要很少或不需要更改服务代码。它强大的控制平面带来了重要的特点,包括:
Istio 主要由两部分组成,分别是数据平面和控制平面。
Istio 是一个与 Kubernetes 紧密结合的服务网格(Service Mesh),用于服务治理。
注意,Istio 是用于服务治理的,主要有流量管理、服务间安全、可观测性这几种功能。在微服务系统中,会碰到很多棘手的问题,Istio 只能解决其中一小部分。
服务治理有三种方式,第一种是每个项目中包含单独的治理逻辑,这样比较简单;第二种是将逻辑封装到 SDK 中,每个项目引用 SDK 即可,不增加或只需要少量配置或代码即可;第三种是下沉到基础设施层。Istio 便是第三种方式。
Istio 可以的作用原理是拦截 Kubernetes 部署 Pod 的事件,然后从 Pod 中注入一个名为 Envoy 的容器,这个容器会拦截外部到业务应用的流量。由于所有流量都被 Envoy “劫持” 了,所以 Istio 可以对流量进行分析例如收集请求信息,以及一系列的流量管理操作,也可以验证授权信息。当 Envoy 拦截流量并执行一系列操作之后,如果请求没问题,就会转发流量到业务应用的 Pod 中。
【左:普通 Pod;Istio;右:Istio 代理了出入口流量】
当然,由于 Envoy 需要拦截流量之后转发给业务应用,这样就多了一层转发,会导致系统响应速度会有所下降,但是增加的响应时间几乎可以忽略不计。
每个 Pod 都有一个 Envoy 负责拦截、处理和转发进出 Pod 的所有网络流量,这种方式被称为 Sidecar。
以下是 Istio Sidecar 的一些主要功能:
由于 Pod 是通过 Envoy 暴露端口的,所有进出口流量都需要经过 Envoy 的检查,所以很容易判断访问来源,如果请求方不是在 Istio 中的服务,那么 Envoy 便会拒绝访问。
在 Istio 中,Envoy 这一块称为数据平面,而负责管理集群的 istiod 组件称为控制平面。
注意,这里是 istiod ,是 Istio 负责管理集群的一种组件。
istioctl(可以通过curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.20.1 sh 安装)
[root@bt ~]# istioctl profile list
Istio configuration profiles:
ambient
default
demo
empty
external
minimal
openshift
preview
remote
或者
安装profile=demo的 istio
istioctl manifest apply --set profile=demo \
--set cni.enabled=true --set cni.components.cni.namespace=kube-system \
--set values.gateways.istio-ingressgateway.type=ClusterIP
设置自动 istio 注入,可以通过 namespace 去做
#给ns1的命名空间添加istio标签,那么在这个标签里,所有创建的 pod 都会被自动注入 istio
kubectl label ns ns1 istio-injection=enabled
# 查看labels
kubectl get ns --show-labels
使用 istio 单独的注入一个pod
# 创建
istioctl kube-inject -f pod1.yaml | kubectl apply -f -
# 查看pod数量
kubectl get pods #此时READY数为2
#这个pod新增的docker,就是 pilot,envoy
## 在创建一个 pod 测试
sed 's/pod1/pod2/' pod1.yaml | kubectl apply -f -
kubectl get pods # 发现这个 pod2 是没有被注入的
安装kiali :图形化工具,可以直观的查看流量
kubectl get pods -n istio-system
# 安装
kubectl apply -f istio-1.10.3/samples/addons/kiali.yaml
# 或者可以选择直接全部都安装上
kubectl apply -f istio-1.10.3/samples/addons/
kubectl get svc -n istio-system
# kiali 的PORT:20001,TYPE为 ClusterIP
# 修改 kiali 的 svc
kubectl edit svc kiali -n istio-system
sessionAffinity: None
type: LoadBalancer #把ClusterIP修改为NodePort或者LoadBalancer
# 查看并验证
kubectl get svc -n istio-system
# 查看 kiali 的 ip 和端口,使用浏览器访问
# 进入浏览器后可以测试一下,进入 Graph 页面,选择 istio-system 和 ns1 的 Namespace,可以看到我们现在环境中的拓扑图
Kiali 的 Graph 数据主要来自两个来源:Prometheus 和 Istio 本身的遥测数据。
Prometheus:Prometheus 是一个开源监控和警报工具,它用于收集和存储 Istio 服务网格中的指标数据。Istio 使用 Envoy 代理收集遥测数据,这些数据随后被 Prometheus 抓取和存储。Kiali 使用这些 Prometheus 数据来生成服务之间的流量、错误率、延迟等指标。
Istio 遥测数据:Istio 服务网格生成的遥测数据包括请求、响应、延迟以及 Envoy 代理的其他性能指标。这些数据由 Istio 组件(例如 Mixer 和 Pilot)以及 Envoy 代理本身生成。Kiali 从这些遥测数据中获取服务拓扑信息,以创建服务之间的依赖关系图。
Kiali 将这两个数据源的信息整合在一起,生成 Graph,它展示了服务网格的拓扑结构、服务之间的流量以及其他性能指标。这有助于用户更好地理解服务之间的依赖关系,发现潜在的性能问题,并优化服务网格配置。
可能失败的原因
如果你的 Kiali 一直显示 Empty Graph。请关注以下几种可能的情况:
集群版本低于 1.23 ,需要升级 Kubernetes 集群。
安装了 Kubesphere,说多了都是泪,Kubesphere 太重了,笔者花了一晚上时间重新安装集群。
访问的地址不正确,没有配置对 /productpage 的访问地址,请求流量没有打入集群。
Pod 没有被注入 istio-proxy。
你可以在 Kiali 的 Workloads 查看每个负载的 Pod 信息,正常情况应当如下所示:
修复 Kiali Grafana 问题
点击右上角的消息,可能会提示配置不正确,因为 kiali 需要从 Grafana 拉取数据。
编辑 configmap 。
kubectl edit configmap kiali -n istio-system
grafana: \n enabled: true \n url: \"http://grafana.istio-system.svc.cluster.local:3000\"
\ \n in_cluster_url: \"http://grafana.istio-system.svc.cluster.local:3000\"\n
如果上方不行,就添加下方
grafana: \n enabled: true \n url: \"http://grafana.istio-system.svc.cluster.local:3000\"
如果使用的是可视化工具,添加就简单了。
grafana:
enabled: true
url: "http://grafana.istio-system.svc.cluster.local:3000"
in_cluster_url: "http://grafana.istio-system>.svc.cluster.local:3000"
然后使用 kubectl describe configmap kiali -n istio-system 查看配置是否正确。
和Kubernetes资源一致,Istio的配置也是通过声明式自定义资源配置来加载的。常用的核心资源有VirtualService、DestinationRule、Gateway、ServiceEntry、Sidecar等。
Gateway 类似 Nginx 需要创建一个反向代理时需要绑定的域名配置。
Istio VistualService 中可以限制外部能够访问的路由地址,
DestinationRule 则可以配置访问的 Pod 策略。
可以为 Istio VistualService 绑定一个 Istio DestinationRule
通过 DestinationRule 我们还可以定义版本子集等,通过更加丰富的策略转发流量。
bookinfo
服务。bookinfo
服务时,VirtualService就像是一个分拣员,它会根据请求的路径或者其他属性,决定请求应该被发送到哪个服务。在你的例子中,productpage
的VirtualService可能会把请求发送到productpage
服务。productpage
服务需要访问其他服务(如reviews
)时,它会发送一个请求。这个请求就像是一个新的邮件,它会被Envoy(快递员)拿到,然后根据VirtualService和DestinationRule的规则,被发送到正确的服务。在 Istio 中,VirtualService 和 DestinationRule 是两个关键的自定义资源定义(CRD),它们用于配置和控制服务间的流量路由。
它们之间的关系可以概括为:
VirtualService 定义了流量的路由规则,
DestinationRule 定义了流量到达目的地后如何进行负载分发和连接池管理。
VirtualService 用于定义流量的路由规则。 当请求从一个服务到另一个服务时,VirtualService 可以指定如何将流量路由到不同的目的地(例如,不同的服务实例,版本或子集)。VirtualService 还可以根据请求的属性(如请求头、路径、来源等)对流量进行匹配和分发。此外,VirtualService 可以配置复杂的路由行为,如重试、超时和故障注入等。
DestinationRule 被用于控制流量的分发和连接池管理。 DestinationRule 定义了服务的子集(即服务的不同版本或变体),并指定如何根据负载均衡策略(如轮询、随机、最少连接等)将流量分发到这些子集。此外,DestinationRule 还可以配置连接池设置(如最大连接数、空闲超时等)和传输层安全策略(如 TLS 设置)。
总之,VirtualService 和 DestinationRule 在 Istio 中共同实现了流量的精细控制。VirtualService 用于定义流量的路由规则,而 DestinationRule 则负责处理流量到达目的地后的负载分发和连接池管理。
Istio 的做法是 Gateway 监控入口流量,
通过 VirtualService 设置流量进入的策略,并指向 Service。
而 DestinationRule 则定义了流量流向 Pod 的策略。
VirtualService(虚拟服务)和Kubernetes的Service类似,但是两种并不是对等的资源类型。VirtualService基于Istio和对应平台提供的基本连通性和服务发现能力,将请求路由到对应的目标。每一个VirtualService包含一组路由规则,Istio将每个请求根据路由匹配到指定的目标地址。
和Kubernetes的Service不同的是,Kubernetes的Service只提供了最简单的服务发现和负载均衡的能力,如果想要实现更加细粒度的流量分发,比如灰度、蓝绿等流量管理,Kubernetes的Service显得比较吃力或者无法实现,而VirtualService在流量管理方面有着比较好的灵活性和有效性,可以在代码零侵入的情况下实现更加丰富的流量管理,比如灰度等。
一个典型的用例是将流量发送到被指定服务的不同版本,比如80%的流量发送给v1版本,20%的流量发送给新版本。或者将某个登录用户指定到新版本,其他用户指定到旧版本,可以实现AB测试等功能。
接下来看一个VirtualService的配置示例,根据特定用户将流量分发至不同版本:
apiVersion: networking.istio.io/v1beta1
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
上面参数说明:
注意:VirtualService路由规则按照从上往下的顺序进行匹配,第一个规则有最高的优先级,如果不满足第一个路由规则,则流量会选择下一个规则。
除了上述的路由匹配外,VirtualService也支持域名+路径的方式进行路由。比如后端有两个服务,一个是reviews,通过http://?**bookinfo.com/reviews访问;另一个是ratings,通过http://?bookinfo.com/ratings**访问。此时可以配置VirtualService如下:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- bookinfo.com
http:
- match:
- uri:
prefix: /reviews
route:
- destination:
host: reviews
- match:
- uri:
prefix: /ratings
route:
- destination:
host: ratings
将VirtualService理解为Kubernetes Service层面,DestinationRule理解为Service后端真实的目标地址,即VirtualService用于Service层面的路由管控,DestinationRule用于对后端真实的服务再做进一步的划分。比如存在一个Service名为paycenter,指向后端多个paycenter的Pod(该Pod可能是不同的Deployment创建的),而DestinationRule可以对后端的多个Pod区分新旧版本,划分成不同的subnet,之后VirtualService可以针对不同的版本进行流量管控。
在下面的示例中,目标规则为 my-svc 目标服务配置了 3 个具有不同负载均衡策略的子集:
apiVersion: networking.istio.io/v1beta1
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
:这是一个用于定义流量策略的部分。在这个例子中,定义了三个子集(subsets
)的流量策略loadBalancer
:用于指定负载均衡算法的配置subsets
:这里定义了三个子集(v1、v2、v3),每个子集通过 labels
来选择对应版本的服务实例。第一个子集 v1
对应版本为 v1
的服务实例,并使用 simple: RANDOM
负载均衡策略。这意味着请求将随机路由到 v1
子集中的服务实例;第二个子集 v2
对应版本为 v2
的服务实例,并使用 simple: ROUND_ROBIN
负载均衡策略。这意味着请求将以循环方式(Round Robin)路由到 v2
子集中的服务实例;第三个子集 v3
对应版本为 v3
的服务实例。在这里没有指定负载均衡策略,因此将使用默认的负载均衡策略。每个子集都是基于一个或多个 labels
定义的,在 Kubernetes 中它是附加到像 Pod 这种对象上的键/值对。这些标签应用于 Kubernetes 服务的 Deployment 并作为 metadata
来识别不同的版本。
除了定义子集之外,此目标规则对于所有子集都有默认的流量策略,而对于该子集, 则有特定于子集的策略覆盖它。定义在 subsets
上的默认策略,为 v1
和 v3
子集设置了一个简单的随机负载均衡器。在 v2
策略中,轮询负载均衡器被指定在相应的子集字段上
默认情况下,Istio 使用轮询的负载均衡策略,实例池中的每个实例依次获取请求。Istio 同时支持如下的负载均衡模型, 可以在 DestinationRule
中为流向某个特定服务或服务子集的流量指定这些模型。
Istio同样支持网关功能,可以使用Gateway在网格最外层接收HTTP/TCP流量,并将流量转发到网格内的某个服务。
在安装Istio时,可以在istio-system命名空间下安装ingressgateway的Pod,用来充当Ingress Gateway。其中Ingress Gateway为入口网关,可以将网格内的服务“暴露”出去,一般和VirtualService配置使用,并配置一个可以被外部服务访问的域名,从而外部服务可以通过该域名访问网格内的服务。
配置Gateway和Istio其他资源类似,kind指定为Gateway即可。比如配置一个VirtualService和Gateway实现对网格内的某个服务进行发布,首先创建一个Gateway,代码如下:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
上面参数说明:
之后配置一个VirtualService与之匹配,即可通过该域名访问VirtualService配置的服务。比如将http://httpbin.example.com的/status和/delay代理到httpbin服务的8000端口:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
host: httpbin
port:
number: 8000
之后将域名解析至ingressgateway Pod的Service上即可访问该域名。