Todos os produtos
Search
Central de documentação

Alibaba Cloud Service Mesh:Escreva um plug-in Wasm em Go para um proxy Envoy

Última atualização: Jun 28, 2026

WebAssembly for Proxies é uma nova especificação que permite aos desenvolvedores criar plug-ins portáteis usando WebAssembly (Wasm). Esses plug-ins podem ser executados em diversos servidores proxy. O Service Mesh (ASM) oferece suporte à especificação WebAssembly for Proxies. Este tópico descreve como escrever um plug-in Wasm em Go para um proxy Envoy no ASM.

Pré-requisitos

Informações básicas

O Wasm é um formato binário portátil e emergente para código executável. O código é executado com velocidade quase nativa em uma sandbox segura para memória (para o host). Essa sandbox possui restrições de recursos bem definidas e fornece uma API clara para comunicação com o ambiente host incorporado (neste caso, refere-se a um proxy).

Os plug-ins Wasm oferecem os seguintes benefícios:

  • Agilidade: É possível atualizar plug-ins sem reiniciar o proxy Envoy, garantindo que as requisições sejam tratadas conforme o esperado.

  • Confiabilidade e isolamento: Como os plug-ins são implantados dentro de uma sandbox com restrições de recursos, eles podem falhar sem derrubar o proxy Envoy.

  • Segurança: A implantação ocorre em uma sandbox com uma API bem definida para comunicação com o proxy, o que garante controle rigoroso.

  • Diversidade: Os plug-ins podem ser escritos em várias linguagens de programação, como C++, Go e Rust.

Para obter mais informações sobre plug-ins Wasm, consulte WebAssembly-in-Envoy.md e OVERVIEW.md.

Exemplo de configuração

Neste exemplo, um plug-in Wasm é escrito em Go. Após a criação do plug-in, um arquivo binário Wasm é gerado e empacotado em uma imagem. Essa imagem deve ser enviada para um repositório de imagens OCI. Depois do envio, configure o recurso WasmPlugin no ASM e aplique o plug-in ao proxy Envoy especificado.

Este exemplo desenvolve um plug-in para verificar se uma requisição contém o cabeçalho allow: true. Caso contrário, o sistema retorna o código de status 403 e um corpo específico. Se o cabeçalho estiver presente, a aplicação HTTPBin poderá ser acessada normalmente.

Etapa 1: Preparar um ambiente de desenvolvimento

Para desenvolver um plug-in Wasm em Go para um proxy Envoy, instale primeiro as seguintes ferramentas:

  • Go: O compilador Go e ferramentas relacionadas são usados para escrever projetos Go. Para obter mais informações, consulte The Go Programming Language.

  • Docker: Neste exemplo, o Docker é utilizado para compilar e enviar imagens OCI.

  • TinyGo: Embora o Go seja usado para escrever o plug-in Wasm, não é possível usar o compilador oficial do Go para compilar código Go no formato Wasm. Use o TinyGo. Para saber mais sobre como instalar o TinyGo, consulte Guia de instalação rápida.

Para obter mais informações sobre os SDKs dos quais o plug-in Wasm depende, consulte proxy-wasm-go-sdk no site do GitHub. Você encontra o código completo do SDK Go para Proxy-Wasm no site. Caso queira usar outros SDKs, consulte o código do SDK Go para Proxy-Wasm como referência.

Etapa 2: Escrever o código do plug-in

  1. Crie uma pasta e crie um arquivo main.go com o seguinte conteúdo:

    Show the main.go file

    package main
    import (
    	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
    	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
    )
    func main() {
    	proxywasm.SetVMContext(&vmContext{})
    }
    type vmContext struct {
    	// Embed the default VM context here,
    	// so that we don't need to reimplement all the methods.
    	types.DefaultVMContext
    }
    // Override types.DefaultVMContext.
    func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
    	return &pluginContext{}
    }
    type pluginContext struct {
    	// Embed the default plugin context here,
    	// so that we don't need to reimplement all the methods.
    	types.DefaultPluginContext
    }
    // Override types.DefaultPluginContext.
    func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus {
    	return types.OnPluginStartStatusOK
    }
    // Override types.DefaultPluginContext.
    func (ctx *pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
    	return &HeaderAuthorizationHandler{}
    }
    type HeaderAuthorizationHandler struct {
    	// Embed the default http context here,
    	// so that we don't need to reimplement all the methods.
    	types.DefaultHttpContext
    }
    // Override types.DefaultHttpContext.
    func (ctx *HeaderAuthorizationHandler) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
    	// Randomly routing to the canary cluster.
    	const AuthorizationKey = "allow"
    	value, err := proxywasm.GetHttpRequestHeader(AuthorizationKey)
    	if err != nil || value != "true" {
    		proxywasm.LogDebugf("request header: 'allow' is %v, only true can passthrough", value)
    		return ctx.DenyRequest()
    	}
    	return types.ActionContinue
    }
    func (ctx *HeaderAuthorizationHandler) DenyRequest() types.Action {
    	proxywasm.SendHttpResponse(403, [][2]string{{"Content-Type", "text/plain"}}, []byte("Forbidden by ASM Wasm Plugin"), -1)
    	return types.ActionPause
    }
    
  2. Execute os seguintes comandos na pasta criada para obter as dependências do SDK:

    go mod init
    go mod tidy
  3. Execute o comando a seguir para compilar o código em um arquivo binário Wasm:

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

    Um arquivo plugin.wasm é gerado. Esse arquivo é o executável binário Wasm.

Etapa 3: Criar uma imagem OCI do plug-in Wasm e enviá-la para a instância do Container Registry Enterprise Edition

  1. Na pasta criada na Etapa 2, crie um arquivo Dockerfile com o seguinte conteúdo:

    FROM scratch
    ADD ./plugin.wasm ./plugin.wasm
  2. Execute os comandos a seguir para criar uma imagem:

    docker build -t header-authorization:v0.0.1 .
  3. Crie um repositório de imagens. Para obter mais informações, consulte as subetapas 2.a e 2.b da Etapa 1 no tópico Implementar um WAF em um gateway ASM com o plug-in Coraza Wasm.

    Neste exemplo, o namespace é test-oci e o nome do repositório é header-authorization. A figura a seguir mostra o repositório criado.

    Na página de detalhes do repositório, em Image Guide, a seção Push image to the Registry fornece os comandos para fazer login na instância do Registry com docker login, marcar a imagem com docker tag [ImageId] <registry-url>/<namespace>/<repository>:[image-version] e enviar a imagem com docker push <registry-url>/<namespace>/<repository>:[image-version]. Substitua [ImageId] e [image-version] pelos valores reais.

    Para obter mais informações sobre como enviar uma imagem para a instância do Container Registry Enterprise Edition, consulte Push image to the registry na figura anterior.

Etapa 4: Aplicar o plug-in Wasm ao gateway de entrada

  1. Configure as permissões para baixar imagens. Para obter mais informações, consulte Etapa 2: Configurar permissões para baixar imagens.

    Execute o comando a seguir para criar um Secret chamado wasm-secret:

    kubectl create secret docker-registry -n istio-system wasm-secret --docker-server=${Domain name of the Container Registry Enterprise Edition instance} --docker-username =${Username} --docker-password =${Password}
  2. Crie um arquivo asm-plugin.yaml com o seguinte conteúdo:

    apiVersion: extensions.istio.io/v1alpha1
    kind: WasmPlugin
    metadata:
      name: header-authorization
      namespace: istio-system
    spec:
      imagePullPolicy: IfNotPresent
      imagePullSecret: wasm-secret
      selector:
        matchLabels:
          istio: ingressgateway
      url: oci://${Domain name of the Container Registry Enterprise Edition instance}/test-oci/header-authorization:v0.0.1
      phase: AUTHN
  3. Use o kubectl para conectar-se à instância do ASM com base nas informações do arquivo kubeconfig. Em seguida, execute o comando a seguir para aplicar o plug-in Wasm à instância do ASM:

    kubectl apply -f wasm-plugin.yaml

Etapa 5: Verificar se o plug-in Wasm entrou em vigor

  1. Use o arquivo kubeconfig do cluster no plano de dados onde reside o gateway de entrada e execute o comando a seguir para ativar o recurso de log de depuração do plug-in Wasm aplicado ao gateway de entrada:

    kubectl -n istio-system exec ${Name of the pod where the ingress gateway resides} -c istio-proxy -- curl -XPOST "localhost:15000/logging?wasm=debug"
  2. Execute o comando a seguir para acessar a aplicação HTTPBin exposta pelo gateway de entrada:

    curl ${IP address of the ingress gateway}/status/418

    Saída esperada:

    Forbidden by ASM Wasm Plugin
  3. Visualize os logs do pod onde o gateway de entrada reside.

    Logs de exemplo:

    2024-03-08T08:16:46.747394Z	debug	envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1168	wasm log istio-system.header-authorization: request header: 'allow' is , only true can passthrough	thread=24
    {"bytes_received":"0","bytes_sent":"28","downstream_local_address":"xxxxxxx","downstream_remote_address":"xxxxxxxx","duration":"0","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"780c8493-13e4-4f97-9771-486efe30347c","requested_server_name":"-","response_code":"403","response_flags":"-","route_name":"httpbin","start_time":"2024-03-08T08:16:46.747Z","trace_id":"-","upstream_cluster":"outbound|8000||httpbin.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_response_time":"-","upstream_transport_failure_reason":"-","user_agent":"curl/8.4.0","x_forwarded_for":"xxxxxx","authority_for":"xxxxxx"}
  4. Execute o comando a seguir para acessar a aplicação HTTPBin exposta pelo gateway de entrada:

    curl ${IP address of the ingress gateway}/status/418 -H "allow: true"

    Saída esperada:

        -=[ teapot ]=-
           _...._
         .'  _ _ `.
        | ."` ^ `". _,
        \_;`"---"`|//
          |       ;/
          \_     _/
            `"""`

    A saída indica que a aplicação HTTPBin pode ser acessada conforme o esperado.

Vazamentos de memória no TinyGo

Existem vazamentos de memória no plug-in Wasm para um proxy Envoy compilado com o TinyGo. A comunidade proxy-wasm-go-sdk recomenda o uso do nottinygc para otimização da compilação. Siga as etapas abaixo para usar o nottinygc na otimização da compilação:

  1. Adicione o seguinte código import no início do arquivo main.go:

    import _ "github.com/wasilibs/nottinygc"

    Se nenhuma dependência for encontrada, execute o comando go mod tidy para baixar as dependências automaticamente.

  2. Execute o comando a seguir para compilar o código:

    tinygo build -o plugin.wasm -gc=custom -tags='custommalloc nottinygc_envoy'  -target=wasi -scheduler=none main.go

    O comando anterior define os parâmetros -gc e -tags. Para obter mais informações, consulte nottinygc.