背景
在基于的微服务体系结构中,都会存在一些需要解决的问题,例如当我们的不同服务(应用)直接进行交互访问,如何进行流量控制、鉴权、服务熔断、治理等问题,不同的微服务架构实现这些功能方式不一,像Spring Cloud与Netflix OSS是偏向于通过使用微服务的框架来实现,而基于Kubernetes的微服务体系是通过服务网格方式来进行实现
什么是服务网格(Service Mesh):服务网格指的是专门处理服务通讯的基础设施层,目前比较主流的有Istio
简介 Istio 是一个由谷歌、IBM 与 Lyft 共同开发的开源项目,旨在提供一种统一化的微服务连接、安全保障、管理与监控方式。Istio 项目能够为微服务架构提供流量管理机制,同时亦为其它增值功能(包括安全性、监控、路由、连接管理与策略等)创造了基础。这款软件利用久经考验的 Lyft Envoy 代理进行构建,可在无需对应用程序代码作出任何发动的前提下实现可视性与控制能力。
Envoy 服务代理扩展了 Kubernetes,以建立一个可编程的、可感知的应用程序网络。Istio 与 Kubernetes 和传统工作负载一起使用,为复杂的部署带来了标准的通用流量管理、遥测和安全性。
特点 流量管理:部署服务间路由,故障恢复和负载平衡等功能。
可观测性:提供流量和服务性能的端到端视图。
安全:跨服务进行加密,基于角色的访问和身份验证。
概念 流量管理 流量管理指的是在Client调用到我们服务的过程中对其进行管理,包括其路由到指定服务,负载均衡,服务熔断超时重试等
Gateway:它控制网络边界,指定了从外部网络进入Istio网络的请求如何被处理。Gateway定义了负责处理请求的服务器,以及请求的进入端点。
VirtualService:它控制网络流量,指定了请求如何被路由到服务。VirtualService定义了请求如何到达特定的服务,以及在路由到服务时的其他流量控制策略。
DestinationRule:它控制服务流量,指定了请求如何被路由到服务的具体实例。DestinationRule定义了服务的抖动行为、负载均衡策略和请求的拆分策略。
虚拟服务(VirtualService) 虚拟服务(Virtual Service)是Istio组件之一,用于将服务网格内的请求路由到对应的服务,每个虚拟服务包含一组路由规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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
hosts:虚拟服务主机地址,即用户指定的目标或是路由规则设定的目标。这是客户端向服务发送请求时使用的一个或多个地址。可以是IP、域名、通配符
match:路由匹配,支持正则
destination:目的地址
更多参考官方文档:https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/
目标规则(Destination Rule) 目标规则(Destination Rule)配合虚拟服务,用于配置目的地址的负载均衡,服务子集版本等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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
负载均衡支持
随机:请求以随机的方式转到池中的实例。
权重:请求根据指定的百分比转到实例。
最少请求:请求被转到最少被访问的实例。
网关(Gateway) 网关主要用于管理入站和出栈流量, Istio 的网关资源可以配置 4-6 层的负载均衡属性,如对外暴露的端口、TLS 设置等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 serverCertificate: /tmp/tls.crt privateKey: /tmp/tls.key
这个网关配置让 HTTPS 流量从 ext-host.example.com 通过 443 端口流入网格,但没有为请求指定任何路由规则。为想要工作的网关指定路由,您必须把网关绑定到虚拟服务上
1 2 3 4 5 6 7 8 9 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: virtual-svc spec: hosts: - ext-host.example.com gateways: - ext-host-gwy
服务入口(Service Entry) 使用服务入口(Service Entry) 来添加一个入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样。配置服务入口允许你管理运行在**网格外的服务的流量 **,它包括以下几种能力:
为外部目标 redirect 和转发请求,例如来自 web 端的 API 调用,或者流向遗留老系统的服务。
为外部目标定义重试、超时和故障注入策略。
添加一个运行在虚拟机的服务来扩展您的网格。
示例:将 ext-resource 外部依赖项添加到 Istio 的服务注册中心:
1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: svc-entry spec: hosts: - ext-svc.example.com ports: - number: 443 name: https protocol: HTTPS location: MESH_EXTERNAL resolution: DNS
配置DR设置超时时间
1 2 3 4 5 6 7 8 9 10 apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: ext-res-dr spec: host: ext-svc.example.com trafficPolicy: connectionPool: tcp: connectTimeout: 1s
边车(Sidecar) sidecar主要的作用是:
微调 Envoy 代理接受的端口和协议集。
限制 Envoy 代理可以访问的服务集合。
原理
应用 安装Istio
获取istio
1 curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.16.2 TARGET_ARCH=arm_64 sh -
移动可执行二进制文件到
查看版本
安装istio
1 istioctl install --set profile=demo -y
给命名空间添加标签,指示 Istio 在部署应用的时候,自动注入 Envoy 边车代理:
1 kubectl label namespace default istio-injection=enabled
部署应用 官方案例
Bookinfo 应用分为四个单独的微服务:
productpage. 这个微服务会调用 details 和 reviews 两个微服务,用来生成页面。
details. 这个微服务中包含了书籍的信息。
reviews. 这个微服务中包含了书籍相关的评论。它还会调用 ratings 微服务。
ratings. 这个微服务中包含了由书籍评价组成的评级信息。
reviews 微服务有 3 个版本:
v1 版本不会调用 ratings 服务。
v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。
部署
1 kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 apiVersion: v1 kind: Service metadata: name: details labels: app: details service: details spec: ports: - port: 9080 name: http selector: app: details --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-details labels: account: details --- apiVersion: apps/v1 kind: Deployment metadata: name: details-v1 labels: app: details version: v1 spec: replicas: 1 selector: matchLabels: app: details version: v1 template: metadata: labels: app: details version: v1 spec: serviceAccountName: bookinfo-details containers: - name: details image: docker.io/istio/examples-bookinfo-details-v1:1.17.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 securityContext: runAsUser: 1000 --- apiVersion: v1 kind: Service metadata: name: ratings labels: app: ratings service: ratings spec: ports: - port: 9080 name: http selector: app: ratings --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-ratings labels: account: ratings --- apiVersion: apps/v1 kind: Deployment metadata: name: ratings-v1 labels: app: ratings version: v1 spec: replicas: 1 selector: matchLabels: app: ratings version: v1 template: metadata: labels: app: ratings version: v1 spec: serviceAccountName: bookinfo-ratings containers: - name: ratings image: docker.io/istio/examples-bookinfo-ratings-v1:1.17.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 securityContext: runAsUser: 1000 --- apiVersion: v1 kind: Service metadata: name: reviews labels: app: reviews service: reviews spec: ports: - port: 9080 name: http selector: app: reviews --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-reviews labels: account: reviews --- apiVersion: apps/v1 kind: Deployment metadata: name: reviews-v1 labels: app: reviews version: v1 spec: replicas: 1 selector: matchLabels: app: reviews version: v1 template: metadata: labels: app: reviews version: v1 spec: serviceAccountName: bookinfo-reviews containers: - name: reviews image: docker.io/istio/examples-bookinfo-reviews-v1:1.17.0 imagePullPolicy: IfNotPresent env: - name: LOG_DIR value: "/tmp/logs" ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp - name: wlp-output mountPath: /opt/ibm/wlp/output securityContext: runAsUser: 1000 volumes: - name: wlp-output emptyDir: {} - name: tmp emptyDir: {}--- apiVersion: apps/v1 kind: Deployment metadata: name: reviews-v2 labels: app: reviews version: v2 spec: replicas: 1 selector: matchLabels: app: reviews version: v2 template: metadata: labels: app: reviews version: v2 spec: serviceAccountName: bookinfo-reviews containers: - name: reviews image: docker.io/istio/examples-bookinfo-reviews-v2:1.17.0 imagePullPolicy: IfNotPresent env: - name: LOG_DIR value: "/tmp/logs" ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp - name: wlp-output mountPath: /opt/ibm/wlp/output securityContext: runAsUser: 1000 volumes: - name: wlp-output emptyDir: {} - name: tmp emptyDir: {}--- apiVersion: apps/v1 kind: Deployment metadata: name: reviews-v3 labels: app: reviews version: v3 spec: replicas: 1 selector: matchLabels: app: reviews version: v3 template: metadata: labels: app: reviews version: v3 spec: serviceAccountName: bookinfo-reviews containers: - name: reviews image: docker.io/istio/examples-bookinfo-reviews-v3:1.17.0 imagePullPolicy: IfNotPresent env: - name: LOG_DIR value: "/tmp/logs" ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp - name: wlp-output mountPath: /opt/ibm/wlp/output securityContext: runAsUser: 1000 volumes: - name: wlp-output emptyDir: {} - name: tmp emptyDir: {}--- apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage service: productpage spec: ports: - port: 9080 name: http selector: app: productpage --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-productpage labels: account: productpage --- apiVersion: apps/v1 kind: Deployment metadata: name: productpage-v1 labels: app: productpage version: v1 spec: replicas: 1 selector: matchLabels: app: productpage version: v1 template: metadata: labels: app: productpage version: v1 spec: serviceAccountName: bookinfo-productpage containers: - name: productpage image: docker.io/istio/examples-bookinfo-productpage-v1:1.17.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp securityContext: runAsUser: 1000 volumes: - name: tmp emptyDir: {}---
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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
查看Service
1 2 3 4 5 6 7 8 9 [root@k8s-master01 bookinfo]# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE demo ClusterIP 10.105 .133 .95 <none> 80 /TCP 91 d details ClusterIP 10.98 .114 .171 <none> 9080 /TCP 3 m26s kubernetes ClusterIP 10.96 .0 .1 <none> 443 /TCP 98 d nginx ClusterIP None <none> 80 /TCP 14 d productpage ClusterIP 10.102 .82 .121 <none> 9080 /TCP 3 m15s ratings ClusterIP 10.101 .219 .48 <none> 9080 /TCP 3 m15s reviews ClusterIP 10.111 .191 .190 <none> 9080 /TCP 3 m15s
查看Pod
访问
1 kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
1 <title>Simple Bookstore App</title>
对外开放
经上述步骤部署成功后我们需要对其进行提供外部访问,需要创建 Istio 入站网关(Ingress Gateway), 它会在网格边缘把一个路径映射到路由。
把应用关联到istio网关
1 kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
查看集群是否支持外部负载均衡
1 kubectl get svc istio-ingressgateway -n istio-system
1 2 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.96 .248 .193 <pending> 15021 :31675/TCP,80:30703/TCP,443:32396/TCP,31400:31654/TCP,15443:30816/TCP 88m
设置 EXTERNAL-IP 的值之后, 您的环境就有了一个外部的负载均衡器,可以将其用作入站网关。 但如果 EXTERNAL-IP 的值为 (或者一直是 状态), 则您的环境则没有提供可作为入站流量网关的外部负载均衡器。 在这个情况下,您还可以用服务(Service)的节点端口访问网关。
通过节点端口访问网关,设置入站端口
1 2 export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}' )export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}' )
设置入站访问入口
1 2 3 export INGRESS_HOST=worker-node-address //如export INGRESS_HOST=192.168.100.21
1 export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}' )
设置环境变量
1 export GATEWAY_URL=$INGRESS_HOST :$INGRESS_PORT
查看访问Endpoint
验证外部访问
1 echo "http://$GATEWAY_URL/productpage"
1 http://192.168.100.21:30703/productpage
我们在访问的时候会随机的打到三个服务上,
修改路由把全部流量指向v1
1 kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: productpage spec: hosts: - productpage http: - route: - destination: host: productpage subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - route: - destination: host: reviews subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: ratings spec: hosts: - ratings http: - route: - destination: host: ratings subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: details spec: hosts: - details http: - route: - destination: host: details subset: v1 ---
安装仪表盘
创建可视化仪表盘
创建可视化仪表盘
1 2 kubectl apply -f samples/addons kubectl rollout status deployment/kiali -n istio-system
访问仪表盘
1 2 3 istioctl dashboard kiali istioctl dashboard kiali --address 192.168 .100 .21
以上案例体验完后想删除可直接直接clean脚本进行清除
1 samples/bookinfo/platform/kube/cleanup.sh
案例 配置请求路由
如何将请求动态路由到微服务的多个版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: reviews spec: host: reviews subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 - name: v3 labels: version: v3
所有请求指向同一个版本
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - route: - destination: host: reviews subset: v1
基于用户身份的路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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: v1
故障注入 此任务说明如何注入故障并测试应用程序的弹性。
流量转移 展示如何将流量从旧版本迁移到新版本的服务。
TCP 流量转移 展示如何将一个服务的 TCP 流量从旧版本迁移到新版本。
设置请求超时 本任务用于示范如何使用 Istio 在 Envoy 中设置请求超时。
熔断 本任务展示如何为连接、请求以及异常检测配置熔断。
镜像 此任务演示了 Istio 的流量镜像/影子功能。
地域负载均衡 本系列任务演示如何在 Istio 中配置地域负载均衡。
Ingress 控制 Istio 服务网格的入口流量。
Egress 控制 Istio 服务网格的出口流量。
资料
官网 :https://istio.io/latest/zh/
github:https://github.com/istio/istio