Tous les produits
Search
Centre de documentation

Alibaba Cloud Service Mesh:Écrire un plug-in Wasm en Go pour un proxy Envoy

Dernière mise à jour :Aug 11, 2026

WebAssembly for Proxies est une nouvelle spécification qui permet aux développeurs de créer des plug-ins portables avec WebAssembly (Wasm). Ces plug-ins s'exécutent sur divers serveurs proxy. Service Mesh (ASM) prend en charge la spécification WebAssembly for Proxies. Cette rubrique explique comment écrire un plug-in Wasm en Go pour un proxy Envoy dans ASM.

Prérequis

Informations générales

Wasm est un format binaire portable et émergent pour le code exécutable. Le code s'exécute à une vitesse quasi native dans un bac à sable sécurisé pour la mémoire (pour l'hôte). Ce bac à sable impose des contraintes de ressources clairement définies et fournit une API explicite pour communiquer avec l'environnement hôte d'intégration (ici, un proxy).

Les plug-ins Wasm offrent les avantages suivants :

  • Agilité : vous pouvez mettre à jour les plug-ins sans redémarrer le proxy Envoy. Ainsi, les requêtes sont traitées comme prévu.

  • Fiabilité et isolation : comme les plug-ins sont déployés dans un bac à sable avec des contraintes de ressources, ils peuvent planter sans entraîner l'arrêt du proxy Envoy.

  • Sécurité : étant déployés dans un bac à sable disposant d'une API clairement définie pour communiquer avec un proxy, les plug-ins sont strictement contrôlés.

  • Diversité : les plug-ins peuvent être écrits dans plusieurs langages de programmation, tels que C++, Go et Rust.

Pour en savoir plus sur les plug-ins Wasm, consultez WebAssembly-in-Envoy.md et OVERVIEW.md.

Exemple de configuration

Dans cet exemple, nous écrivons un plug-in Wasm en Go. Une fois le plug-in développé, nous générons un fichier binaire Wasm, puis nous l'encapsulons dans une image. L'image doit être poussée vers un registre d'images OCI. Après le push de l'image, configurez la ressource WasmPlugin dans ASM et appliquez le plug-in au proxy Envoy spécifié.

Dans cet exemple, un plug-in vérifie si une requête contient l'en-tête allow: true. Si ce n'est pas le cas, le code d'état 403 et le corps spécifié sont renvoyés. Sinon, l'application HTTPBin est accessible comme prévu.

Étape 1 : Préparer l'environnement de développement

Pour développer un plug-in Wasm en Go destiné à un proxy Envoy, installez d'abord les outils suivants :

  • Go : le compilateur Go et les outils associés servent à écrire des projets Go. Pour plus d'informations, voir The Go Programming Language.

  • Docker : dans cet exemple, Docker sert à construire et pousser des images OCI.

  • TinyGo : bien que Go soit utilisé pour écrire le plug-in Wasm, vous ne pouvez pas utiliser le compilateur Go officiel pour compiler le code Go au format Wasm. Vous devez utiliser TinyGo. Pour savoir comment installer TinyGo, consultez le Guide d'installation rapide.

Pour plus d'informations sur les SDK dont dépend le plug-in Wasm, consultez proxy-wasm-go-sdk sur GitHub. Vous y trouverez le code complet du SDK Go pour Proxy-Wasm. Si vous souhaitez utiliser d'autres SDK, inspirez-vous du code du SDK Go pour Proxy-Wasm.

Étape 2 : Écrire le code du plug-in

  1. Créez un dossier et créez un fichier main.go contenant le contenu suivant :

    Afficher le fichier main.go

    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. Exécutez les commandes suivantes dans le dossier créé pour obtenir les dépendances du SDK :

    go mod init
    go mod tidy
  3. Exécutez la commande suivante pour compiler le code en un fichier binaire Wasm :

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

    Un fichier plugin.wasm est généré. Il s'agit du fichier exécutable binaire Wasm.

Étape 3 : Créer une image OCI du plug-in Wasm et la pousser vers l'instance Container Registry Enterprise Edition

  1. Dans le dossier créé à l'étape Étape 2, créez un fichier Dockerfile contenant le contenu suivant :

    FROM scratch
    ADD ./plugin.wasm ./plugin.wasm
  2. Exécutez la commande suivante pour créer une image :

    docker build -t header-authorization:v0.0.1 .
  3. Créez un référentiel d'images. Pour plus d'informations, consultez les sous-étapes 2.a et 2.b de l'étape 1 de la rubrique Implémenter un WAF sur une passerelle ASM avec le plug-in Coraza Wasm.

    Dans cet exemple, le namespace est test-oci et le nom du référentiel est header-authorization. La figure suivante montre le référentiel créé.

    Sur la page des détails du référentiel, dans la section Image Guide, la partie Push image to the Registry fournit les commandes pour se connecter à l'instance Registry avec docker login, étiqueter l'image avec docker tag [ImageId] <registry-url>/<namespace>/<repository>:[image-version] et pousser l'image avec docker push <registry-url>/<namespace>/<repository>:[image-version]. Remplacez [ImageId] et [image-version] par les valeurs réelles.

    Pour plus d'informations sur la façon de pousser une image vers l'instance Container Registry Enterprise Edition, consultez Push image to the registry dans la figure précédente.

Étape 4 : Appliquer le plug-in Wasm à la passerelle d'entrée

  1. Configurez les autorisations pour extraire les images. Pour plus d'informations, voir Étape 2 : Configurer les autorisations pour extraire les images.

    Exécutez la commande suivante pour créer un Secret nommé 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. Créez un fichier asm-plugin.yaml contenant le contenu suivant :

    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. Connectez-vous à l'instance ASM avec kubectl en utilisant les informations du fichier kubeconfig. Ensuite, exécutez la commande suivante pour appliquer le plug-in Wasm à l'instance ASM :

    kubectl apply -f wasm-plugin.yaml

Étape 5 : Vérifier que le plug-in Wasm prend effet

  1. Utilisez le fichier kubeconfig du cluster sur le plan de données où réside la passerelle d'entrée et exécutez la commande suivante pour activer la fonctionnalité de journalisation de débogage pour le plug-in Wasm appliqué à la passerelle d'entrée :

    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. Exécutez la commande suivante pour accéder à l'application HTTPBin exposée via la passerelle d'entrée :

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

    Résultat attendu :

    Forbidden by ASM Wasm Plugin
  3. Consultez les journaux du pod où réside la passerelle d'entrée.

    Exemple de journaux :

    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. Exécutez la commande suivante pour accéder à l'application HTTPBin exposée via la passerelle d'entrée :

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

    Résultat attendu :

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

    Le résultat indique que l'application HTTPBin est accessible comme prévu.

Fuites de mémoire dans TinyGo

Des fuites de mémoire existent dans le plug-in Wasm pour un proxy Envoy compilé à l'aide de TinyGo. La communauté proxy-wasm-go-sdk recommande d'utiliser nottinygc pour optimiser la compilation. Suivez les étapes ci-dessous pour utiliser nottinygc afin d'optimiser la compilation :

  1. Ajoutez le code import suivant au début du fichier main.go :

    import _ "github.com/wasilibs/nottinygc"

    Si aucune dépendance n'est trouvée, exécutez la commande go mod tidy pour télécharger automatiquement les dépendances.

  2. Exécutez la commande suivante pour compiler le code :

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

    La commande précédente définit les paramètres -gc et -tags. Pour plus d'informations, consultez nottinygc.