1.19. 扩展

您可以使用 WebAsembly 扩展直接将新功能添加到 Red Hat OpenShift Service Mesh 代理中。这可让您从应用程序中移出更多常见的功能,并使用编译到 WebAssembly 字节代码的单一语言实现它们。

注意

IBM Z 和 IBM Power Systems 不支持 WebAsembly 扩展。

1.19.1. WebAssembly 模块概述

WebAsembly 模块可以在很多平台上运行,包括代理,并有广泛语言支持、快速执行以及沙盒安全模型。

Red Hat OpenShift Service Mesh 扩展是 Envoy HTTP Filters,为它们提供广泛的功能:

  • 控制请求和响应的正文和标头。
  • 对不在请求路径中的服务(如认证或策略检查)的带外 HTTP 请求。
  • 用来相互通信的 sidechannel 数据存储和过滤器队列。
注意

在创建新的 WebAsembly 扩展时,请使用 WasmPlugin API。ServiceMeshExtension API 从 Red Hat OpenShift Service Mesh 版本 2.2 开始已弃用,并将在以后的版本中删除。

编写 Red Hat OpenShift Service Mesh 扩展有两个部分:

  1. 您必须使用提供 proxy-wasm API 的 SDK 编写扩展,并将其编译到 WebAssembly 模块。
  2. 然后,您必须将模块打包到容器中。

支持的语言

您可以使用任何编译到 WebAssembly 字节码的语言来编写 Red Hat OpenShift Service Mesh 扩展,但以下语言具有公开 proxy-wasm API 的现有 SDK,以便直接使用它。

表 1.14. 支持的语言

语言Maintainer软件仓库

AssemblyScript

solo.io

solo-io/proxy-runtime

C++

proxy-wasm 团队(Istio 社区)

proxy-wasm/proxy-wasm-cpp-sdk

Go

tetrate.io

tetratelabs/proxy-wasm-go-sdk

Rust

proxy-wasm 团队(Istio 社区)

proxy-wasm/proxy-wasm-rust-sdk

1.19.2. WasmPlugin 容器格式

Istio 在其 Wasm Plugin 机制中支持 OCI(Open Container Initiative) 镜像。您可以将 Wasm 插件分发为容器镜像,您可以使用 spec.url 字段来引用容器 registry 位置。例如: quay.io/my-username/my-plugin:latest

因为 WASM 模块的每个执行环境(runtime)都可以有特定于运行时的配置参数,因此 WASM 镜像由两个层组成:

  • plugin.wasm (必需)- 内容层。这个层包含一个包含 WebAssembly 模块字节码的 .wasm 二进制文件,它由运行时加载。您必须将此文件命名为 plugin.wasm
  • runtime-config.json (可选)- 配置层。这个层包含一个 JSON 格式的字符串,用于描述目标运行时模块的元数据。根据目标运行时,配置层也可以包含其他数据。例如,WASM Envoy Filter 的配置包含过滤器上的 root_ids。

1.19.3. WasmPlugin API 参考

WasmPlugins API 提供了通过 WebAssembly 过滤器扩展 Istio 代理提供的功能的机制。

您可以部署多个 WasmPlugins。phasepriority 设置决定了执行顺序(作为 Envoy 的过滤器链的一部分),允许对用户提供的 WasmPlugin 和 Istio 的内部过滤器配置复杂交互。

在以下示例中,身份验证过滤器实施 OpenID 流,并使用 JSON Web Token(JWT)填充 Authorization 标头。Istio 身份验证会消耗这个令牌,并将其部署到 ingress 网关。WasmPlugin 文件在代理 sidecar 文件系统中存在。请注意字段 url

apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: openid-connect
  namespace: istio-ingress
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  url: file:///opt/filters/openid.wasm
  sha256: 1ef0c9a92b0420cf25f7fe5d481b231464bc88f486ca3b9c83ed5cc21d2f6210
  phase: AUTHN
  pluginConfig:
    openid_server: authn
    openid_realm: ingress

以下是相同的示例,但这一次使用 OCI 镜像而不是文件系统中的文件。记录 urlimagePullPolicyimagePullSecret 和 imagePullSecret 字段。

apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: openid-connect
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  url: oci://private-registry:5000/openid-connect/openid:latest
  imagePullPolicy: IfNotPresent
  imagePullSecret: private-registry-pull-secret
  phase: AUTHN
  pluginConfig:
    openid_server: authn
    openid_realm: ingress

表 1.15. WasmPlugin 字段参考

字段类型描述必需

spec.selector

WorkloadSelector

用于选择应该应用此插件配置的特定 pod/VM 集合的条件。如果省略,此配置将应用于同一命名空间中的所有工作负载实例。如果 config root 命名空间中存在 WasmPlugin 字段,它将应用于任何命名空间中的所有适用工作负载。

spec.url

字符串

Wasm 模块或 OCI 容器的 URL。如果没有方案,则默认为 oci://,代表 OCI 镜像。其他有效的方案是 file://(用于引用代理容器内的本地 .wasm 模块文件);http[s]:// 用于远程托管的 .wasm 模块文件 。

spec.sha256

字符串

用于验证 Wasm 模块或 OCI 容器的 SHA256 checksum。如果 url 字段已引用 SHA256(使用 @sha256: 表示法),它必须与此字段的值匹配。如果 tag 引用了 OCI 镜像,并且设置了此字段,则在拉取后将根据此字段的内容验证其校验和。

spec.imagePullPolicy

pullPolicy

获取 OCI 镜像时要应用的拉取行为。只有在通过标签而不是 SHA 引用镜像时才相关。默认为 IfNotPresent 值,除非在 url 字段中引用了 OCI 镜像并且使用了 latest 标签时,这种情况下默认值为 Always,镜像 K8s 的行为。如果 url 字段直接使用 file://http[s]:// 直接引用 Wasm 模块,则忽略设置。

spec.imagePullSecret

字符串

用于 OCI 镜像拉取的凭证。与 WasmPlugin 对象相同的命名空间中的 secret 名称,其中包含用于在拉取镜像时对 registry 进行身份验证的 pull secret。

spec.phase

PluginPhase

决定过滤器链中注入这个 WasmPlugin 对象的位置。

spec.priority

int64

决定有同一 phase 值的 WasmPlugins 对象的顺序。当多个 WasmPlugins 对象应用于同一阶段的同一工作负载时,它们将按优先级和降序应用。如果没有设置 priority 字段,或者两个具有相同值的 WasmPlugins 对象,则排序将从 WasmPlugins 对象的名称和命名空间决定。默认值为 0

spec.pluginName

字符串

Envoy 配置中使用的插件名称。有些 Wasm 模块可能需要这个值来选择要执行的 Wasm 插件。

spec.pluginConfig

Struct

将要传递给插件的配置。

spec.pluginConfig.verificationKey

字符串

用于验证签名 OCI 镜像或 Wasm 模块的公钥。必须以 PEM 格式提供。

WorkloadSelector 对象指定用于确定过滤器是否可应用于代理的条件。匹配条件包括与代理关联的元数据、工作负载实例信息,如附加到 pod/VM 的标签,或代理在初始握手期间向 Istio 提供的任何其他信息。如果指定了多个条件,则所有条件都需要匹配才能选择工作负载实例。目前,只支持基于标签的选择机制。

表 1.16. WorkloadSelector

字段类型描述必需

matchLabels

map<string, string>

指定应应用策略的特定 pod/VM 集合的一个或多个标签。标签搜索范围仅限于存在资源的配置命名空间。

PullPolicy 对象指定要在获取 OCI 镜像时应用的 pull 行为。

表 1.17. pullPolicy

描述

<empty>

默认值为 IfNotPresent,但使用标签 latest 的 OCI 镜像除外,其默认值为 Always

IfNotPresent

如果在之前拉取了镜像的现有版本,则会使用它。如果本地没有镜像版本,我们将拉取最新版本。

Always

应用此插件时,始终拉取镜像的最新版本。

Struct 代表结构化数据值,由映射到动态输入的值的字段组成。在某些语言中,Struct 可能受到原生表示的支持。例如,在脚本语言中,JavaScript astruct 等脚本语言表示为对象。

表 1.18. Struct

字段类型描述

fields

map<string, Value>

动态输入的值的映射。

PluginPhase 指定将注入插件的过滤器链中的阶段。

表 1.19. PluginPhase

字段描述

<empty>

control plane 决定插入插件的位置。这通常位于过滤器链的末尾,在路由器前面。如果插件独立于其他插件,则不要指定 PluginPhase。

AUTHN

在 Istio 身份验证过滤器前插入插件。

AUTHZ

在 Istio 授权过滤器和 Istio 身份验证过滤器后插入插件。

STATS

在 Istio stats 过滤器和 Istio 授权过滤器后插入插件。

1.19.3.1. 部署 WasmPlugin 资源

您可以使用 WasmPlugin 资源启用 Red Hat OpenShift Service Mesh 扩展。在本例中,istio-system 是 Service Mesh control plane 项目的名称。以下示例创建了一个 openid-connect 过滤器,它将执行 OpenID Connect 流来验证用户。

流程

  1. 创建以下示例资源:

    plugin.yaml 示例

    apiVersion: extensions.istio.io/v1alpha1
    kind: WasmPlugin
    metadata:
      name: openid-connect
      namespace: istio-system
    spec:
      selector:
        matchLabels:
          istio: ingressgateway
      url: oci://private-registry:5000/openid-connect/openid:latest
      imagePullPolicy: IfNotPresent
      imagePullSecret: private-registry-pull-secret
      phase: AUTHN
      pluginConfig:
        openid_server: authn
        openid_realm: ingress

  2. 使用以下命令应用 plugin.yaml 文件:

    $ oc apply -f plugin.yaml

1.19.4. ServiceMeshExtension 容器格式

您必须有包含 WebAssembly 模块字节码的 .wasm 文件,以及容器文件系统根中的 manifest.yaml 文件,以使您的容器镜像成为有效的扩展镜像。

注意

在创建新的 WebAsembly 扩展时,请使用 WasmPlugin。ServiceMeshExtension 从 Red Hat OpenShift Service Mesh 版本 2.2 开始已弃用,并将在以后的版本中删除。

manifest.yaml

schemaVersion: 1

name: <your-extension>
description: <description>
version: 1.0.0
phase: PreAuthZ
priority: 100
module: extension.wasm

表 1.20. manifest.yml 的字段参考

字段描述必需

schemaVersion

用于清单架构的版本。目前唯一可能的值是 1

这是必填字段。

name

扩展名。

这个字段只是元数据且目前没有使用。

description

扩展的描述。

这个字段只是元数据且目前没有使用。

version

扩展名的版本。

这个字段只是元数据且目前没有使用。

phase

扩展的默认执行阶段。

这个为必填字段。

priority

扩展的默认优先级。

这个为必填字段。

module

容器文件系统的 root 到 WebAssembly 模块的相对路径。

这是必填字段。

1.19.5. ServiceMeshExtension 参考

ServiceMeshExtension API 提供了通过 WebAssembly 过滤器扩展 Istio 代理提供的功能的机制。编写 WebAssembly 扩展有两个部分:

  1. 使用提供 proxy-wasm API 的 SDK 编写扩展,并将其编译到 WebAssembly 模块。
  2. 将它打包到容器中。
注意

在创建新的 WebAsembly 扩展时,请使用 WasmPlugin。ServiceMeshExtension 从 Red Hat OpenShift Service Mesh 版本 2.2 开始已弃用,并将在以后的版本中删除。

表 1.21. ServiceMeshExtension 字段参考

字段描述

metadata.namespace

ServiceMeshExtension 源的 metadata.namespace 项具有特殊的语义:如果与 Control Plane 命名空间相等,扩展将应用到 Service Mesh 中与 workloadSelector 值匹配的所有工作负载。当部署到任何其他 Mesh 命名空间时,它只适用于同一命名空间中的工作负载。

spec.workloadSelector

spec.workloadSelector 字段的语义与 Istio Gateway 资源spec.selector 字段相同。它将根据其 Pod 标签匹配工作负载。如果没有指定 workloadSelector 值,扩展将应用到命名空间中的所有工作负载。

spec.config

这是一个结构化字段,将被移交给扩展名,其语义取决于您要部署的扩展名。

spec.image

指向包含扩展的镜像的容器镜像 URI。

spec.phase

该阶段根据现有 Istio 功能,如身份验证、授权和指标生成,决定过滤器链中的扩展是否被注入。有效值为: PreAuthN、PostAuthN、PreAuthZ、PostAuthZ、PreStats、PostStats。此字段默认为扩展名的 manifest.yaml 文件中设置的值,但可以被用户覆盖。

spec.priority

如果将具有相同 spec.phase 值的多个扩展应用到同一工作负载实例,则 spec.priority 值会决定执行顺序。优先级更高的扩展将首先执行。这允许相互依赖的扩展。此字段默认为扩展名的 manifest.yaml 文件中设置的值,但可以被用户覆盖。

1.19.5.1. 部署 ServiceMeshExtension 资源

您可以使用 ServiceMeshExtension 资源启用 Red Hat OpenShift Service Mesh 扩展。在本例中,istio-system 是 Service Mesh control plane 项目的名称。

注意

在创建新的 WebAsembly 扩展时,请使用 WasmPlugin。ServiceMeshExtension 从 Red Hat OpenShift Service Mesh 版本 2.2 开始已弃用,并将在以后的版本中删除。

有关使用 Rust SDK 构建的完整示例,请看标题附加过滤器。这是一个简单的过滤器,它会将一个或多个标头附加到 HTTP 响应中,其名称和值从扩展的 config 字段中获取。请参阅以下代码片段中的示例配置。

流程

  1. 创建以下示例资源:

    ServiceMeshExtension 资源 extension.yaml 示例

    apiVersion: maistra.io/v1
    kind: ServiceMeshExtension
    metadata:
      name: header-append
      namespace: istio-system
    spec:
      workloadSelector:
        labels:
          app: httpbin
      config:
        first-header: some-value
        another-header: another-value
      image: quay.io/maistra-dev/header-append-filter:2.1
      phase: PostAuthZ
      priority: 100

  2. 使用以下命令应用 extension.yaml 文件:

    $ oc apply -f <extension>.yaml

1.19.6. 从 ServiceMeshExtension 迁移到 WasmPlugin 资源

ServiceMeshExtension API 从 Red Hat OpenShift Service Mesh 版本 2.2 开始已弃用,并将在以后的版本中删除。如果使用 ServiceMeshExtention API,则必须迁移到 WasmPlugin API 才能继续使用 WebAssembly 扩展。

API 非常相似。迁移由两个步骤组成:

  1. 重命名您的插件文件并更新模块打包。
  2. 创建引用更新的容器镜像的 WasmPlugin 资源。

1.19.6.1. API 更改

新的 WasmPlugin API 与 ServiceMeshExtension 类似,但有一些区别,特别是在字段名称中:

表 1.22. ServiceMeshExtensionsWasmPlugin之间的字段变化

ServiceMeshExtensionWasmPlugin

spec.config

spec.pluginConfig

spec.workloadSelector

spec.selector

spec.image

spec.url

spec.phase 有效值: PreAuthN、PostAuthN、PreAuthZ、PostAuthZ、PreStats、PostStats

spec.phase 有效值: <empty>、AUTHN、AUTHZ、STATS

以下是如何将 ServiceMeshExtension 资源转换为 WasmPlugin 资源的示例。

ServiceMeshExtension 资源

apiVersion: maistra.io/v1
kind: ServiceMeshExtension
metadata:
  name: header-append
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: httpbin
  config:
    first-header: some-value
    another-header: another-value
  image: quay.io/maistra-dev/header-append-filter:2.2
  phase: PostAuthZ
  priority: 100

新的 WasmPlugin 资源等同于上面的 ServiceMeshExtension

apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: header-append
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: httpbin
  url: oci://quay.io/maistra-dev/header-append-filter:2.2
  phase: STATS
  pluginConfig:
    first-header: some-value
    another-header: another-value

1.19.6.2. 容器镜像格式更改

新的 WasmPlugin 容器镜像格式与 ServiceMeshExtensions 类似,其区别如下:

  • ServiceMeshExtension 容器格式需要在容器文件系统的根目录中名为 manifest.yaml 的元数据文件。WasmPlugin 容器格式不需要 manifest.yaml 文件。
  • .wasm 文件(实际插件)以前可能具有任何文件名,现在必须命名为 plugin.wasm,且必须位于容器文件系统的根目录中。

1.19.6.3. 迁移到 WasmPlugin 资源

要将 WebAsembly 扩展从 ServiceMeshExtension API 升级到 WasmPlugin API,您可以重命名您的插件文件。

先决条件

  • ServiceMeshControlPlane 升级到 2.2 或更高版本。
小心

因为这两个插件都会为每个请求调用,所以您可能需要在创建新 WasmPlugin 资源前删除现有的 ServiceMeshExtension 资源。您可能会获得不必要的结果,同时有两个插件活跃。

流程

  1. 更新您的容器镜像。如果插件已在容器内的 /plugin.wasm 中,则跳至下一步。如果没有:

    1. 确保插件文件名为 plugin.wasm。您需要将扩展文件命名为 plugin.wasm
    2. 确保插件文件位于 root (/)目录中。您必须将扩展文件存储在容器文件系统的根目录中。
    3. 重新构建容器镜像并将其推送到容器 registry。
  2. 删除 ServiceMeshExtension 资源,并创建一个 WasmPlugin 资源来引用您构建的新容器镜像。