Knative Serving 进阶: Knative Serving SDK 开发实践
作者 | 阿里云智能事业群技术专家 牛秋霖(冬岛)
导读:通过前面的一系列文章你已经知道如何基于 kubectl 来操作 Knative 的各种资源。但是如果想要在项目中集成 Knative 仅仅使用 kubectl 这种命令的方式是不够的,还需要在代码中基于 Knative Serving SDK 进行集成开发。本篇文章中,阿里云智能事业群技术专家冬岛将从 Knative Serving SDK 入手,介绍如何基于 Knative SDK 进行 serverless 开发。
Golang Context
在正式开始介绍 Knative Serving SDK 之前,我们先简单介绍一下 Golang Context 的机理。因为在 Knative Serving 中 client、Informer 的初始化和信息传递完全是基于 Golang Context 实现的。
Golang 是从 1.7 版本开始引入的 Context ,Golang 的 Context 可以很好的简化多个 goroutine 之间以及请求域间的数据传递、取消信号和截至时间等相关操作。Context 主要有两个作用:
- 传输必要的数据;
- 进行协调控制,比如终止 goroutein、设置超时时间等。
Context 定义
Context 本身是一个接口。
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
这个接口中定义了四个方法,下面分别介绍:
- Deadline 方法是获取设置的截止时间的意思,到了这个时间点,Context 会自动发起取消请求;
- Done 方法返回一个只读的 chan,如果该方法返回的 chan 可以读取,则意味着 parent Context 已经发起了取消请求, 此时应该做清理操作,然后退出 goroutine 并释放资源;
- Err 方法返回取消的错误原因;
- Value 方法获取该 Context 上绑定的值,是一个键值对。所以要通过一个 Key 才可以获取对应的值,这个值是线程安全的。
关于 Context 主要记住一点:可以通过 Value 传递数据,Value 是一个键值对结构。更多详细的介绍可以参见下面这些文章:
- Concurrency Patterns in Go
- How to correctly use context.Context in Go 1.7
- Using context cancellation in Go
- Go Context
Knative Serving client 源码浅析
在 Context 的这些特性中,Knative Serving 中重度依赖的是 Value 功能。以 Service 的 Informer 初始化为例进行说明,这里可以看到源码。
Informer “构造函数”是在 init 函数中自动注册到 injection.Default 中的。当 Informer “构造函数”被调用之后会自动把生成的 Informer 注入到 Context 中 context.WithValue(ctx, Key{}, inf), inf.Informer()
。
从上图中可以看到:Informer 初始化的时候需要调用 factory,而 factory 本身是从 Context 中获取的。下面我们再看看 factory 是怎么初始化的。factory 的初始化。
上图可以发现,factory 也是把“构造函数”注册到 injection.Default 中,并会将生成的 SharedInformerFactory 注入到 Context 中。而且 factory 中使用的 client (链接 kube-apiserver 使用的对象)也是从 Context 获取到的。
可以说 Knative Serving SDK 初始化的过程是面向 Context 编程的。关键对象是自动注入到 Context,在使用的时候从 Context 中取出。
顺带提一点,Knative Serving 的日志对象也是在 Context 保存的,当需要打印日志的时候先通过 logger := logging.FromContext(ctx)
从 Context 中拿到 logger,然后就可以使用了。这样做的好处是可以通过管理 logger 对象,比如做 trace 功能。
如下所示是基于 logger 打印出来的日志,可以看到对于同一个请求的处理是可以通过 traceID 进行追踪的。下面这段日志都是对 577f8de5-cec9-4c17-84f7-f08d39f40127
这个 trace 的处理。
{"level":"info","ts":"2019-08-28T20:24:39.871+0800","caller":"controller/service.go:67","msg":"Reconcile: default/helloworld-go","knative.dev/traceid":"be5ec711-6ca3-493c-80ed-dddfa21fd576","knative.dev/key":"default/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.871+0800","caller":"controller/controller.go:339","msg":"Reconcile succeeded. Time taken: 487.347µs.","knative.dev/traceid":"90653eda-644b-4b1e-8bdb-4a1a7a7ff0d8","knative.dev/key":"eci-test/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.871+0800","caller":"controller/service.go:106","msg":"service: default/helloworld-go route: default/helloworld-go ","knative.dev/traceid":"be5ec711-6ca3-493c-80ed-dddfa21fd576","knative.dev/key":"default/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.872+0800","caller":"controller/service.go:67","msg":"Reconcile: eci-test/helloworld-go","knative.dev/traceid":"22f6c77d-8365-4773-bd78-e011ccb2fa3d","knative.dev/key":"eci-test/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.872+0800","caller":"controller/service.go:116","msg":"service: default/helloworld-go revisions: 1 ","knative.dev/traceid":"be5ec711-6ca3-493c-80ed-dddfa21fd576","knative.dev/key":"default/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.872+0800","caller":"controller/service.go:118","msg":"service: default/helloworld-go revision: default/helloworld-go-cgt65 ","knative.dev/traceid":"be5ec711-6ca3-493c-80ed-dddfa21fd576","knative.dev/key":"default/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.872+0800","caller":"controller/controller.go:339","msg":"Reconcile succeeded. Time taken: 416.527µs.","knative.dev/traceid":"be5ec711-6ca3-493c-80ed-dddfa21fd576","knative.dev/key":"default/helloworld-go"}
{"level":"info","ts":"2019-08-28T20:24:39.872+0800","caller":"controller/service.go:106","msg
使用 Knative Serving SDK
介绍完 Knative Serving client 的初始化过程,下面我们看一下应该如何在代码中用 Knative Serving SDK 进行编码。
示例参见:https://github.com/knative-sample/serving-controller/blob/v0.1/cmd/app/app.go
这个示例中首先使用配置初始化 *zap.SugaredLogger
对象,然后基于 ctx := signals.NewContext()
生成一个 Context。signals.NewContext()
作用是监听 SIGINT 信号,也就是处理 CTRL+c 指令。这里用到了 Context 接口的 Done 函数机制。
构造 Informer
接着使用 ctx, informers := injection.Default.SetupInformers(ctx, cfg)
构造出所有的 informer,然后调用下面这段代码执行注入,把 informer 注入到 Context 中。
// Start all of the informers and wait for them to sync.
logger.Info("Starting informers.")
if err := controller.StartInformers(ctx.Done(), informers...); err != nil {
logger.Fatalw("Failed to start informers", err)
}
从 Context 中获取 Informer
实例代码: https://github.com/knative-sample/serving-controller/blob/v0.1/pkg/controller/controller.go
如上所示,所有的 informer 都是从 Context 中获取的。
最后 Controller 初始化一个 Reconciler 接口,接口的定义如下, 里面只有一个 Reconcile 函数。这个使用方式和 sigs.k8s.io/controller-runtime
使用的逻辑是一样的。如果你之前写过 Operator 之类的功能,对这个操作应该不会陌生。
// Reconciler is the interface that controller implementations are expected
// to implement, so that the shared controller.Impl can drive work through it.
type Reconciler interface {
Reconcile(ctx context.Context, key string) error
}
在 Reconcile 中调用 Knative API
代码示例: https://github.com/knative-sample/serving-controller/blob/v0.1/pkg/controller/service.go
现在就可以在 Reconcile 中通过 c.serviceLister.Services(namespace).Get(name)
这种方式直接操作 Seving 资源了。
至此,我们已经把基于 Knative Seving 开发 Serverless 应用的关键脉梳理了一遍。更详细的代码示例请参见:https://github.com/knative-sample/serving-controller ,这里面有完整可以运行的代码。
小结
本文从 Knative Serving client 的初始化过程开始展开,介绍了 Knative informer 的设计以及使用方法。通过本文你可以了解到:
- Knative Serving client 的设计思路
- 如何基于 Knative Serving SDK 进行二次开发
- 通过 Knative Serving 学习到如何面向 Context 编程
- Knative Serving 集成开发示例: https://github.com/knative-sample/serving-controller
欢迎加入 Knative 交流群
扫描下方二维码添加小助手,拉你进群!
Knative Serving 进阶: Knative Serving SDK 开发实践的更多相关文章
- Kinect for Windows SDK开发入门(15):进阶指引 下
Kinect for Windows SDK开发入门(十五):进阶指引 下 上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun K ...
- 《JavaScript设计模式与开发实践》整理
最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...
- Kinect for Windows SDK开发学习相关资源
Kinect for Windows SDK(K4W)将Kinect的体感操作带到了平常的应用学习中,提供了一种不同于传统的鼠标,键盘及触摸的无接触的交互方式,在某种程度上实现了自然交互界面的理想,即 ...
- Android软件安全开发实践(下)
Android开发是当前最火的话题之一,但很少有人讨论这个领域的安全问题.本系列将分两期,探讨Android开发中常见的安全隐患和解决方案.第一期将从数据存储.网络通信.密码和认证策略这三个角度,带你 ...
- Android开发:最详细的 Toolbar 开发实践总结
最详细的 Toolbar 开发实践总结 过年前发了一篇介绍 Translucent System Bar 特性的文章 Translucent System Bar 的最佳实践,收到很多开发者的关注和反 ...
- 基于React Native的58 APP开发实践
React Native在iOS界早就炒的火热了,随着2015年底Android端推出后,一套代码能运行于双平台上,真正拥有了Hybrid框架的所有优势.再加上Native的优秀性能,让越来越多的公司 ...
- Android进阶(十八)AndroidAPP开发问题汇总(二)
Android进阶(十八)AndroidAPP开发问题汇总(二) 端口被占用解决措施: Android使用SimpleAdapter更新ListView里面的Drawable元素: http://ww ...
- 升讯威微信营销系统开发实践:(4)源代码结构说明 与 安装部署说明( 完整开源于 Github)
GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...
- 升讯威微信营销系统开发实践:(1)功能概要与架构设计( 完整开源于 Github)
GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...
随机推荐
- Spring Boot自定义配置实现IDE自动提示
一.背景 官方提供的spring boot starter的配置项,我们用IDE配置的时候一般都有自动提示的,如下图所示 而我们自己自定义的配置却没有,对开发非常不友好容易打错配置,那这个是怎样实现的 ...
- dubbo(提供者、消费者)基于java的实现
1.安装好jdk.zookeeper以后可以尝试开发代码进行dubbo的学习和练习. 首先创建Dubbo的Provider配置.创建一个maven project工程. RPC框架,不希望Consum ...
- 解决 Windows Server 2008 R2 上 Windows Update 无法失败,提示 8024402F
1.同步服务器时间 2.打开 services.msc,停止 Windows Update Service 3.手动下载 KB3138615 补丁:https://support.microsoft. ...
- 基于OpenCV.Net投影法进行文本分块切割
假设有如下一张图,如何把其中的文本分块切割出来,比如“华普超市朝阳门店”.“2015-07-26”就是两个文本块. 做图像切割有很多种方法,本文描述一种最直观的投影检测法.先来看看什么是投影,简单来说 ...
- runtime template in vuejs
在使用vuejs开发的过程中,有时候我们需要动态模板的场景,也就是说模板并不是静态定义好的,而是动态变化的. 比如在做一个所见所得编辑器时,编辑人员可能时刻需要调整他设计的页面内容,而如果页面内容包含 ...
- Linux目录和文件——查询目录和文件的命令
Linux目录和文件——查询目录和文件的命令 摘要:本文主要学习了在Linux系统中是如何查询目录和文件的. which命令 which命令是根据PATH环境变量设置的路径,去搜索执行文件. 基本语法 ...
- 深入理解Java对象
深入理解Java对象(理清关系) 1.对象的创建过程: 所有创建过程如下所示: new 类名 根据new的参数在常量池中定位一个类的符号引用. 如果没有找到这个符号引用,说明类还没有被加载,则进行类的 ...
- 消息服务dubbo接口性能压测性能优化案例
最近项目中的消息服务做了运营商的改动,导致这个服务做了重新开发 压测脚本如下: 开启200线程压测: tps只有200-300之间,平均耗时在700ms左右 开启500线程压测 500并发压测,发现平 ...
- Linux命令: ps
STAT 进程状态 S-睡眠 s-进程是会话向导进程 N拥有比普通优先级更低的 R-正在运行 D-短期等待 Z-僵尸进程 T被跟踪或者被停止 STATED 进程启动时间 TIME 进程使用CPU时间 ...
- git仓库的安装和基本使用
一.安装git软件 # yum install git -y 二.初始化git仓库 2.1 在git仓库的机器进行配置 # ifconfig eth0 | awk -F '[ :]+' 'NR==2 ...