注意事项 佩雷夫 :本系列的第一部分专门介绍Istio并在实际中进行演示。 现在,我们将讨论该服务网格的配置和使用的更复杂方面,尤其是关于微调的路由和网络流量管理。
我们还提醒您,本文使用istio-mastery存储库中的配置(Kubernetes和Istio的清单)。 交通管理
使用Istio,新功能会出现在群集中,以提供:
- 动态查询路由 :金丝雀推出,A / B测试;
- 负载平衡 :简单且一致,基于哈希;
- 秋季恢复 :超时,重试,断路器;
- 故障输入 :延迟,请求中断等
在本文的后续部分,这些功能将作为所选应用程序的示例显示,并且将在此过程中引入新的概念。 第一个这样的概念将是
DestinationRules
(即有关流量/请求接收者的规则-大约是Transl。) ,通过它我们可以启动A / B测试。
A / B测试:实际中的DestinationRules
如果应用程序有两个版本(通常在视觉上有所不同),并且我们不确定100%确定哪个版本可以改善用户交互,则使用A / B测试。 因此,我们同时启动两个版本并收集指标。
要部署演示A / B测试所需的前端的第二个版本,请运行以下命令:
$ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml deployment.extensions/sa-frontend-green created
“绿色版本”的部署清单在两个地方有所不同:
- 该图片基于另一个标记
istio-green
, - 豆荚有一个
version: green
标签。
由于两个部署都具有
app: sa-frontend
标签,因此由
sa-external-services
虚拟服务路由到
sa-frontend
服务的请求将被重定向到其所有实例,并且将使用
round-robin算法分配负载,这将导致以下情况:
找不到请求的文件找不到这些文件是因为它们在应用程序的不同版本中被不同地调用。 让我们确保这一点:
$ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main /static/css/main.c7071b22.css /static/js/main.059f8e9c.js $ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main /static/css/main.f87cd8c9.css /static/js/main.f7659dbb.js
这意味着,请求平衡文件的一种版本的
index.html
可以由负载平衡器发送到具有不同版本的Pod,在这些Pod中,由于明显的原因,这些文件不存在。 因此,为了使该应用程序正常工作,我们需要施加一个限制:“
提供index.html的相同版本的应用程序也必须满足后续请求 。”
我们将通过基于一致性的基于哈希的负载平衡
(Consistent Hash Loadbalancing)来实现该目标。 在这种情况下,
来自一个客户端的请求将发送到同一后端实例 ,该
后端实例使用预定义的属性-例如HTTP标头。 使用DestinationRules实现。
DestinationRules
在
VirtualService向所需的服务发送请求之后,使用DestinationRules,我们可以确定将应用于发往该服务实例的流量的策略:
Istio资源流量管理注意 :此处以简化的方式介绍了Istio资源对网络流量的影响。 确切地说,Envoy在CRD中配置的Ingress网关中决定将请求发送到哪个实例。
使用目标规则,我们可以配置负载平衡,以便使用一致的哈希值,并确保来自同一服务实例的响应被提供给同一用户。 通过以下配置,此
目标地址 (
destinationrule-sa-frontend.yaml )可以实现此目的:
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sa-frontend spec: host: sa-frontend trafficPolicy: loadBalancer: consistentHash: httpHeaderName: version # 1
1-将基于HTTP
version
标头的内容生成哈希。
使用以下命令应用配置:
$ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml destinationrule.networking.istio.io/sa-frontend created
现在运行下面的命令,并确保在指定
version
头时获得所需的文件:
$ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' '\n' | grep main
注意 :要在标题中添加不同的值并直接在浏览器中测试结果,您可以
将此扩展名用于Chrome
(对于Firefox ,请使用
此扩展名 -大约翻译) 。
通常,DestinationRules在负载均衡领域中有更多选项-请查看
官方文档以了解详细信息。
在进一步探索VirtualService之前,我们将通过执行以下命令来删除应用程序的“绿色版本”和流量方向上的相应规则:
$ kubectl delete -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml deployment.extensions “sa-frontend-green” deleted $ kubectl delete -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml destinationrule.networking.istio.io “sa-frontend” deleted
镜像:实践中的虚拟服务
在我们想要测试生产变更而不影响最终用户的情况下,会使用阴影
(“屏蔽”)或镜像
(“镜像”) :为此,我们在第二次实例中重复(“镜像”)请求,并在必要时进行了更改,看看后果。
简而言之,这是您的(一位)同事选择最关键的问题并以巨大污垢的形式提出拉动请求时,实际上没有人可以对他进行审查。要测试实际情况,请通过运行以下命令来创建第二个带有错误(
buggy
)的SA-Logic实例:
$ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service-buggy.yaml deployment.extensions/sa-logic-buggy created
现在,我们执行命令以确保所有具有
app=sa-logic
实例
app=sa-logic
具有带有相应版本的标签:
$ kubectl get pods -l app=sa-logic --show-labels NAME READY LABELS sa-logic-568498cb4d-2sjwj 2/2 app=sa-logic,version=v1 sa-logic-568498cb4d-p4f8c 2/2 app=sa-logic,version=v1 sa-logic-buggy-76dff55847-2fl66 2/2 app=sa-logic,version=v2 sa-logic-buggy-76dff55847-kx8zz 2/2 app=sa-logic,version=v2
sa-logic
针对带有
app=sa-logic
标签的pod,因此所有请求将在所有实例之间分配:

...但是我们希望将请求定向到版本v1的实例并镜像到版本v2的实例:

我们将通过将VirtualService与DestinationRule结合使用来实现此目标,在DestinationRule中,规则将确定VirtualService的子集和到特定子集的路由。
在目标规则中定义子集
子集由以下配置(
sa-logic-subsets-destinationrule.yaml )定义:
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sa-logic spec: host: sa-logic # 1 subsets: - name: v1 # 2 labels: version: v1 # 3 - name: v2 labels: version: v2
host
确定此规则仅适用于路由进入sa-logic
;- 路由到子集的实例时使用子集的名称。
- 标签定义实例必须匹配的键/值对,才能成为子集的一部分。
使用以下命令应用配置:
$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-destinationrule.yaml destinationrule.networking.istio.io/sa-logic created
现在已经定义了子集,您可以继续并配置VirtualService以将规则应用于对sa-logic的请求,以便它们:
- 路由到
v1
的子集, - 镜像到
v2
的子集。
以下清单可帮助您实现计划(
sa-logic-subsets-shadowing-vs。yaml ):
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 mirror: host: sa-logic subset: v2
这里不需要解释,因此只需看一下操作即可:
$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing-vs.yaml virtualservice.networking.istio.io/sa-logic created
通过调用以下命令来添加负载:
$ while true; do curl -v http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done
让我们看一下Grafana中的结果,在这里我们可以看到有
buggy
版本在大约60%的请求中崩溃,但是这些崩溃都不会影响最终用户,因为他们拥有有效的服务。
不同版本的sa-logic服务的响应成功在这里,我们首先看到了如何将VirtualService应用于服务的Envoy:当
sa-web-app
向
sa-logic
发出请求时,它将通过sidecar Envoy,后者通过VirtualService被配置为将请求路由到子集v1和镜像对
sa-logic
v2的子集的请求。
我知道:您已经有时间认为虚拟服务很简单。 在下一部分中,我们通过它们也确实很棒的事实来扩展这种观点。
金丝雀卷
Canary Deployment是为少数用户推出应用程序新版本的过程。 它用于确保发行版中没有问题,仅在此之后,已经对其足够的(发行版)质量充满信心,才能传播到更大的受众群体。
为了演示金丝雀的推出,我们将继续使用
sa-logic
的
buggy
集。
让我们不要浪费时间,立即将20%的用户发送给有错误的版本(它将代表我们的Canary推出),其余80%的用户返回正常服务。 为此,请应用以下VirtualService(
sa-logic-subsets-canary-vs.yaml ):
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 weight: 80 # 1 - destination: host: sa-logic subset: v2 weight: 20 # 1
1是权重,它确定将发送给接收者或接收者子集的请求的百分比。
sa-logic
以下命令为
sa-logic
更新以前的VirtualService配置:
$ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yaml virtualservice.networking.istio.io/sa-logic configured
...并立即看到部分请求崩溃:
$ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}' \ --silent -w "Time: %{time_total}s \t Status: %{http_code}\n" \ -o /dev/null; sleep .1; done Time: 0.153075s Status: 200 Time: 0.137581s Status: 200 Time: 0.139345s Status: 200 Time: 30.291806s Status: 500
VirtualServices激活了金丝雀的推出:在这种情况下,我们将问题的潜在影响范围缩小到了20%的用户群。 太好了! 现在,在每种情况下,当我们不确定我们的代码时(换句话说,总是...),我们可以使用镜像和canary卷展栏。
超时和重试
但并非总是在代码中包含错误。 在“
分布式计算中的
8个错误 ”列表中,首先出现了“网络可靠”的错误观点。 实际上,网络是
不可靠的,因此,我们需要超时和
重试 。
为了进行演示,我们将继续使用相同版本的
sa-logic
(
buggy
),并将模拟随机故障导致的网络不可靠性。
让我们的错误服务有1/3的机会响应时间太长,有1/3的机会完成内部服务器错误,有1/3的机会返回成功的页面。
为了减轻此类问题的后果并改善用户的生活,我们可以:
- 如果服务响应时间超过8秒,请添加超时,
- 如果请求失败,请重试。
为了实现,我们将使用以下资源定义(
sa-logic-retries-timeouts-vs.yaml ):
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sa-logic spec: hosts: - sa-logic http: - route: - destination: host: sa-logic subset: v1 weight: 50 - destination: host: sa-logic subset: v2 weight: 50 timeout: 8s # 1 retries: attempts: 3 # 2 perTryTimeout: 3s # 3
- 请求的超时设置为8秒;
- 重复请求尝试3次;
- 如果响应时间超过3秒,则每次尝试都将被视为失败。
因此,我们已经实现了优化,因为用户不必等待超过8秒的时间,并且在发生故障时我们将进行三种新的尝试来获得答案,从而增加了成功响应的机会。
使用以下命令应用更新的配置:
$ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts-vs.yaml virtualservice.networking.istio.io/sa-logic configured
并检查Grafana的图形,成功答案的数量已经结束:
添加超时和重试后,成功响应统计信息的改进在继续下一节
(或者,因为本文中不会进行更多实验-大约翻译)之前 ,请通过运行以下命令删除
sa-logic-buggy
和VirtualService:
$ kubectl delete deployment sa-logic-buggy deployment.extensions “sa-logic-buggy” deleted $ kubectl delete virtualservice sa-logic virtualservice.networking.istio.io “sa-logic” deleted
断路器和隔板模式
我们正在谈论微服务体系结构中的两个重要模式,这些模式可让您实现
自我修复服务。
电路断路器 (“电路断路器”)用于停止请求到不健康服务实例的请求,并在客户端请求重定向到该服务的健康实例(恢复成功响应的百分比)时恢复该请求。
(注意:例如,可以在这里找到关于模式的更详细的描述。)隔板 (“分区”)将服务故障与整个系统的故障隔离开来。 例如,服务B中断,另一个服务(服务B的客户端)向服务B发出请求,结果它将耗尽其线程池,并且将无法服务其他请求(即使它们与服务B不相关)。
(注意:例如,可以在这里找到关于模式的更详细的描述。)我将省略有关这些模式的实现的详细信息,因为它们在
官方文档中很容易找到,并且我确实想显示身份验证和授权,这将在本文的下一部分中进行讨论。
译者的PS
另请参阅我们的博客: