官方文档: Documentation
服务网格是什么
现代应用程序通常被构建为微服务的分布式集合,每个微服务集合执行一些离散的业务功能。服务网格是一个专用的基础设施层,您可以将其添加到您的应用程序中。它允许您透明地添加可观察性
、流量管理
和安全性
等功能,而无需将它们添加到您自己的代码中。术语“服务网格”描述了您用于实现此模式的软件类型,以及您使用该软件时创建的安全或网络域。
随着分布式服务的部署(例如在基于 Kubernetes 的系统中)的规模和复杂性的增长,它可能变得更难理解和管理。它的要求可以包括发现
、负载平衡
、故障恢复
、度量
和监控
。服务网格还经常解决更复杂的操作要求,例如 A/B 测试
、金丝雀部署
、速率限制
、访问控制
、加密
和端到端身份验证
。
Istio 是什么
Istio 是一个开源服务网格,它透明地分层到现有的分布式应用程序上。Istio 的强大功能提供了一种统一且更有效的方式来保护、连接和监控服务。Istio 是负载均衡、服务到服务身份验证和监控的途径 —— 几乎不需要更改服务代码。
其强大的控制平面带来了重要的功能,包括:
- 使用 TLS 加密、强大的基于身份的身份验证和授权来保护集群中的服务到服务通信
- HTTP、gRPC、WebSocket 和 TCP 流量的自动负载平衡
- 通过丰富的路由规则、重试、故障转移和故障注入对流量行为进行细粒度控制
- 支持访问控制、速率限制和配额的可插拔策略层和配置 API
- 集群内所有流量的自动指标、日志和跟踪,包括集群入口和出口
Istio 专为可扩展性而设计,可以处理各种部署需求。 Istio 的控制平面在 Kubernetes 上运行,您可以将部署在该集群中的应用程序添加到您的网格中,将网格扩展到其他集群,甚至连接在 Kubernetes 之外运行的虚拟机或其他端点。
Istio 怎么工作
Istio 有两个组件:数据平面和控制平面
数据平面是服务之间的通信。如果没有服务网格,网络就无法理解发送过来的流量,也无法根据流量类型或来自谁或去向谁做出任何决定。
服务网格使用代理来拦截您的所有网络流量,允许基于您设置的配置的广泛的应用程序感知功能。
Envoy 代理与您在集群中启动的每个服务一起部署,或者与在 VM 上运行的服务一起运行。
控制平面采用您想要的配置及其服务视图,并动态地对代理服务器进行编程,并随着规则或环境的变化对其进行更新。
安装 Istio
Istio 的版本选择: Supported Releases
Istio 下载地址: Istio release
使用 operator 方法安装 istio
首先下载 Istio 的安装包
1
wget https://github.com/istio/istio/releases/download/1.13.2/istio-1.13.2-linux-amd64.tar.gz
解压压缩包后,将 istio 的客户端工具 istioctl 移动到 /usr/local/bin 目录下
1
2
3
4
5
6
7
8tar xf istio-1.13.2-linux-amd64.tar.gz
cd istio-1.13.2/
mv bin/istioctl /usr/local/bin/
# 查看 istio 的版本
# istioctl version
no running Istio pods in "istio-system"
1.13.2接下来安装 Istio 的 Operator,可以使用 istioctl 一键部署
1
2
3
4
5# istioctl operator init
Installing operator controller in namespace: istio-operator using image: docker.io/istio/operator:1.13.2
Operator controller will watch namespaces: istio-system
✔ Istio operator installed
✔ Installation complete出现
Installation complete
后,查看 Pod 是否正常1
2
3# kubectl get pods -n istio-operator
NAME READY STATUS RESTARTS AGE
istio-operator-7f58846f8f-59gd9 1/1 Running 0 2m22s通过定义 Istio Operator 资源
istio-operator.yaml
,在 kubernetes 中安装 Istio1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
name: example-istiocontrolplane
spec:
profile: default
components:
ingressGateways:
- name: istio-ingressgateway
enabled: true
k8s:
service:
type: NodePort
ports:
- port: 15020
nodePort: 30520
name: status-port
- port: 80 # 流量入口 80 端口映射到 NodePort 30080,之后通过节点 IP + 30080 即可访问 Istio 服务
nodePort: 30080
name: http2
targetPort: 8080
- port: 443
nodePort: 30443
name: https
targetPort: 8443执行以下命令安装 Istio
1
2
3
4
5
6
7
8
9# istioctl manifest apply -f istio-operator.yaml
This will install the Istio 1.13.2 default profile with ["Istio core" "Istiod" "Ingress gateways"] components into the cluster. Proceed? (y/N) y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete
Making this installation the default for injection and validation.
Thank you for installing Istio 1.13. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/pzWZpAvMVBecaQ9h9查看创建的 service 和 pod
1
2
3
4
5
6
7
8# kubectl get pods,svc -n istio-system
NAME READY STATUS RESTARTS AGE
pod/istio-ingressgateway-54799bcf46-6rmxq 1/1 Running 0 4m17s
pod/istiod-5b6d7d4cb5-rwr6k 1/1 Running 0 5m30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/istio-ingressgateway NodePort 10.97.205.15 <none> 15020:30520/TCP,80:30080/TCP,443:30443/TCP 4m17s
service/istiod ClusterIP 10.105.81.210 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 5m30s配置自动注入,修改 APIServer 的配置文件,添加 MutatingAdmissionWebhook,ValidatingAdmissionWebhook(如果 K8s 版本大于 1.16 默认已经开启):
1
2# vi /etc/kubernetes/manifests/kube-apiserver.yaml # 二进制安装方式需要找到 APIServer 的 Service 文件
- --enable-admission-plugins=MutatingAdmissionWebhook,ValidatingAdmissionWebhook # 本示例省略了其它配置项,读者需要追加这两项即可- 接下来创建一个测试的 namespace,并添加一个
istio-injection=enabled
的标签,之后在该 namespace 下创建的 Pod 就会被自动注入 Istio 的 Proxy。
1
2kubetl create ns bookinfo
kubectl label ns bookinfo istio-injection=enabled- 接下来创建一个测试的 namespace,并添加一个
安装 Kiali 图形界面
Kiali 为 Istio 提供了可视化的界面,可以在 Kiali 上进行观测流量的走向、调用链,同时还可 以使用 Kiali 进行配置管理,给用户带来了很好的体验。
接下来在 Kubernetes 中安装 Kiali 工具。
首先进入到 Istio 的安装包目录,执行以下命令
1
2
3
4
5
6
7
8
9
10
11cd ~/istio-1.13.2
# kubectl create -f samples/addons/kiali.yaml
serviceaccount/kiali created
configmap/kiali created
clusterrole.rbac.authorization.k8s.io/kiali-viewer created
clusterrole.rbac.authorization.k8s.io/kiali created
clusterrolebinding.rbac.authorization.k8s.io/kiali created
role.rbac.authorization.k8s.io/kiali-controlplane created
rolebinding.rbac.authorization.k8s.io/kiali-controlplane created
service/kiali created
deployment.apps/kiali created查看部署状态
1
2
3
4
5
6# kubectl get pod,svc -n istio-system -l app=kiali
NAME READY STATUS RESTARTS AGE
pod/kiali-699f98c497-qjnnx 1/1 Running 0 55s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kiali ClusterIP 10.99.252.158 <none> 20001/TCP,9090/TCP 55s可以将 Service 类型修改为 NodePort,或者配置 Ingress 即可访问 kiali 服务
安装链路追踪工具 jaeger
除了 Kiali 之外,还需要一个链路追踪的工具,安装该工具可以在 Kiali 的 Workloads 页面,查看某个服务的 Traces 信息。
输入以下命令直接安装即可:
1
2
3
4
5# kubectl create -f samples/addons/jaeger.yaml
deployment.apps/jaeger created
service/tracing created
service/zipkin created
service/jaeger-collector created查看部署状态
1
2
3
4
5
6
7# kubectl get pod,svc -n istio-system -l app=jaeger
NAME READY STATUS RESTARTS AGE
pod/jaeger-9dd685668-fc5d5 1/1 Running 0 42s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/jaeger-collector ClusterIP 10.102.222.140 <none> 14268/TCP,14250/TCP,9411/TCP 42s
service/tracing ClusterIP 10.103.162.193 <none> 80/TCP,16685/TCP 42s
Kiali 与 Jaeger 进行关联
为了可以将 jaeger 暴露在 k8s 集群外访问,需要将 tracing 的 ClusterIP 服务类型更改为 NodePort。执行语句如下
1
kubectl patch svc -n istio-system tracing -p '{"spec":{"type": "NodePort"}}'
查看 jaeger svc 端口
1
2
3
4# kubectl get svc -n istio-system -l app=jaeger
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jaeger-collector ClusterIP 10.96.140.113 <none> 14268/TCP,14250/TCP,9411/TCP 8d
tracing NodePort 10.96.24.11 <none> 80:31509/TCP,16685:30139/TCP 8d使用浏览器访问 jaeger UI http://10.1.40.70:31509
注意:
10.1.40.70
为 k8s 集群的 VIP 地址-
点击上面箭头
Distributed Tracing
链接可以打开 jaeger。如果访问不到,说明你本地的浏览器并不能直接访问到 kiali 设置的 jaeger 外部链接。注意:默认是没有的,关联之后才有该链接。
设置 kiali jaeger 外部链接地址,编辑 kiali
configmap
1
kubectl edit configmap -n istio-system kiali
在
external_services.tracing.url
内容下添加 jaeger 外部链接,链接地址就是 istio-system 命名空间下 jaeger-query 服务的宿主机地址和 nodeport,如下1
2
3
4
5
6
7
8
9
10
11
12
13
14external_services:
grafana:
url: http://grafana:3000
custom_dashboards:
enabled: true
tracing:
auth:
type: none
enabled: true
url: http://10.1.40.70:31509/jaeger
in_cluster_url: http://tracing:16685/jaeger
use_grpc: true
istio:
root_namespace: istio-system编辑 kiali configmap 后,需要删除并重新生成 kiali pod,好让配置挂载生效,执行语句如下
1
kubectl delete pods -n istio-system -l app=kiali
kiali 重启后,查看容器内的
/kiali-configuration/config.yaml
配置文件,查看 url 是否生效1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18kubectl exec -it -n istio-system kiali-5ccffdfd97-xk5b7 -- cat /kiali-configuration/config.yaml
# 输出信息如下
... 省略 N 行 ...
external_services:
grafana:
url: http://grafana:3000
custom_dashboards:
enabled: true
tracing:
auth:
type: none
enabled: true
url: http://10.1.40.70:31509/jaeger
in_cluster_url: http://tracing:16685/jaeger
use_grpc: true
istio:
root_namespace: istio-system再次刷新访问 kiali,就会在左侧栏出现Distributed Tracing,点击它,就会打开jaeger,效果同上!
kiali jaeger 流量关联
以上的操作中通过 kiali 可以打开 jaeger 了,还可以通过实际流量将 kiali 和 jaeger 关联起来,首先打入一些流量,这里采用的是 istio 的官方用例 bookinfo
访问 kiali 的 service 菜单标签:
1
while true; do sleep 1;curl http://192.168.31.16:32223/productpage; done
访问 kiali 的 service 菜单标签
双击 productpage 进入微服务,然后选择标签页 Traces,再点击蓝色圆圈(trace 点)后会显示该 tracing 的路径信息,然后再选择链接(View Trace in Tracing)
安装 Prometheus
Prometheus 是一个开源的监控系统、时间序列数据库。您可以利用 Prometheus 与 Istio 集成来收集指标,通过这些指标判断 Istio 和网格内的应用的运行状况。您可以使用 Grafana 和 Kiali 来可视化这些指标。
Istio 提供了一个简单地安装示例来快速安装、运行 Prometheus:
1
kubectl apply -f samples/addons/prometheus.yaml
这将会在您的集群中部署 Prometheus。这仅用于展示,不会针对性能和安全性进行调整。
注意: 快速开始的配置仅适合小型集群和短期监控,不适用于大型网格和长时间的监控。特别的是,增加标签将会增加指标的基数,需要大量内存。并且,当尝试确定流量随时间的趋势变化,需要获取历史数据。
Istio 使用示例
使用 Istio 发布服务,主要分以下几个步骤:
- 发布服务资源,以及 Service;
- 创建 Gateway,配置域名入口,一般建议一个项目创建一个 gateway,hosts 配置成
*
- 创建 VirtualService,绑定到 Gateway,然后
- 配置域名解析到 DMZ F5,Nginx,SLB,ELB 等入口负载均衡设备上,(由于这里没有公网IP,所以使用 hosts 绑定域名,然后加端口方式访问服务)
部署测试用例服务
首先在 Kubernetes 集群中,部署 Bookinfo 项目。
Istio 提供了用于测试功能的应用程序 Bookinfo,可以直接通过下述命令创建 Bookinfo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36# kubectl create ns bookinfo
namespace/bookinfo created
# kubectl label ns bookinfo istio-injection=enabled
namespace/bookinfo labeled
# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created
# 官方示例里面 reviews 服务的 v1,v2,v3 版本都直接部署了,为方便后面演示,这里将 v2 以及 v3 版本的 reviews 副本数设置为 0
# kubectl scale deployment -n bookinfo --replicas=0 reviews-v2
deployment.apps/reviews-v2 scaled
# kubectl scale deployment -n bookinfo --replicas=0 reviews-v3
deployment.apps/reviews-v3 scaled
# kubectl get deploy -n bookinfo
NAME READY UP-TO-DATE AVAILABLE AGE
details-v1 1/1 1 1 3d19h
productpage-v1 1/1 1 1 3d19h
ratings-v1 1/1 1 1 3d19h
reviews-v1 1/1 1 1 3d19h
reviews-v2 0/0 0 0 3d19h
reviews-v3 0/0 0 0 3d19h查看部署的 Pod 和 service
1
2
3
4
5
6
7
8
9
10
11
12
13
14# kubectl get pods,svc -n bookinfo
NAME READY STATUS RESTARTS AGE
pod/details-v1-79f774bdb9-7kvwz 2/2 Running 6 (3h50m ago) 3d17h
pod/productpage-v1-6b746f74dc-t4nfv 2/2 Running 6 (3h50m ago) 3d18h
pod/ratings-v1-b6994bb9-j9zjt 2/2 Running 6 (3h50m ago) 3d18h
pod/reviews-v1-545db77b95-5jtf5 2/2 Running 6 (3h50m ago) 3d18h
pod/reviews-v2-7bf8c9648f-zxqtm 2/2 Running 6 (3h50m ago) 3d18h
pod/reviews-v3-84779c7bbc-tcwrc 2/2 Running 2 (3h50m ago) 27h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/details ClusterIP 10.96.161.56 <none> 9080/TCP 3d18h
service/productpage ClusterIP 10.106.12.0 <none> 9080/TCP 3d18h
service/ratings ClusterIP 10.106.45.216 <none> 9080/TCP 3d18h
service/reviews ClusterIP 10.107.189.191 <none> 9080/TCP 3d18h此时可以通过 productpage Service 的 ClusterIP 访问 Bookinfo 项目
1
2
3
4
5
6
7
8# curl 10.106.12.0:9080 -I
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 1683
server: istio-envoy
date: Sun, 27 Mar 2022 08:04:09 GMT
x-envoy-upstream-service-time: 2
x-envoy-decorator-operation: productpage.bookinfo.svc.cluster.local:9080/*
部署 Gateway 以及 VirtualService
接下来想要实现域名访问 Bookinfo 项目,需要创建 Gateway 以及 VirtualService 资源
- 首先创建 Gateway,假设域名是 bookinfo.59izt.com,则 Gateway 的资源清单如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # 使用默认的 istio ingress gateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- '*' # 发布域名,一般一个项目创建一个 gateway,或者使用 '*' 作为所有项目的入口- 接下来配置 VirtualService,实现对不同微服务的路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.59izt.com" # 发布的域名
gateways:
- bookinfo-gateway # 指定与哪个 gateway 进行绑定
http:
- match:
- uri:
exact: /productpage # 完全匹配
- uri:
prefix: /static # 非完全匹配
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage # 目标 Service 名称
port:
number: 9080执行以下命令创建 gateway 以及 VirtualService
1
2
3# kubectl create -f bookinfo-gateway.yaml -f bookinfo-vs.yaml -n bookinfo
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created- 查看创建的 gateway 与 vs
1
2
3
4
5
6# kubectl get gw,vs -n bookinfo
NAME AGE
gateway.networking.istio.io/bookinfo-gateway 24s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/bookinfo ["bookinfo-gateway"] ["bookinfo.kubeasy.com"] 24s
配置域名解析(Hosts 绑定)
接下来将域名 bookinfo.59izt.com 解析到集群任意一个安装了 kube-proxy 的节点 IP 上,然后通过 ingressgateway 的 Service 的 NodePort 即可访问到 Bookinfo,输入以下命令查看 istio-ingressgate 相关的信息
1
2
3
4
5
6# kubectl get pods,svc -n istio-system -l app=istio-ingressgateway
NAME READY STATUS RESTARTS AGE
pod/istio-ingressgateway-54799bcf46-6rmxq 1/1 Running 3 (4h21m ago) 3d19h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/istio-ingressgateway NodePort 10.97.205.15 <none> 15020:30520/TCP,80:30080/TCP,443:30443/TCP 3d19h- 通过以上信息可以看到,istio-ingressgateway Service 使用 NodePort 的方式在宿主机上监听了几个端口,接下来配置 hosts 解析
1
192.168.200.110 bookinfo.59izt.com
绑定 hosts 后,通过 bookinfo.59izt.com + ingressgateway 80 端口的 NodePort 既可访问该服务,比如本次示例的
bookinfo.59izt.com:30080/productpage
Istio 实现灰度部署
使用 Istio 实现灰度部署,主要分以下几个步骤:
- 创建 DestinationRule (DR) 将 reviews 服务分成多个 subsets – v1、v2、 v3 等;
- 配置 VirtualService,将所有流量指向 v1 版本
- 部署新版本的服务;
- 调整 VirtualService,将部分流量指向新版本服务
接下来开始测试使用 Istio 部署灰度发布
创建 DestinationRule
创建 DestinationRule,将 reviews 分成三个版本,
reviews-dr.yaml
文件内容如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews # services
subsets:
- name: v1
labels:
version: v1 # subset v1指向具有version=v1的Pod
- name: v2
labels:
version: v2 # subset v2指向具有version=v2的Pod
- name: v3
labels:
version: v3 # subset v3指向具有version=v3的Pod创建 dr 资源
1
2
3
4
5
6# kubectl create -f reviews-dr.yaml -n bookinfo
destinationrule.networking.istio.io/reviews created
# kubectl get dr -n bookinfo
NAME HOST AGE
reviews reviews 15s
配置 VirtualService 将所有流量都指向 v1 版本
创建 reviews-vs.yaml 文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1 # 将流量指向 v1创建 vs 资源
1
2
3
4
5
6
7# kubectl create -f reviews-vs.yaml -n bookinfo
virtualservice.networking.istio.io/reviews created
# kubectl get vs -n bookinfo
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["bookinfo.59izt.com"] 67m
reviews ["reviews"] 17s部署 bookinfo 项目 reviews 服务的 v2 版本,由于之前已经部署了,所以这里只要调整 deployment 的副本数即可
1
2
3
4
5
6
7# kubectl scale deployment -n bookinfo reviews-v2 --replicas=1
deployment.apps/reviews-v2 scaled
# kubectl get pods -n bookinfo -l app=reviews
NAME READY STATUS RESTARTS AGE
reviews-v1-545db77b95-5jtf5 2/2 Running 6 (5h24m ago) 3d20h
reviews-v2-7bf8c9648f-kl5xf 2/2 Running 0 63s注意: 此时访问 bookinfo 项目,无论刷新多少次网页,review 页面还是显示为 v1 版本,因为这时候还没修改 vs 的流量策略
接下来修改 VirtualService,将 20% 的流量导向 v2 版本,修改后的 reviews-vs.yaml 文件内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 80 # 只需要配置一个 weight 参数即可
- destination:
host: reviews
subset: v2
weight: 20 # 将 20% 的流量导向 v2 版本重新 replace 该 vs 资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26# kubectl replace -f reviews-vs.yaml -n bookinfo
virtualservice.networking.istio.io/reviews replaced
# kubectl get vs -n bookinfo reviews -oyaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
creationTimestamp: "2022-03-27T09:33:27Z"
generation: 2
name: reviews
namespace: bookinfo
resourceVersion: "401441"
uid: 59413c53-1b96-4a79-843d-32706e0e49e1
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 80
- destination:
host: reviews
subset: v2
weight: 20可以再次调整 vs,将所有流量都指向 v2,查看是否所有流量都访问到 v2 版本
可以看到, reviews 服务只有 v2 一个版本了