Kubernetes服务网格(第10部分):服务网格API
作为我们上个月发布的Linkerd1.0的一部分,我们已经悄悄地看到了很少有人注意的东西——Linkerd的服务网格API。随着1.0版本的发布,我们认为我们需要花些时间来解释这个API的作用,以及它对Linkerd的未来意味着什么。我们还将展示这个API的即将发布的一个功能——动态控制Linkerd的每项服务的通信策略。
Linkerd服务网格
今天早上在Gluecon,Buoyant CTO Oliver Gould发表了题为“The Service Mesh”的主题演讲 。在这个主题中,他概述了服务网格的视野,如Linkerd所示例。尽管Linkerd经常被添加到构建在Kubernetes上的增加弹性的系统上,但是服务网格的完整视野远不止于此 。正如William Morgan在他的博客文章"什么是服务网格?"表明的:
服务网格的明确目标是将服务通信从隐形的基础设施领域中转移到生态系统的重要一员 - 在这里可以对其进行监控,管理和控制。
对于Linkerd来说,这意味着它行为的每个方面不应该仅被检测和观察,而是在运行时同样可以控制。理想情况下,应该使用这种可更改性替换旧的版本,不是通过编辑配置文件和热重载,而是通过一个统一的,设计良好的运行时API来实现。
简言之,这就是Linkerd的服务网格API的目的。为此,我们引入了io.l5d.mesh
解释器和 a new gRPC API for Namerd。这些功能一起提供了动态控制路由策略的能力,并形成了Linkerd服务网格API的核心。这是实现对Linkerd行为的每个方面提供统一的全球控制模式的最终目标的第一步。
Linkerd 1.0还引入了一种还没通过服务网格API揭露的新策略——每个服务通信的略。在这篇文章中,我们将展示如何配置这个策略,并且我们将介绍后续将此控件添加到Linkerd的服务网格API所需的工作。
本文是关于Linkerd,Kubernetes和服务网格的一系列文章之一 。本系列的其他部分包括:
- 顶级服务指标
- Pod很好,至少看上去如此
- 加密所有的东西
- 通过流量转移进行连续部署
- Dogfood环境,入口和边缘路由
- 没有痛苦的分期微服务
- 使分布式跟踪变得容易
- Linkerd作为入口控制器
- gRPC乐趣和盈利
- Service Mesh API(本文)
- 出口
- 重估预算,截止日期传播,和优雅失败
- 通过顶级指标自动缩放
通信策略
Linkerd的新的每项服务 通信政策 是一个经常要求的功能。通信策略涵盖了Linkerd如何代理请求的各个方面,包括:在超时之前我们应该等待服务处理请求多久?哪种请求可以安全重试?我们是否应该加密与TLS的通信,以及我们应该使用哪个证书?等等。
让我们来看看现在如何使用这个策略,以两个具有截然不同的延迟的服务为例。
从一个新的Kubernetes集群开始,让我们部署两个具有不同延迟的服务。我们以hello world
从本系列的其他文章中部署我们熟悉的微服务,只需稍作调整:hello
服务将在配置中添加500ms
人工延迟。
-name:service
image: buoyantio/helloworld:0.1.2
args:
- "-addr=:7777"
- "-text=Hello"
- "-target=world"
- "-latency=500ms"
使用以下命令将其部署到你的Kubernetes集群:
kubectl apply -f https://raw.githubusercontent.com/BuoyantIO/linkerd-examples/master/k8s-daemonset/k8s/hello-world-latency.yml
(注意,在这些博客文章的例子假设Kubernetes在像GKE这种外部负载均衡器IP可用并且不需要使用CNI插件的环境中运行,其他环境中微小的修正-见我们的 Flavors of Kubernetes forum posting 一文介绍如何使用Calico / Weave处理Minikube或用Calico/Weave配置CNI。)
我们下一步将部署Linkerd服务网格。我们希望添加一个超时,以便能中止(并可能重连)时间过长的请求,但是我们遇到了一个问题。该world
服务很快,响应时间在 100ms
以内,但 hello
服务很慢,响应时间超过500ms
。如果我们仅仅设置超时时间100ms
,那么对world
服务的请求将会成功,但是对hello
服务的请求将会超时。另一方面,如果我们设置超时时间超过 500ms
那么我们需要给worl
服务一个比所需的更长的超时时间,这可能会给我们的调用者带来问题 。
为了给每个服务一个适当的超时时间,我们可以使用Linkerd 1.0为每个服务设置精确的新配置为每个服务设置一个单独的通信策略:
service:
kind: io.l5d.static
configs:
- prefix: /svc/hello
totalTimeoutMs: 600ms
- prefix: /svc/world
totalTimeoutMs: 100ms
该配置会建立以下超时:
我们可以使用这个命令来配置Linkerd服务网格:
kubectl apply -f https://raw.githubusercontent.com/BuoyantIO/linkerd-examples/master/k8s-daemonset/k8s/linkerd-latency.yml
一旦Kubernetes为Linkerd提供了一个外部的负载均衡 IP,我们就可以用它测试hello
和 world
两个服务的请求,并确保两者在各自的超时时间内处理。
$ L5D_INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}")
$ curl $L5D_INGRESS_LB:4140 -H "Host: hello"
Hello (10.196.1.242) world (10.196.1.243)!!
$ curl $L5D_INGRESS_LB:4140 -H "Host: world"
world (10.196.1.243)!!
(注意,前几个请求会比较慢,因为它们必须建立连接并可能超时,后续请求都会成功。)
我们还可以手动地增加hello
和world
服务的等待时间直到他们超时为止来检查它们的超时时间。我们将将增加hello
服务的手动延迟到600ms
。考虑到hello
服务的超时时间是600ms
这留给hello服务的开销为零,因此每个请求都该设置超时如下:
$ curl "$L5D_INGRESS_LB:4140/setLatency?latency=600ms" -X POST -H "Host: hello"
ok
$ curl $L5D_INGRESS_LB:4140 -H "Host: hello"
exceeded 600.milliseconds to unspecified while waiting for a response for the request, including retries (if applicable). Remote Info: Not Available
同样,我们可以 给 world
服务添加100ms
人为延迟,这将导致所有请求到 world
服务违反100ms
超时。
$ curl "$L5D_INGRESS_LB:4140/setLatency?latency=100ms" -X POST -H "Host: world"
ok
$ curl $L5D_INGRESS_LB:4140 -H "Host: world"
exceeded 100.milliseconds to unspecified while waiting for a response for the request, including retries (if applicable). Remote Info: Not Available
一切顺利!我们为每个服务设置了合适的超时时间,并且证明了这些超时有(或者)没有违反预期。
在这个例子中,我们只是配置超时,但是,正如你所期望的那样,可以使用相同的模式来配置任何类型的每项服务通信策略,包括响应分类或重估预算。
展望
在这篇文章中,我们已经看到了一个使用Linkerd的处理两个有很大不同预估延迟的服务的新的策略。每个服务通信策略的引入为Linkerd用户解决了一些直接的用例。但是我们在这里看到的仅仅是Linkerd中通信策略控制的开始——这个策略是从一开始就可以动态更新的,并且明确的目标是使其成为服务网格API的一部分。
在接下来的几个月中,我们将把这个通信策略和路由策略一起添加到Linkerd的服务网格API中。更长远来看,其他形式的策略(包括速率限制,请求分支策略和安全策略 )都在 Linkerd路线图上,并将形成更多Linkerd的服务网格API。Linkerd运行时行为的全面控制,是一个一致统一的,设计良好的服务网格API,是我们将Linkerd作为云本地应用服务网格的核心。
- 微信群之间消息自动转发简明教程(Github上免费共享有代码和教程)
- 使用CNN+ Auto-Encoder 实现无监督Sentence Embedding (代码基于Tensorflow)
- Flume日志收集系统架构详解
- 讨厌算法的程序员 | 第六章 归并排序
- 基于Spark /Tensorflow使用CNN处理NLP的尝试
- 一个优雅的框架 | Pytorch 初体验
- ffmpeg的时基
- FFmpeg菜鸡互啄#第7篇#文件/rtsp推流到rtmp
- H.264格式分析
- JS高级-数据结构的封装
- JS数组去重的三种方法
- 秒懂JS对象、构造器函数和原型对象之间的关系
- nginx rtmp server搭建
- 微信小程序-实战巩固(二)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SpringMVC系列之SpringMVC快速入门 MVC设计模式介绍+什么是SpringMVC+ SpringMVC的作用及其基本使用+组件解析+注解解析
- [Go] GoAdminGroup/go-admin的安装和运行
- 算法篇:滑动窗口(一)
- PHP代码审计02之filter_var()函数缺陷
- Flutter基础widgets教程-Tooltip篇
- 08 . Jenkins之SpringCloud微服务+Vue+Docker持续集成
- Spark 模型选择和调参
- Spark Parquet详解
- Spark 频繁模式挖掘
- Flutter基础widgets教程-WidgetsApp篇
- Js中Number对象
- Flutter基础widgets教程-Scaffold篇
- Redis:主从复制
- Flutter基础widgets教程-Baseline篇
- whereis命令