×

您可以使用 WebAssembly 扩展直接向 Red Hat OpenShift 服务网格代理添加新功能。这使您可以将更多常用功能从应用程序中移除,并使用编译成 WebAssembly 字节码的单一语言来实现它们。

WebAssembly 扩展在 IBM Z® 和 IBM Power® 上不受支持。

WebAssembly 模块概述

WebAssembly 模块可以在许多平台上运行,包括代理,并具有广泛的语言支持、快速的执行速度和默认的沙箱安全模型。

Red Hat OpenShift 服务网格扩展是Envoy HTTP 过滤器,赋予它们广泛的功能

  • 操作请求和响应的主体和标头。

  • 向请求路径中不存在的服务发出带外 HTTP 请求,例如身份验证或策略检查。

  • 用于过滤器相互通信的旁路数据存储和队列。

创建新的 WebAssembly 扩展时,请使用WasmPlugin API。ServiceMeshExtension API 在 Red Hat OpenShift 服务网格 2.2 版本中已弃用,并在 Red Hat OpenShift 服务网格 2.3 版本中已移除。

编写 Red Hat OpenShift 服务网格扩展包含两个部分

  1. 您必须使用公开proxy-wasm API 的 SDK 编写扩展,并将其编译成 WebAssembly 模块。

  2. 然后,您必须将模块打包到容器中。

支持的语言

您可以使用任何编译成 WebAssembly 字节码的语言来编写 Red Hat OpenShift 服务网格扩展,但以下语言具有现有的 SDK,这些 SDK 公开了 proxy-wasm API,以便可以直接使用。

表 1. 支持的语言
语言 维护者 代码库

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

WasmPlugin 容器格式

Istio 在其 Wasm Plugin 机制中支持开放容器倡议 (OCI) 镜像。您可以将 Wasm Plugin 分发为容器镜像,并且可以使用spec.url 字段引用容器注册表位置。例如,quay.io/my-username/my-plugin:latest

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

  • plugin.wasm(必需)- 内容层。此层包含包含 WebAssembly 模块字节码的.wasm 二进制文件,供运行时加载。您必须将此文件命名为plugin.wasm

  • runtime-config.json(可选)- 配置层。此层包含描述目标运行时模块元数据的 JSON 格式字符串。根据目标运行时,配置层还可以包含其他数据。例如,WASM Envoy 过滤器的配置包含过滤器上可用的 root_ids。

WasmPlugin API 参考

WasmPlugins API 提供了一种机制,可以通过 WebAssembly 过滤器扩展 Istio 代理提供功能。

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

在下面的例子中,一个身份验证过滤器实现了一个OpenID流程,并用JSON Web Token (JWT)填充授权头。Istio身份验证会使用这个令牌并将其部署到入口网关。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

下面是相同的例子,但这次使用的是Open Container Initiative (OCI)镜像,而不是文件系统中的文件。请注意urlimagePullPolicyimagePullSecret字段。

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. WasmPlugin字段参考
字段 类型 描述 必填

spec.selector

WorkloadSelector

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

spec.url

字符串

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

spec.sha256

字符串

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

spec.imagePullPolicy

PullPolicy

获取OCI镜像时要应用的拉取行为。仅当通过标签而不是SHA引用镜像时才相关。默认为IfNotPresent,但当url字段引用OCI镜像且使用latest标签时,默认为Always,这反映了K8s的行为。如果url字段直接使用file://http[s]://引用Wasm模块,则忽略此设置。

spec.imagePullSecret

字符串

用于OCI镜像拉取的凭据。与WasmPlugin对象位于同一命名空间中的密钥名称,其中包含用于在拉取镜像时对注册表进行身份验证的拉取密钥。

spec.phase

PluginPhase

确定在此过滤器链中注入此WasmPlugin对象的位置。

spec.priority

int64

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

spec.pluginName

字符串

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

spec.pluginConfig

结构体

将传递给插件的配置。

spec.pluginConfig.verificationKey

字符串

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

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

表3. WorkloadSelector
字段 类型 描述 必填

matchLabels

map<string, string>

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

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

表4. PullPolicy
描述

<empty>

默认为IfNotPresent,但对于带有latest标签的OCI镜像,默认为Always

IfNotPresent

如果之前已经拉取了现有版本的镜像,则将使用该版本。如果本地不存在任何版本的镜像,我们将拉取最新版本。

Always

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

Struct表示结构化数据值,由映射到动态类型值的字段组成。在某些语言中,Struct可能由本机表示支持。例如,在JavaScript等脚本语言中,struct表示为对象。

表5. Struct
字段 类型 描述

fields

map<string, Value>

动态类型值的映射。

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

表6. PluginPhase
字段 描述

<empty>

控制平面决定在哪里插入插件。这通常位于过滤器链的末尾,就在路由器之前。如果插件独立于其他插件,则不要指定PluginPhase。

AUTHN

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

AUTHZ

在Istio授权过滤器之前以及Istio身份验证过滤器之后插入插件。

STATS

在Istio统计过滤器之前以及Istio授权过滤器之后插入插件。

部署WasmPlugin资源

您可以使用WasmPlugin资源启用Red Hat OpenShift Service Mesh扩展。在此示例中,istio-system是Service Mesh控制平面项目的名称。以下示例创建了一个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

ServiceMeshExtension容器格式

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

创建新的 WebAssembly 扩展时,请使用WasmPlugin API。ServiceMeshExtension API 在 Red Hat OpenShift 服务网格 2.2 版本中已弃用,并在 Red Hat OpenShift 服务网格 2.3 版本中已移除。

manifest.yaml
schemaVersion: 1

name: <your-extension>
description: <description>
version: 1.0.0
phase: PreAuthZ
priority: 100
module: extension.wasm
表7. manifest.yml字段参考
字段 描述 必填

schemaVersion

用于清单模式的版本控制。目前唯一可能的值是1

这是必填字段。

name

扩展的名称。

此字段只是元数据,目前未使用。

description

扩展的描述。

此字段只是元数据,目前未使用。

version

扩展的版本。

此字段只是元数据,目前未使用。

phase

扩展的默认执行阶段。

这是必填字段。

priority

扩展的默认优先级。

这是必填字段。

module

从容器文件系统的根目录到WebAssembly模块的相对路径。

这是必填字段。

ServiceMeshExtension参考

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

  1. 使用公开proxy-wasm API的SDK编写扩展,并将其编译为WebAssembly模块。

  2. 将其打包到容器中。

创建新的WebAssembly扩展时,请使用WasmPlugin API。在Red Hat OpenShift Service Mesh 2.2版本中已弃用的ServiceMeshExtension API已在Red Hat OpenShift Service Mesh 2.3版本中移除。

表8. ServiceMeshExtension字段参考
字段 描述

metadata.namespace

ServiceMeshExtension 资源的metadata.namespace 字段具有特殊语义:如果它等于控制平面命名空间,则该扩展将应用于服务网格中与其workloadSelector值匹配的所有工作负载。如果部署到任何其他网格命名空间,则它仅应用于同一命名空间中的工作负载。

spec.workloadSelector

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

spec.config

这是一个结构化字段,将传递给扩展,其语义取决于您正在部署的扩展。

spec.image

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

spec.phase

phase 决定了扩展在过滤器链中的位置,相对于现有的 Istio 功能(如身份验证、授权和指标生成)。有效值为:PreAuthN、PostAuthN、PreAuthZ、PostAuthZ、PreStats、PostStats。此字段默认为扩展的manifest.yaml文件中设置的值,但用户可以覆盖它。

spec.priority

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

部署ServiceMeshExtension资源

您可以使用ServiceMeshExtension资源启用 Red Hat OpenShift Service Mesh 扩展。在此示例中,istio-system是服务网格控制平面项目的名称。

创建新的 WebAssembly 扩展时,请使用WasmPlugin API。ServiceMeshExtension API 在 Red Hat OpenShift Service Mesh 2.2 版本中已弃用,并在 Red Hat OpenShift Service Mesh 2.3 版本中移除。

有关使用 Rust SDK 构建的完整示例,请查看header-append-filter。它是一个简单的过滤器,它将一个或多个标头添加到 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

ServiceMeshExtension资源迁移到WasmPlugin资源

在 Red Hat OpenShift Service Mesh 2.2 版本中已弃用的ServiceMeshExtension API 已在 Red Hat OpenShift Service Mesh 2.3 版本中移除。如果您正在使用ServiceMeshExtension API,则必须迁移到WasmPlugin API 才能继续使用您的 WebAssembly 扩展。

这两个 API 非常相似。迁移包括两个步骤

  1. 重命名插件文件并更新模块打包。

  2. 创建一个引用更新的容器镜像的WasmPlugin资源。

API 更改

新的WasmPlugin API 与ServiceMeshExtension相似,但有一些区别,尤其是在字段名称方面

表 9.ServiceMeshExtensionsWasmPlugin之间的字段更改
ServiceMeshExtension WasmPlugin

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
等效于上述 ServiceMeshExtension 的新的 WasmPlugin 资源
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

容器镜像格式更改

新的WasmPlugin容器镜像格式与ServiceMeshExtensions相似,但存在以下差异

  • ServiceMeshExtension容器格式需要在容器文件系统的根目录中有一个名为manifest.yaml的元数据文件。WasmPlugin容器格式不需要manifest.yaml文件。

  • 以前可以具有任何文件名 的.wasm文件(实际插件)现在必须命名为plugin.wasm,并且必须位于容器文件系统的根目录中。

迁移到WasmPlugin资源

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

先决条件
  • ServiceMeshControlPlane已升级到 2.2 或更高版本。

步骤
  1. 更新您的容器镜像。如果插件已经在容器内的/plugin.wasm中,请跳到下一步。如果不是

    1. 确保插件文件命名为plugin.wasm。您必须将扩展文件命名为plugin.wasm

    2. 确保插件文件位于根(/)目录中。您必须将扩展文件存储在容器文件系统的根目录中。

    3. 重新构建您的容器镜像并将其推送到容器注册表。

  2. 删除ServiceMeshExtension资源并创建一个引用您构建的新容器镜像的WasmPlugin资源。