Higress实战: 30行代码写一个Wasm Go插件

前言

在11月15号的直播 《Higress 开源背后的发展历程和上手 Demo 演示》中,为大家演示了 Higress 的 Wasm 插件如何面向 Ingress 资源进行配置生效,本文对当天的 Demo 进行一个回顾,并说明背后的原理机制。

本文中 Demo 运行的前提,需要在 K8s 集群中安装了 Higress,并生效了下面这份 quickstart 配置:

https://github.com/alibaba/higress/releases/download/v0.5.2/quickstart.yaml

这个 Demo 要实现的功能是一个 Mock 应答的功能,需要实现根据配置的内容,返回 HTTP 应答。

本文会按以下方式进行介绍:

  • 编写代码:代码逻辑解析
  • 生效插件:说明代码如何进行编译打包并部署生效
  • 测试插件功能:说明全局粒度,路由/域名级粒度如何生效
  • 插件生效原理:对整体流程进行回顾,说明插件生效的原理
  • 三个革命性的特性:介绍 Wasm 插件机制为网关插件开发带来的变革

编写代码

package mainimport (. "github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper""github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm""github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types""github.com/tidwall/gjson"
)func main() {SetCtx("my-plugin",ParseConfigBy(parseConfig),ProcessRequestHeadersBy(onHttpRequestHeaders),)
}type MyConfig struct {content string
}func parseConfig(json gjson.Result, config *MyConfig, log Log) error {config.content = json.Get("content").String()return nil
}func onHttpRequestHeaders(ctx HttpContext, config MyConfig, log Log) types.Action {proxywasm.SendHttpResponse(200, nil, []byte(config.content), -1)return types.ActionContinue
}

上面代码中可以看到三个函数:

  • main:插件通过 main 函数定义插件上下文,包括插件名称,用于解析配置的函数,以及用于处理请求/应答的函数
  • parseConfig:这个函数通过在 SetCtx 中指定的 ParseConfigBy 被挂载到插件配置解析阶段,传入的三个参数分别是:
    • json:传入插件的配置,将统一序列化为一个 json 字典对象,提供 parseConfig 进行解析
    • config:parseConfig 将解析后的插件配置输出到这个 MyConfig 对象
    • log:提供日志输出接口
  • onHttpRequestHeaders:函数中调用的 proxywasm.SendHttpResponse,用于实现直接返回 HTTP 应答,这个函数通过在 SetCtx 中指定的 ProcessRequestHeadersBy 被挂载到解析请求 Header 的执行阶段,其他的挂载方式还有:
    • ProcessRequestBodyBy:挂载到解析请求 Body 的执行阶段
    • ProcessResponseHeadersBy:挂载到构造应答 Header 的执行阶段
    • ProcessResponseBodyBy:挂载到构造应答 Body 的执行阶段

传入的三个参数分别是:

    • ctx:用于获取请求上下文,如 scheme/method/path 等,通过 ctx 可以设置自定义上下文,能跨执行阶段访问
    • config:提供 parseConfig 解析好的自定义配置
    • log:提供日志输出接口

这个 30 行代码实现的插件功能比较简单,这里有一些功能相对复杂的例子:https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions

这里有插件 sdk 的详细使用文档:

https://higress.io/zh-cn/docs/user/wasm-go.html

这个插件 sdk 是基于 Tetrate 社区的 proxy-wasm-go-sdk 实现的,如果关注更底层的细节,可以查看:

https://github.com/tetratelabs/proxy-wasm-go-sdk

https://github.com/alibaba/higress/blob/main/plugins/wasm-go/pkg/wrapper

可以看到,Higress 的 wasm-go sdk 是通过 Go 1.18 引入的泛型特性封装了插件上下文处理细节,从而降低插件开发所需代码量,开发者只用关心配置解析和请求应答处理的逻辑。

生效插件

编写完成代码后,一共有三个步骤,实现插件逻辑的生效:

  1. 编译:将 go 代码编译成 Wasm 格式文件
  2. 镜像推送:将 Wasm 文件打包成 docker 镜像,并推送至镜像仓库
  3. 下发配置:在 K8s 上创建 WasmPlugin 资源

编译

将上面的 Go 文件 main.go 编译成 plugin.wasm

tinygo build -o plugin.wasm -scheduler=none -target=wasi main.go

镜像推送

编写 Dockerfile

FROM scratch
COPY plugin.wasm ./

构建并推送 Docker 镜像 (这里示例用的是 Higress 的官方镜像仓库)

docker build -t higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/demo:1.0.0 .
docker push higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/demo:1.0.0

下发配置

编写 wasmplugin.yaml,配置说明:

  • selector: 选中了默认安装在 higress-system 命名空间下的 higress-gateway 生效这份插件
  • pluginConfig:插件配置,最终会被转换成上面代码中的 MyConfig 对象
  • url:填写镜像地址,需要以"oci://"开头

除了这些配置外,还可以定义插件的执行阶段和优先级等进阶配置,可以参考 Istio API 官方文档:https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/

# wasmplugin.yaml
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:name: mock-responsenamespace: higress-system
spec:selector:matchLabels:higress: higress-system-higress-gatewaypluginConfig:content: "hello higress"url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/demo:1.0.0

通过 kubectl 创建这个资源

kubectl apply -f wasmplugin.yaml

测试插件功能

基于之前生效的 quickstart.yaml,目前集群中的 Ingress 访问拓扑如下所示:

未生效插件的情况下:

  • 请求/foo 将返回 HTTP 应答 "foo"
  • 请求/bar 将返回 HTTP 应答 "bar"

全局生效

基于上文生效插件阶段,下发的 wasmplugin.yaml,生效插件后效果如下:

  • 请求/foo 将返回 HTTP 应答 "hello higress"
  • 请求/bar 将返回 HTTP 应答 "hello higress"

域名&路由级生效

将 wasmplugin.yaml 配置修改如下

# wasmplugin.yaml
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:name: mock-responsenamespace: higress-system
spec:selector:matchLabels:higress: higress-system-higress-gatewaypluginConfig:content: "hello higress"_rules_:- content: "hello foo"_match_route_:- "default/foo"- content: "hello bar"_match_route_:- "default/bar"- content: "hello world"_match_domain_:- "*.example.com"- "www.test.com"url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/demo:1.0.0

在 pluginConfig 中增加了 _rules_ 规则列表,规则中可以指定匹配方式,并填写对应生效的配置:

  • _match_route_:匹配 Ingress 生效,匹配格式为:Ingress 所在命名空间 + "/" + Ingress 名称
  • _match_domain_:匹配域名生效,填写域名即可,支持通配符

生效这份修改后的配置:

kubectl apply -f wasmplugin.yaml

可以看到效果如下:

  • 请求/foo 将返回 HTTP 应答 "hello foo" (匹配到第一条 rule)
  • 请求/bar 将返回 HTTP 应答 "hello bar" (匹配到第二条 rule)
  • 请求www.example.com 将返回 HTTP 应答 "hello world" (匹配到第三条 rule)
  • 请求www.abc.com 将返回 HTTP 应答 "hello higress" (没有匹配的 rule,使用全局配置)

插件生效原理

这里对插件的生效机制简单做个说明:

  1. 用户将代码编译成 wasm 文件
  2. 用户将 wasm 文件构建成 docker 镜像
  3. 用户将 docker 镜像推送至镜像仓库
  4. 用户创建 WasmPlugin 资源
  5. Istio watch 到 WasmPlugin 资源的变化
  6. Higress Gateway 中的 xDS proxy 进程从 Istio 获取到配置,发现插件的镜像地址
  7. xDS proxy 从镜像仓库拉取镜像
  8. xDS proxy 从镜像中提取出 wasm 文件
  9. Higress Gateway 中的 envoy 进程从 xDS proxy 获取到配置,发现 wasm 文件的本地路径
  10. envoy 从本地文件中加载 wasm 文件

这里 envoy 获取配置并加载 wasm 文件使用到了 ECDS (Extension Config Discovery Service)的机制,实现了 wasm 文件更新,直接热加载,不会导致任何连接中断,业务流量完全无损。

三个革命性的特性

上面的 Wasm 插件机制为网关自定义插件开发带来了三个革命性的特性。

特性一:插件生命周期和网关解耦

这个特性主要得益于 Istio 的 WasmPlugin 机制设计。可以和 K8s Nginx Ingress 的插件机制做个对比:

reference: https://github.com/kubernetes/ingress-nginx/blob/main/rootfs/etc/nginx/lua/plugins/README.md
Installing a plugin

There are two options:
mount your plugin into /etc/nginx/lua/plugins/<your plugin name> in the ingress-nginx pod
build your own ingress-nginx image like it is done in the example and install your plugin during image build

可以看到 Nginx Ingress 加载自定义插件,需要将 lua 文件挂载进 pod,或者在构建镜像时装入。这样就将插件的生命周期跟网关绑定在一起,插件逻辑更新,需要发布新版本,网关也需要发布新版本或者重新部署。

使用 WasmPlugin 的机制,插件需要发布新版本,只需构建插件自身的镜像并进行下发生效,而且可以基于镜像的 tag 进行插件的版本管理。这样插件变更,不仅无需重新部署网关,结合 Envoy 的 ECDS 机制对流量也是完全无损。

特性二:高性能的多语言支持

基于 Wasm 的能力,可以用多种语言编写插件,对开发人员更加友好。实现多语言开发插件的另一种方式是基于 RPC 和网关进程通信的外置进程/服务插件,这种模式会有额外的 IO 开销,并且附加的进程/服务也带来额外的运维复杂度。目前大家对 Wasm 插件的性能比较关心,从我们的测试数据来看,指令执行性能相比原生的 C++ 语言确实有差距,但性能和 Lua 持平,且远好于外置插件。

对于一段逻辑:循环执行20次请求头设置,循环执行20次请求头获取,循环执行20次请求头移除。我们对比了分别用 Lua 和不同语言实现的 Wasm 的处理性能,下面是对单个请求延时的影响对比:

特性三:安全沙箱

Envoy 目前支持多种 Wasm 的运行时,例如 V8,WAMR,wasmtime 等等,这些运行时均提供了安全沙箱能力,即 Wasm 插件中出现了访问空指针、异常未捕获等逻辑,也不会令 Envoy 宿主进程 Crash。并且可以通过配置,在插件逻辑出现异常后进行 Fail Open 处理,跳过插件的执行逻辑,将对业务的影响降至最低。

原文链接

本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/510358.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Serverless 的前世今生

从云计算到 Serverless 架构 大家好&#xff0c;我是阿里云 Serverless 产品经理刘宇&#xff0c;很高兴可以和大家一起探索 Serverless 架构的前世今生。 从云计算到云原生再到 Serverless 架构&#xff0c;技术飞速发展的轨迹都有一定规律可循&#xff0c;那么 Serverless 架…

eunomia-bpf 项目重磅开源!eBPF 轻量级开发框架来了

近日&#xff0c;在 2022 云栖大会龙蜥峰会 eBPF & Linux 稳定性专场上&#xff0c;来自 eBPF 技术探索 SIG Maintainer 、浙江大学的郑昱笙分享了《eunomia-bpf&#xff1a;eBPF 轻量级开发框架》技术演讲&#xff0c;以下为本次演讲内容&#xff1a; 大家好&#xff01;…

一文看懂分布式链路监控系统

背景 传统的大型单体系统随着业务体量的增大已经很难满足市场对技术的需求&#xff0c;通过对将整块业务系统拆分为多个互联依赖的子系统并针对子系统进行独立优化&#xff0c;能够有效提升整个系统的吞吐量。在进行系统拆分之后&#xff0c;完整的业务事务逻辑所对应的功能会…

深度 | 新兴软件研发范式崛起,云计算全面走向 Serverless 化

11月3日&#xff0c;2022 杭州 云栖大会上&#xff0c;阿里云智能总裁张建锋表示&#xff0c;以云为核心的新型计算体系正在形成&#xff0c;软件研发范式正在发生新的变革&#xff0c;Serverless 是其中最重要的趋势之一&#xff0c;阿里云将坚定推进核心产品全面 Serverless…

适用场景全新升级!扩展 Dragonfly2 作为分布式缓存系统架构

Dragonfly2 简介 Dragonfly 作为龙蜥社区的镜像加速标准解决方案&#xff0c;是一款基于 P2P 的智能镜像和文件分发工具。它旨在提高大规模文件传输的效率和速率&#xff0c;最大限度地利用网络带宽。在应用分发、缓存分发、日志分发和镜像分发等领域被大规模使用。 现阶段 D…

sdut 最长公共子序列问题

Problem Description 从一个给定的串中删去&#xff08;不一定连续地删去&#xff09;0个或0个以上的字符&#xff0c;剩下地字符按原来顺序组成的串。例如&#xff1a;“ ”&#xff0c;“a”&#xff0c;“xb”&#xff0c;“aaa”&#xff0c;“bbb”&#xff0c;“xabb”&a…

hdu1176 免费馅饼 动态规划 二维数组实现

免费馅饼 Time Limit: 1000MS Memory Limit: 32768KBSubmit Statistic DiscussProblem Description 都说天上不会掉馅饼&#xff0c;但有一天gameboy正走在回家的小径上&#xff0c;忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了&#xff0c;这馅饼别处都不掉&am…

如何通过链路追踪进行定时任务诊断

背景简介 什么是定时任务 定时任务是业务应用系统中存在定时周期性运行的业务逻辑。由于其运行于后端进程中往往存在执行状态和执行链路的不可见性《常见定时任务技术方案》。 什么是链路追踪 随着分布式微服务化架构在企业中大规模运用&#xff0c;业务运行的应用平台是一…

关于平台工程的开发者工具链,你还想加点啥?

前言 从 Kubernetes 诞生以来&#xff0c;以 DevOps、容器化、可观测、微服务、Serverless 等技术为代表的云原生&#xff0c;催生了应用架构新一轮的升级。有意思的是&#xff0c;与以往的技术迭代更新不同&#xff0c;原本是一个技术圈常规的一次技术实践&#xff0c;在千行…

阿里云联合“产学研媒”发起 BizDevOps 共促计划,助力企业提升组织效能

2012年全球最具影响力的独立研究咨询机构Forrester曾预言&#xff1a;“In the future, all companies will be software companies”&#xff08;在未来&#xff0c;所有的企业都将成为软件企业&#xff09; 近10年来&#xff0c;DevOps运动在全球和中国风起云涌&#xff0c;…

Kubernetes HPA 的三个误区与避坑指南

前言 云计算带来的优势之一便是弹性能力&#xff0c;云原生场景下Kubernetes提供了水平弹性扩容能力&#xff08;HPA&#xff09;&#xff0c;让应用可以随着实时指标进行扩/缩。然而HPA的实际工作情况可能和我们直观预想的情况是不一样的&#xff0c;这里面存在一些认知误区。…

K8s有损发布问题探究

问题提出 流量有损是在应用发布时的常见问题&#xff0c;其现象通常会反馈到流量监控上&#xff0c;如下图所示&#xff0c;发布过程中服务RT突然升高&#xff0c;造成部分业务响应变慢&#xff0c;给用户的最直观体验就是卡顿&#xff1b;或是请求的500错误数突增&#xff0c…

解读 K8s Pod 的13种典型异常

在K8s中&#xff0c;Pod作为工作负载的运行载体&#xff0c;是最为核心的一个资源对象。Pod具有复杂的生命周期&#xff0c;在其生命周期的每一个阶段&#xff0c;可能发生多种不同的异常情况。K8s作为一个复杂系统&#xff0c;异常诊断往往要求强大的知识和经验储备。结合实战…

实践教程之如何快速使用 PolarDB-X

PolarDB-X 为了方便用户体验&#xff0c;提供了免费的实验环境&#xff0c;您可以在实验环境里体验 PolarDB-X 的安装部署和各种内核特性。除了免费的实验&#xff0c;PolarDB-X 也提供免费的视频课程&#xff0c;手把手教你玩转 PolarDB-X 分布式数据库。 本期实验可以让您快…

实践教程之如何将 PolarDB-X 与大数据等系统互通

本期实验将指导您使用PolarDB-XCanalClickHouse搭建实时分析系统。 本期免费实验地址 本期教学视频地址 前置准备 假设已经根据前一讲内容完成了PolarDB-X的搭建部署&#xff0c;可以成功链接上PolarDB-X数据库。 实践教程之如何快速安装部署PolarDB-X 部署Canal Canal是…

加载速度提升 15%,关于 Python 启动加速探索与实践的解析

编者按&#xff1a;在刚刚结束的 PyCon China 2022 大会上&#xff0c;龙蜥社区开发者严懿宸分享了主题为《Python 启动加速的探索与实践》的技术演讲。本次演讲&#xff0c;作者将从 CPython 社区相关工作、本方案的设计及实现&#xff0c;以及业务层面的集成等方面进行介绍。…

统信软件高级工程师:关于云原生技术在容器方面的应用介绍

编者按&#xff1a;随着近几年来云原生生态的不断壮大&#xff0c;众多企业纷纷开展了用云上云的工作&#xff0c;学习云原生及容器技术对于现代工程师是必不可少的。本文整理自龙蜥大讲堂 54 期&#xff0c;统信高级研发工程师参与技术分享&#xff0c;为大家介绍了云原生的介…

解读最佳实践:倚天710 ARM芯片的 Python+AI 算力优化

编者按&#xff1a;在刚刚结束的 PyCon China 2022 大会上&#xff0c;龙蜥社区开发者朱宏林分享了主题为《ARM 芯片的 PythonAI 算力优化》的技术演讲。本次演讲&#xff0c;作者将向大家介绍他们在倚天 710 ARM 芯片上开展的 PythonAI 优化工作&#xff0c;以及在 ARM 云平台…

从敏捷协作到价值交付

前面我的同事在分享的时候&#xff0c;指出目前软件研发的最大问题不是效率&#xff0c;而是研发资源的浪费。可能产品经理半天写的需求&#xff0c;开发要埋头苦干三个月。如果错误的选择了一个对业务发展无益的需求&#xff0c;会带着大家往错误的方向越跑越远。 那么什么是…

行动策略过于复杂怎么办?试试下面一些解决方法

背景 随着使用SLS告警越来越深入&#xff0c;有些用户的行动策略会配置的特别复杂&#xff0c;有些时候可以让用户通过创建多个行动策略来进行一定的精简&#xff0c;但是在一些场景下&#xff0c;用户是无法创建多个行动策略的。例如用户想要通过SLS来统一管理其各个监控系统…