当前位置:   article > 正文

Istio 1.12 引入 Wasm 插件配置 API 以扩展 Istio 生态

istio 扩展

bf499d35febcc870a6b0d4fd3eea9efc.png

作者:胡渐飞,Tetrate  工程师

Istio 中新的 WebAssembly 基础设施使其能够轻松地将额外的功能注入网格部署中。

经过三年的努力,Istio 现在有了一个强大的扩展机制,可以将自定义和第三方 Wasm 模块添加到网格中的 sidecar。Tetrate 工程师米田武(Takeshi Yoneda)[1] 和 周礼赞(Lizan Zhou)[2] 在实现这一目标方面发挥了重要作用。这篇文章将介绍 Istio 中 Wasm 的基础知识,以及为什么它很重要,然后是关于建立自己的 Wasm 插件并将其部署到网格的简短教程。

为什么 Istio 中的 Wasm 很重要

使用 Wasm,开发人员可以更容易的扩展网格和网关。在 Tetrate,我们相信这项技术正在迅速成熟,因此我们一直在投资上游的 Istio,使配置 API、分发机制和从 Go 开始的可扩展性体验更加容易。我们认为这将使 Istio 有一个全新的方向。

有何期待:新的插件配置 API,可靠的获取和安装机制

有一个新的顶级 API,叫做 WasmPlugin[3],可以让你配置要安装哪些插件,从哪里获取它们(OCI 镜像、容器本地文件或远程 HTTP 资源),在哪里安装它们(通过 Workload 选择器 [4]),以及一个配置结构体来传递给插件实例。

istio-agent 中的镜像提取机制(在 Istio 1.9 中引入),从远程 HTTP 源可靠地检索 Wasm 二进制文件,已被扩展到支持从任何 OCI 注册处检索 Wasm OCI 镜像,包括 Docker Hub、Google Container Registry(GCR)、Amazon Elastic Container Registry(Amazon ECR)和其他地方。

这意味着你可以创建自己的 Wasm 插件,或者从任何注册处选择现成的插件,只需几行配置就可以扩展 Istio 的功能。Istio 会在幕后做所有的工作,为你获取、验证、安装和配置它们。

Istio Wasm 扩展

Istio 的扩展机制使用 Proxy-Wasm 应用二进制接口(ABI)[5] 规范,该规范由周礼赞和米田武带头制定,提供了一套代理无关的流媒体 API 和实用功能,可以用任何有合适 SDK 的语言来实现。截至目前,Proxy-Wasm 的 SDK 有 AssemblyScript(类似 TypeScript)、C++、Rust、Zig 和 Go(使用 TinyGo WebAssembly 系统接口「WASI」,米田武也是其主要贡献者)。

如何获取:Tetrate Istio Distro

获得 Istio 的最简单方法是使用 Tetrate 的开源get-mesh CLI 和 Tetrate Istio Distro[6],这是一个简单、安全的上游 Istio 的企业级发行版。

Wasm 实战:构建你自己的速率限制 WebAssembly 插件

在我们之前关于 Envoy 中的 Wasm 扩展 [7] 的博客中,我们展示了如何开发 WebAssembly 插件来增强服务网格的能力。新的 Wasm 扩展 API 让它变得更加简单。本教程将解释如何使用 Istio Wasm 扩展 API 来实现 Golang 中的速率限制。

先决条件

• 熟悉 Istio 和 Envoy 中的 Wasm[8]。• 安装 TinyGo 0.21.0[9] 并使用 Golang 构建 Wasm 扩展。

说明

在这个例子中,我们将在集群中部署两个应用程序(sleep 和 httpbin)。我们将从一个容器向另一个容器发送几个请求,而不部署任何 Wasm 扩展。

接下来,我们将在 Go 中创建一个 Wasm 模块,为响应添加一个自定义头,并拒绝任何请求率超过每秒两个的请求。

我们将把 Wasm 模块推送到 Docker 镜像仓库,并使用新的 WasmPlugin 资源,告诉 Istio 从哪里下载 Wasm 模块,以及将该模块应用于哪些工作负载。

第 1 步:安装 Istio 并部署应用程序

首先,我们将下载并安装 Istio 1.12,并标记 Kubernetes 的 default 命名空间,以便自动注入 sidecar。

  1. curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.12 sh
  2. cd istio-1.12/
  3. ./bin/istioctl install --set profile=demo -y
  4. kubectl label namespace default istio-injection=enabled --overwrite

接下来,我们将部署 httpbin 和 sleep 应用程序的示例。

  1. kubectl apply -f samples/httpbin/httpbin.yaml
  2. kubectl apply -f samples/sleep/sleep.yaml

应用程序部署并运行后,我们将每秒从 sleep 容器向 httpbin 容器发送 4 个请求。

  1. $ SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
  2. $ kubectl exec ${SLEEP_POD} -c sleep -- sh -c 'for i in $(seq 1 3); do curl --head -s httpbin:8000/headers; sleep 0.25; done'
  3. HTTP/1.1 200 OK
  4. server: envoy
  5. date: Tue, 16 Nov 2021 22:18:32 GMT
  6. content-type: application/json
  7. content-length: 523
  8. access-control-allow-origin: *
  9. access-control-allow-credentials: true
  10. x-envoy-upstream-service-time: 2
  11. HTTP/1.1 200 OK
  12. server: envoy
  13. date: Tue, 16 Nov 2021 22:18:32 GMT
  14. content-type: application/json
  15. content-length: 523
  16. access-control-allow-origin: *
  17. access-control-allow-credentials: true
  18. x-envoy-upstream-service-time: 4
  19. HTTP/1.1 200 OK
  20. server: envoy
  21. date: Tue, 16 Nov 2021 22:18:32 GMT
  22. content-type: application/json
  23. content-length: 523
  24. access-control-allow-origin: *
  25. access-control-allow-credentials: true
  26. x-envoy-upstream-service-time: 1

你会发现所有的请求都成功了,并返回了 HTTP 200。

第 2 步:开发、编译和推送 Wasm 模块

我们将使用 Golang 和 Proxy Wasm Golang SDK 来开发 Wasm 模块。我们将使用 SDK 资源库中的一个现有例子,叫做 istio-rate-limiting。要开始,请先克隆 Github 仓库。

  1. git clone https://github.com/tetratelabs/wasm-rate-limiting
  2. cd wasm-rate-limiting/

我们来看看 main.go 中的代码。这就是我们使用 Proxy Wasm Golang SDK 实现速率限制逻辑的地方。Wasm 模块做了两件事。

• 在响应中添加一个自定义的头。• 执行 2 个请求 / 秒的速率限制,拒绝超额的请求。

下面是 main.go 的片段,显示了功能是如何实现的。

  1. // Modify the header
  2. func (ctx *httpHeaders) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action {
  3. for key, value := range additionalHeaders {
  4. proxywasm.AddHttpResponseHeader(key, value)
  5. }
  6. return types.ActionContinue
  7. }
  8. // Perform rate limiting
  9. func (ctx *httpHeaders) OnHttpRequestHeaders(int, bool) types.Action {
  10. current := time.Now().UnixNano()
  11. // We use nanoseconds() rather than time.Second() because the proxy-wasm has the known limitation.
  12. // TODO(incfly): change to time.Second() once https://github.com/proxy-wasm/proxy-wasm-cpp-host/issues/199
  13. // is resolved and released.
  14. if current > ctx.pluginContext.lastRefillNanoSec+1e9 {
  15. ctx.pluginContext.remainToken = 2
  16. ctx.pluginContext.lastRefillNanoSec = current
  17. }
  18. proxywasm.LogCriticalf("Current time %v, last refill time %v, the remain token %v",
  19. current, ctx.pluginContext.lastRefillNanoSec, ctx.pluginContext.remainToken)
  20. if ctx.pluginContext.remainToken == 0 {
  21. if err := proxywasm.SendHttpResponse(403, [][2]string{
  22. {"powered-by", "proxy-wasm-go-sdk!!"},
  23. }, []byte("rate limited, wait and retry."), -1); err != nil {
  24. proxywasm.LogErrorf("failed to send local response: %v", err)
  25. proxywasm.ResumeHttpRequest()
  26. }
  27. return types.ActionPause
  28. }
  29. ctx.pluginContext.remainToken -= 1
  30. return types.ActionContinue
  31. }

在 OnHttpResponseHeaders 函数中,我们正在迭代 extraHeaders 变量,并将头文件添加到响应中。

在 OnHttpRequestHeaders 函数中,我们得到当前的时间戳,将其与最后一次补给时间的时间戳进行比较(对于速率限制器),如果需要的话,就补给令牌。

如果没有剩余的令牌,我们就发送一个带有额外头的 403 响应(由:proxy-wasm-go-sdk!!)。

让我们用 tinygo 将 Golang 程序编译成 Wasm 模块,并将其打包成一个 Docker 镜像。

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

我们构建一个 Docker 镜像,并将其推送到镜像仓库(用你自己的 Docker 镜像仓库和镜像名称替换 ${YOUR_DOCKER_REGISTRY_IMAGE})。在这之后,你的 Wasm 插件就可以在你的服务网格中使用了。

  1. docker build -t ${YOUR_DOCKER_REGISTRY_IMAGE}:v1 .
  2. docker push -t ${YOUR_DOCKER_REGISTRY_IMAGE}:v1

另外,你也可以使用一个预构建的 Docker 镜像,它有相同的代码,位于 ghcr.io/tetratelabs/wasm-rate-limiting:v1[10]

第 3 步:配置 Istio Wasm 扩展 API

Istio Wasm Extension API 和新的 WasmPlugin 资源允许我们将我们推送到 Docker 镜像仓库的速率限制 Wasm 模块添加到 httpbin 工作负载中。下面是 WasmPlugin 资源的 YAML 配置。

  1. apiVersion: extensions.istio.io/v1alpha1
  2. kind: WasmPlugin
  3. metadata:
  4. name: httpbin-rate-limiting
  5. namespace: default
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: httpbin
  10. url: oci://ghcr.io/tetratelabs/wasm-rate-limiting:v1

这个配置部署后,Istiod 就会把相应的配置推送到 Envoy sidecar(与我们在 matchLabels 字段中指定的标签相匹配的那些)。Sidecar 中的 Istio 代理将执行远程获取,下载我们刚刚推送的 Wasm 模块,然后将其加载到 Envoy 运行时的 Wasm 引擎中执行。

让我们把上述 YAML 保存为 wasm.yaml,并将其部署到集群中。

  1. $ kubectl apply -f ./wasm.yaml
  2. wasmplugin.extensions.istio.io/httpbin-rate-limiting created

第 4 步:验证速率限制的效果

在我们部署了 WasmPlugin 资源和 Istio 从注册表中获取了 Wasm 模块后,我们现在可以验证 Wasm 插件中实现的速率限制是如何工作的。

  1. $ SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
  2. $ kubectl exec ${SLEEP_POD} -c sleep -- sh -c 'for i in $(seq 1 3); do curl --head -s httpbin:8000/headers; sleep 0.25; done'
  3. HTTP/1.1 200 OK
  4. server: envoy
  5. date: Tue, 16 Nov 2021 22:16:34 GMT
  6. content-type: application/json
  7. content-length: 523
  8. access-control-allow-origin: *
  9. access-control-allow-credentials: true
  10. x-envoy-upstream-service-time: 2
  11. who-am-i: wasm-extension
  12. injected-by: istio-api!
  13. HTTP/1.1 200 OK
  14. server: envoy
  15. date: Tue, 16 Nov 2021 22:16:35 GMT
  16. content-type: application/json
  17. content-length: 523
  18. access-control-allow-origin: *
  19. access-control-allow-credentials: true
  20. x-envoy-upstream-service-time: 2
  21. who-am-i: wasm-extension
  22. injected-by: istio-api!
  23. HTTP/1.1 403 Forbidden
  24. powered-by: proxy-wasm-go-sdk!!
  25. content-length: 29
  26. content-type: text/plain
  27. who-am-i: wasm-extension
  28. injected-by: istio-api!
  29. date: Tue, 16 Nov 2021 22:16:35 GMT
  30. server: envoy
  31. x-envoy-upstream-service-time: 0

就像以前一样,我们从 sleep 容器向 httpbin 容器发送 3 个请求。这一次,Wasm 插件代码被执行,我们可以注意到输出中的一些差异。首先,who-am-i 头被 Wasm 插件注入了。前两个请求以 HTTP 200 的响应代码成功,剩下的请求则以 HTTP 429 失败。此外,我们可以注意到一个名为 powered-by 的额外头,它也被 Wasm 插件注入了。

教程摘要

总而言之,本教程演示了如何轻松实现插件功能,以扩展 Istio 的功能,满足你的特定需求。这需要三个步骤:

1. 在 Golang 中实现你的插件功能。2. 编译、构建,并将 Wasm 模块推送到符合 OCI 标准的 Docker 镜像仓库。3. 使用 WasmPlugin 资源配置服务网格工作负载,以便从远程镜像仓库中拉取 Wasm 模块。

该教程实现了一个单一的 Wasm 插件来处理 HTTP 请求。除此之外,你可以有多个 Wasm 插件,每个单独的插件负责某一部分的功能。

例如,AUTHN[11] 阶段的一个插件获取或验证认证凭证;AUTHZ[12] 阶段的另一个插件实现你自己定制的授权逻辑,等等。

Istio Wasm 扩展还允许我们生成插件指标,或在多个 Wasm 插件中汇总。该插件提供了一个日志功能,允许我们将日志信息写到 Envoy sidecar。这对 Wasm 插件的调试和开发特别有帮助。

目前的 Istio Wasm API 处于 alpha 阶段,将在未来的 Istio 版本中得到增强和稳定。这包括通过验证签名来安全地验证 Wasm 插件本身,支持用存储为 Kubernetes Secret 的秘密来拉取 Wasm 插件等。

进一步阅读和补充资源

在 Tetrate,我们正在努力改善开发者的体验,tetratelabs/proxy-wasm-golang-sdk[13] 包含本教程使用的 Golang SDK 库。你可以找到更多的例子,如 http 头的操作 [14]、样例 授权 [15]、 改变路由 [16] 行为等。

Tetrate Istio Distro[17] 是安装、操作和升级 Istio 的最简单方法。

报名参加 Tetrate 的 Istio Wasm 插件研讨会,向 Istio 中的 Wasm 插件的创造者学习 [18]

引用链接

[1] 米田武(Takeshi Yoneda): https://github.com/mathetake
[2] 周礼赞(Lizan Zhou): https://github.com/lizan
[3] WasmPlugin: https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/
[4] Workload 选择器: https://istio.io/latest/docs/reference/config/type/workload-selector/#WorkloadSelector
[5] Proxy-Wasm 应用二进制接口(ABI): https://github.com/proxy-wasm/spec
[6] get-mesh CLI 和 Tetrate Istio Distro: https://istio.tetratelabs.io/
[7] Envoy 中的 Wasm 扩展: https://www.tetrate.io/blog/wasm-modules-and-envoy-extensibility-explained-part-1/
[8] Istio 和 Envoy 中的 Wasm: https://www.tetrate.io/blog/wasm-modules-and-envoy-extensibility-explained-part-1/
[9] TinyGo 0.21.0: https://tinygo.org/getting-started/install/
[10] ghcr.io/tetratelabs/wasm-rate-limiting:v1: http://ghcr.io/tetratelabs/wasm-rate-limiting:v1
[11] AUTHN: https://github.com/istio/api/blob/master/extensions/v1alpha1/wasm.proto#L254
[12] AUTHZ: https://github.com/istio/api/blob/master/extensions/v1alpha1/wasm.proto#L257
[13] tetratelabs/proxy-wasm-golang-sdk: https://github.com/tetratelabs/proxy-wasm-go-sdk/tree/main/examples
[14] 头的操作: https://github.com/tetratelabs/proxy-wasm-go-sdk/blob/main/examples/http_routing/main.go#L70-L80
[15] 授权: https://github.com/tetratelabs/proxy-wasm-go-sdk/tree/main/examples/http_auth_random
[16] 改变路由: https://github.com/tetratelabs/proxy-wasm-go-sdk/tree/main/examples/http_routing
[17] Tetrate Istio Distro: https://istio.tetratelabs.io/
[18] 报名参加 Tetrate 的 Istio Wasm 插件研讨会,向 Istio 中的 Wasm 插件的创造者学习: https://www.tetrate.io/istio-wasm-workshop/

关于云原生社区

云原生社区是国内最大的独立第三方云原生终端用户和泛开发者社区,由 CNCF 大使、开源意见领袖共同发起成立于 2020 年 5 月 12 日,提供云原生专业资讯,促进云原生产业发展。云原生社区基于成员兴趣创建了多个 SIG(特别兴趣小组),如 KubernetesIstioEnvoyDaprOAM边缘计算机器学习可观察性稳定性安全等。点击了解我们

点击下方“阅读原文”查看更多

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/784687
推荐阅读
相关标签
  

闽ICP备14008679号