Plug‑in-Code vorbereiten

Der benutzerdefinierte Code, den Sie für Service Extensions-Plug-ins erstellen, muss verpackt und in Artifact Registry hochgeladen werden, bevor andere Dienste darauf zugreifen können. Auf dieser Seite wird beschrieben, wie Sie Plug-in-Code erstellen, den Code verpacken und in ein Artifact Registry-Repository hochladen.

Dieses Feature befindet sich für Media CDN im Vorschaumodus.

Informationen zu Diensterweiterungen finden Sie unter Übersicht über Diensterweiterungen.

Bevor Sie beginnen, sollten Sie sich die Best Practices für das Schreiben von Plug-in-Code ansehen.

Weitere Beispiele finden Sie unter Codebeispiele für Plug-ins.

Hinweis

  1. Melden Sie sich in Ihrem Google Cloud -Konto an. Wenn Sie mit Google Cloudnoch nicht vertraut sind, erstellen Sie einfach ein Konto, um die Leistungsfähigkeit unserer Produkte in der Praxis sehen und bewerten zu können. Neukunden erhalten außerdem ein Guthaben von 300 $, um Arbeitslasten auszuführen, zu testen und bereitzustellen.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  5. Install the Google Cloud CLI.

  6. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  7. To initialize the gcloud CLI, run the following command:

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  11. Install the Google Cloud CLI.

  12. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  13. To initialize the gcloud CLI, run the following command:

    gcloud init

Toolchain einrichten

C++

Mit dem Proxy-Wasm-C++-SDK können Entwickler C++ verwenden, um WebAssembly-Plug-ins (Wasm) für Service Extensions zu implementieren. Das SDK verwendet die C++-WebAssembly-Toolchain Emscripten sowie andere Bibliotheken wie protobuf und optional Abseil.

Da das Erstellen von in C++ geschriebenen Plug-ins von bestimmten Versionen dieser Tools und Bibliotheken abhängt, empfehlen wir die Verwendung des Docker-Images, das vom Proxy-Wasm C++ SDK bereitgestellt wird. In der Anleitung für C++ auf dieser Seite wird die Docker-Methode verwendet. Informationen zum Erstellen von C++-Plug-ins ohne Docker finden Sie in der Dokumentation zum Proxy-Wasm C++ SDK.

  1. Installieren Sie Docker, falls es noch nicht installiert ist. Docker ist in Cloud Shell, der Google Cloud interaktiven Shell-Umgebung, enthalten.

  2. Laden Sie eine Kopie des Proxy-Wasm C++ SDK herunter. Am einfachsten geht das, wenn Sie das Git-Repository klonen:

    git clone https://github.com/proxy-wasm/proxy-wasm-cpp-sdk.git
    
  3. Erstellen Sie das Docker-Image des Proxy-Wasm C++ SDK aus dem vom SDK bereitgestellten Dockerfile:

    cd proxy-wasm-cpp-sdk
    docker build -t wasmsdk:v3 -f Dockerfile-sdk .
    

    Wenn der Befehl die SDK-Bibliotheken und Abhängigkeiten erstellt hat, wird das resultierende Docker-Image mit dem angegebenen Tag verknüpft, in diesem Beispiel wasmsdk:v3.

Go

Das Proxy-Wasm Go SDK bietet ein Go SDK mit vollem Funktionsumfang. Go bietet eine gute Leistung und umfassende Unterstützung für Drittanbieterbibliotheken, die in reinem Go geschrieben sind.

Go-Toolchain v1.24.0 installieren

Rust

Die Anpassungsfunktion von Diensterweiterungen wird durch die Verwendung von WebAssembly und Proxy-Wasm bereitgestellt. WebAssembly unterstützt eine Reihe von Programmiersprachen. Google empfiehlt Rust, da es eine hervorragende WebAssembly-Unterstützung bietet und Proxy-Wasm ein voll funktionsfähiges Rust SDK bereitstellt. Rust bietet außerdem eine gute Leistung und eine hohe Typsicherheit.

  1. Installieren Sie die Rust-Toolchain.

    Folgen Sie am Ende der Installation der Anleitung auf dem Bildschirm, um die Konfiguration abzuschließen.

  2. Fügen Sie der Rust-Toolchain Wasm-Unterstützung hinzu:

    rustup target add wasm32-wasip1
    

Plug-in-Paket erstellen

C++

  1. Erstellen Sie ein neues Verzeichnis, das sich von proxy-wasm-cpp-sdk unterscheidet:

    mkdir myproject
    
  2. Erstellen Sie im Verzeichnis ein Makefile mit folgendem Inhalt:

    # Express any dependencies
    PROTOBUF=     # full / lite / none
    WASM_DEPS=    # absl_base re2 ...
    
    # Include the SDK Makefile
    PROXY_WASM_CPP_SDK=/sdk
    include ${PROXY_WASM_CPP_SDK}/Makefile
    
  3. Fügen Sie im selben Verzeichnis eine C++-Quelldatei für das Plug-in hinzu. Die Namen der C++-Quelldateien müssen mit den Wasm-Dateien übereinstimmen, auf die das Makefile abzielt. Dabei muss das Suffix .wasm durch .cc ersetzt werden. In diesem Beispiel muss die Quelldatei den Namen myproject.cc haben.

  4. Fügen Sie den Plug-in-Code in die Quelldatei ein.

    Der folgende Beispielquellcode ist ein Plug-in, das den Host der Anfrage neu schreibt und einen Antwortheader ausgibt:

    #include "proxy_wasm_intrinsics.h"
    
    class MyHttpContext : public Context {
     public:
      explicit MyHttpContext(uint32_t id, RootContext* root) : Context(id, root) {}
    
      FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                           bool end_of_stream) override {
        LOG_INFO("onRequestHeaders: hello from wasm");
    
        // Route Extension example: host rewrite
        if (replaceRequestHeader(":authority", "service-extensions.com") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :authority header");
        }
        if (replaceRequestHeader(":path", "/") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :path header");
        }
        return FilterHeadersStatus::Continue;
      }
    
      FilterHeadersStatus onResponseHeaders(uint32_t headers,
                                            bool end_of_stream) override {
        LOG_INFO("onResponseHeaders: hello from wasm");
    
        // Traffic Extension example: add response header
        if (addResponseHeader("hello", "service-extensions") != WasmResult::Ok) {
          LOG_ERROR("Failed to add response header");
        }
        return FilterHeadersStatus::Continue;
      }
    };
    
    static RegisterContextFactory register_StaticContext(
        CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(RootContext));

    Die Methode onRequestHeaders ist ein Callback, der von Service Extensions aufgerufen wird.

Go

  1. Erstellen Sie ein neues Verzeichnis für das Plug‑in:

    mkdir go-plugin
    
  2. Erstellen Sie im Verzeichnis mit dem Go-Tool eine go.mod-Datei:

    go mod init go-plugin
    
  3. Erstellen Sie im selben Verzeichnis eine Quelldatei mit dem Namen main.go und fügen Sie Ihren Plug-in-Code in die Datei ein.

    Der folgende Beispielquellcode ist ein Plug-in, das den Anfragehost umschreibt und einen Antwortheader ausgibt:

    package main
    
    import (
    	"fmt"
    
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
    )
    
    func main() {}
    func init() {
    	proxywasm.SetVMContext(&vmContext{})
    }
    
    type vmContext struct {
    	types.DefaultVMContext
    }
    
    type pluginContext struct {
    	types.DefaultPluginContext
    }
    
    type httpContext struct {
    	types.DefaultHttpContext
    }
    
    func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
    	return &pluginContext{}
    }
    
    func (*pluginContext) NewHttpContext(uint32) types.HttpContext {
    	return &httpContext{}
    }
    
    func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onRequestHeaders: hello from wasm")
    
    	// Route Extension example: host rewrite
    	err := proxywasm.ReplaceHttpRequestHeader(":authority", "service-extensions.com")
    	if err != nil {
    		panic(err)
    	}
    	err = proxywasm.ReplaceHttpRequestHeader(":path", "/")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    
    func (ctx *httpContext) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onResponseHeaders: hello from wasm")
    
    	// Traffic Extension example: add response header
    	err := proxywasm.AddHttpResponseHeader("hello", "service-extensions")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    

    Die Methode OnHttpRequestHeaders ist ein Callback, der von Service Extensions aufgerufen wird.

  4. Führen Sie go mod tidy aus, um Bibliotheksabhängigkeiten herunterzuladen und anzupinnen:

    go mod tidy
    

Rust

  1. Erstellen Sie mit dem Befehl cargo new aus dem Rust-Paketmanager Cargo ein Rust-Paketverzeichnis:

    cargo new --lib my-wasm-plugin
    

    Mit dem Befehl wird ein Verzeichnis erstellt, das eine cargo.toml-Datei enthält, die Sie aktualisieren können, um zu beschreiben, wie das Rust-Paket erstellt wird, und ein src-Verzeichnis, in dem Sie den Plug‑in-Code speichern.

  2. Aktualisieren Sie die Datei cargo.toml, um die Parameter anzugeben, die zum Erstellen des Pakets erforderlich sind:

    [package]
    name = "my-wasm-plugin"
    version = "0.1.0"
    edition = "2021"
    
  3. Fügen Sie den Abschnitt dependencies hinzu, um das Proxy-Wasm Rust SDK und die Logging-Unterstützung als Abhängigkeiten zu registrieren. Beispiel:

    [dependencies]
    proxy-wasm = "0.2"
    log = "0.4"
    
  4. Wenn Sie eine dynamische Bibliothek erstellen möchten, wie sie für Plug-ins erforderlich ist, fügen Sie den Abschnitt lib hinzu. Beispiel:

    [lib]
    crate-type = ["cdylib"]
    
  5. Wenn Sie die Größe des kompilierten Plug-ins reduzieren möchten, fügen Sie den profile.release-Abschnitt hinzu. Beispiel:

    [profile.release]
    lto = true
    opt-level = 3
    codegen-units = 1
    panic = "abort"
    strip = "debuginfo"
    
  6. Fügen Sie Ihren Plug-in-Code der Datei lib.rs im Verzeichnis src hinzu.

    Der folgende Beispielquellcode ist ein Plug-in, das den Host der Anfrage neu schreibt und einen Antwortheader ausgibt:

    use log::info;
    use proxy_wasm::traits::*;
    use proxy_wasm::types::*;
    
    proxy_wasm::main! { {
        proxy_wasm::set_log_level(LogLevel::Trace);
        proxy_wasm::set_http_context(|_, _| -> Box<dyn HttpContext> { Box::new(MyHttpContext) });
    } }
    
    struct MyHttpContext;
    
    impl Context for MyHttpContext {}
    
    impl HttpContext for MyHttpContext {
        fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onRequestHeaders: hello from wasm");
    
            // Route extension example: host rewrite
            self.set_http_request_header(":authority", Some("service-extensions.com"));
            self.set_http_request_header(":path", Some("/"));
            return Action::Continue;
        }
    
        fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onResponseHeaders: hello from wasm");
    
            // Traffic extension example: add response header
            self.add_http_response_header("hello", "service-extensions");
            return Action::Continue;
        }
    }

    Die Methode on_http_request_headers ist ein Callback, der von Service Extensions aufgerufen wird.

Plug-in kompilieren

C++

Führen Sie zum Kompilieren des Plug-ins den folgenden Befehl im Verzeichnis aus, in dem sich die Makefile- und C++-Plug-in-Quelldateien befinden:

docker run -v $PWD:/work -w /work wasmsdk:v3 /build_wasm.sh myproject.wasm

Mit diesem Befehl wird das aktuelle Verzeichnis dem Verzeichnis work im Docker-Image zugeordnet. Anschließend wird das vom Docker-Image bereitgestellte Skript build_wasm.sh ausgeführt, um den Plug-in-Code zu erstellen. Wenn der Kompilierungsvorgang erfolgreich abgeschlossen wurde, wird im aktuellen Verzeichnis eine myproject.wasm-Datei mit dem kompilierten Wasm-Bytecode erstellt.

Wenn der Plug-in-Code zum ersten Mal mit dem Docker-Image kompiliert wird, generiert Emscripten die Standardbibliotheken. Wenn Sie diese im Docker-Image zwischenspeichern möchten, damit sie nicht jedes Mal neu generiert werden müssen, committen Sie das Image mit den Standardbibliotheken nach der ersten erfolgreichen Kompilierung:

docker commit `docker ps -l | grep wasmsdk:v3 | awk '{print $1}'` wasmsdk:v3

Weitere Informationen zum Erstellen von C++-Plug-ins finden Sie in der Proxy-Wasm C++ SDK-Dokumentation.

Go

Führen Sie den Befehl go build aus, um den Plug-in-Code zu kompilieren:

env GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm main.go

Bei einer erfolgreichen Kompilierung wird im aktuellen Verzeichnis eine main.wasm-Datei erstellt.

Rust

Führen Sie den Befehl cargo build aus, um den Plug-in-Code zu kompilieren:

cargo build --release --target wasm32-wasip1

Wenn der Build erfolgreich abgeschlossen wurde, wird die Meldung Finished release [optimized] target(s) angezeigt. Wenn Sie sich mit Envoy auskennen, können Sie das Plug-in in Envoy laden und sein Verhalten überprüfen.

Kompilierten Plug-in-Code in Artifact Registry hochladen

Laden Sie den kompilierten Plug-in-Code in ein Artifact Registry-Repository hoch, damit Google Cloud -Dienste darauf zugreifen können.

Wenn Sie Service Extensions mit einem globalen Load Balancer verwenden, verwenden Sie ein Repository an einem multiregionalen us-Standort. Wenn Sie einen regionalen Load Balancer verwenden, verwenden Sie ein Repository in derselben Region oder an einem multiregionalen Standort auf demselben Kontinent.

Wenn Sie ein Plug-in an einen globalen Load-Balancer anhängen, kopiert Service Extensions das Wasm-Modul aus dem Artifact Registry-Repository in den eigenen Speicher an Standorten auf der ganzen Welt. Der Speicherort des Repositorys hat also keinen Einfluss auf die Latenz der Anfragen, die an den Load-Balancer gesendet werden. Bei regionalen Load-Balancern wird das Plug-in an Speicherorte in derselben Region kopiert, in der sich der Load-Balancer befindet.

Service Extensions-Plug-ins können in generische oder Docker-Repositories von Artifact Registry hochgeladen werden.

Wenn Sie Standalone-Binärdateien direkter verwalten möchten, empfehlen wir, ein generisches Repository zum Speichern Ihrer Wasm-Dateien zu verwenden. Diese Option befindet sich im Vorschaumodus.

Generisches Repository

  1. Erstellen Sie ein lokales package/-Verzeichnis und kopieren Sie Ihr veröffentlichungsfähiges Plug-in-Modul hinein. Das Plug-in-Artefakt muss den Namen plugin.wasm haben. Mit dem folgenden Beispielbefehl wird das von Rust erstellte Plug-in-Artefakt kopiert:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  2. Artifact Registry-Repository erstellen, wobei --repository-format auf generic festgelegt ist.

  3. Prüfen Sie, ob Sie die erforderlichen Berechtigungen für das Repository haben.

  4. Verwenden Sie den Befehl gcloud artifacts generic upload, um Ihr Wasm-Modul als generisches Artefakt in Ihr Repository hochzuladen.

    gcloud artifacts generic upload \
        --project=PROJECT_ID \
        --location=LOCATION \
        --repository=REPOSITORY \
        --source=package/plugin.wasm \
        --package=PACKAGE \
        --version=VERSION
    

    Ersetzen Sie Folgendes:

    • PROJECT_ID: Ihre Projekt-ID Google Cloud
    • LOCATION: der regionale oder multiregionale Speicherort für das Repository
    • REPOSITORY: der Name des Repositorys, in das Sie das Wasm-Modul hochladen möchten
    • PACKAGE: der Paketname der Datei
    • VERSION: die Version des Wasm-Moduls

    Notieren Sie sich nach Abschluss des Uploads den Namen des generischen Artefakts, wie er mit dem Label name angegeben ist, z. B. add_header_plugin:v4 im folgenden Beispiel. Geben Sie diesen Namen an, wenn Sie ein Plug-in erstellen oder eine Plug-in-Version erstellen.

    Uploading file: plugin.wasm...done.
    '@type': type.googleapis.com/google.devtools.artifactregistry.v1.GenericArtifact
    createTime: '2025-06-16T11:02:25.080248Z'
    name: projects/my-project/locations/us/repositories/my-generic-repo/genericArtifacts/add_header_plugin:v4
    updateTime: '2025-06-16T11:02:25.080248Z'
    version: v4
    
  5. Führen Sie den gcloud artifacts files list-Befehl aus, um zu prüfen, ob das Artefakt erfolgreich in Artifact Registry hochgeladen wurde, und prüfen Sie, ob die Liste eine Datei mit dem Namen PACKAGE:VERSION:plugin.wasm enthält.

     gcloud artifacts files list \
         --project=PROJECT_ID \
         --location=LOCATION \
         --repository=REPOSITORY
    

Docker-Repository

  1. Artifact Registry-Repository erstellen, wobei --repository-format auf docker festgelegt ist.

  2. Prüfen Sie, ob Sie die erforderlichen Berechtigungen für das Repository haben.

  3. Erstellen Sie ein lokales package/-Verzeichnis und kopieren Sie Ihr veröffentlichbares Plug-in-Artefakt dorthin. Im folgenden Beispiel wird das vom Rust-Build erstellte Plug-in-Artefakt kopiert:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  4. Erstellen Sie eine package/Dockerfile-Datei mit folgendem Inhalt:

    FROM scratch
    COPY plugin.wasm plugin.wasm
    
  5. Packen Sie den Plug-in-Code mit Cloud Build oder Docker.

    Cloud Build

    1. Erstellen Sie eine package/cloudbuild.yaml-Datei mit der folgenden Build-Konfiguration:

      steps:
        - name: 'gcr.io/cloud-builders/docker'
          args: [ 'build', '--no-cache', '--platform', 'wasm',
                '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG', '.' ]
      images: [ 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG' ]
      

      Der Pfad, unter dem Sie das Plug-in speichern, muss das folgende Format haben:

      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      Ersetzen Sie Folgendes:

      • LOCATION: der regionale oder multiregionale Standort des Repositorys
      • PROJECT_ID: Ihre Projekt-ID in der Console von Google Cloud
      • REPOSITORY: der Name des Repositorys, in dem Sie das Image speichern möchten
      • IMAGE: der Name des Container-Images im Repository, z. B. us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin
      • IMAGE_TAG: das Image-Tag, das dem Container zugewiesen werden soll, z. B. production
    2. Lösen Sie den Vorgang aus, um den Plug-in-Container zu erstellen und in Artifact Registry hochzuladen:

      gcloud builds submit --config package/cloudbuild.yaml package/
      

    Docker

    1. Installieren Sie Docker, falls es noch nicht installiert ist. Docker ist in Cloud Shell, der Google Cloud interaktiven Shell-Umgebung, enthalten.

    2. Docker für die Authentifizierung bei Artifact Registry konfigurieren Beispiel:

      gcloud auth login
      gcloud auth configure-docker LOCATION-docker.pkg.dev
      gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://LOCATION-docker.pkg.dev
      
    3. Erstellen Sie das Container-Image:

      docker build --no-cache --platform wasm -t my-wasm-plugin package/
      
    4. Verwenden Sie Image-Tags, um das lokale Image mit dem Repository-Image-Namen zu taggen:

      docker tag my-wasm-plugin LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      Ersetzen Sie Folgendes:

      • LOCATION: der regionale oder multiregionale Standort des Repositorys
      • PROJECT_ID: Ihre Projekt-ID in der Console von Google Cloud
      • REPOSITORY: der Name des Repository, in dem Sie das Image speichern möchten
      • IMAGE: Der Name des Container-Images im Repository, z. B. us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin.
      • IMAGE_TAG: das Image-Tag, das dem Container zugewiesen werden soll, z. B. production
    5. Laden Sie Ihr getaggtes Container-Image in Artifact Registry hoch.

      docker push LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      
  6. Führen Sie den gcloud artifacts docker images list-Befehl aus, um zu prüfen, ob das Image erfolgreich in Artifact Registry hochgeladen wurde.

    gcloud artifacts docker images list LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \
        --include-tags
    

Konfigurationsdatei vorbereiten und hochladen

Plug-ins können optional Konfigurationsdaten empfangen, die sich zur Laufzeit auf das Verhalten des Plug-ins auswirken können. Konfigurationsdaten können Text oder Binärdaten sein und in einem beliebigen Format vorliegen, das vom Plug-in akzeptiert wird. Wenn die Konfigurationsdaten groß sind, müssen Sie die Konfigurationsdatei möglicherweise in Artifact Registry hochladen.

Plug-in-Code zum Lesen von Konfigurationsdaten schreiben

C++

Konfigurationsdaten werden an die onConfigure-Methode des Stammkontextobjekts übergeben, das einmal beim Start des Plug-ins instanziiert wird und für die gesamte Lebensdauer der Wasm-Laufzeit, in der das Plug-in gehostet wird, aktiv bleibt. Das Stammkontextobjekt ist eine Instanz der Klasse RootContext oder einer Unterklasse von RootContext.

Mit dem Wert RegisterContextFactory kann im Plug-in-Code festgelegt werden, welche Klasse für den Stammkontext verwendet wird. Im folgenden Plug-in-Code werden beispielsweise MyRootContext und MyHttpContext als die Klassen registriert, die für Stamm- und Stream-Kontextinstanzen verwendet werden sollen. Anschließend wird ein Secret-Wert aus den Plug-in-Konfigurationsdaten gelesen, auf die Streamkontextinstanzen über das Stammkontextobjekt zugreifen können.

#include <string>
#include <string_view>

#include "proxy_wasm_intrinsics.h"

class MyRootContext : public RootContext {
 public:
  explicit MyRootContext(uint32_t id, std::string_view root_id)
      : RootContext(id, root_id) {}

  bool onConfigure(size_t config_len) override {
    auto buffer = getBufferBytes(WasmBufferType::PluginConfiguration, 0, config_len);
    if (!buffer) {
      LOG_ERROR("Failed to retrieve plugin configuration");
      return false;
    }
    secret_ = buffer->toString();
    return true;
  }

  const std::string& secret() const { return secret_; }

 private:
  std::string secret_;
};

class MyHttpContext : public Context {
 public:
  explicit MyHttpContext(uint32_t id, RootContext* root)
      : Context(id, root),
        secret_(static_cast<MyRootContext*>(root)->secret()) {}

  FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                       bool end_of_stream) override {
    // Use secret here...
    LOG_INFO("secret: " + secret_);
    return FilterHeadersStatus::Continue;
  }

 private:
  const std::string& secret_;
};

static RegisterContextFactory register_MyHttpContext(
    CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(MyRootContext));

Go

Konfigurationsdaten werden beim Ausführen von OnPluginStart gelesen, einem Methodenempfänger, der von der Laufzeit einmal beim Start des Plug-ins für die PluginContext-Struktur ausgeführt wird. Die Konfigurationsdaten ändern sich während der Lebensdauer der Wasm-Laufzeit, die das Plug-in hostet, nicht. PluginContext ist nützlich, um Initialisierungslogik auszuführen und den Status über viele Anfragen hinweg beizubehalten.

Mit dem Plug-in-Code kann gesteuert werden, welcher Kontext für PluginContext verwendet wird. Dazu wird die Methode NewPluginContext für VMContext implementiert, wodurch PluginContext instanziiert wird. PluginContext instanziiert dann HttpContext-Kontexte.

Mit dem folgenden Plug-in-Code wird beispielsweise VMContext registriert, wodurch PluginContext instanziiert wird. Dieser Kontext ist für das Lesen von Konfigurationsdaten und das Instanziieren von HttpContext-Kontexten nach Bedarf zuständig. PluginContext liest einen geheimen Wert aus den Konfigurationsdaten des Plug-ins, speichert ihn im PluginContext-Kontext und übergibt ihn an HttpContext in NewHttpContext.

package main

import (
	"fmt"

	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
)

func main() {}
func init() {
	proxywasm.SetVMContext(&vmContext{})
}

type vmContext struct {
	types.DefaultVMContext
}

type pluginContext struct {
	types.DefaultPluginContext
	secret string
}

type httpContext struct {
	types.DefaultHttpContext
	pluginContext *pluginContext
}

func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
	return &pluginContext{}
}

func (ctx *pluginContext) OnPluginStart(int) types.OnPluginStartStatus {
	config, err := proxywasm.GetPluginConfiguration()
	if err != nil {
		proxywasm.LogErrorf("Error reading the configuration: %v", err)
		return types.OnPluginStartStatusFailed
	}
	if config == nil {
		proxywasm.LogError("Configuration is nil")
		return types.OnPluginStartStatusFailed
	}
	ctx.secret = string(config)
	return types.OnPluginStartStatusOK
}

func (ctx *pluginContext) NewHttpContext(uint32) types.HttpContext {
	return &httpContext{pluginContext: ctx}
}

func (ctx *pluginContext) Secret() string {
	return ctx.secret
}

func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
	defer func() {
		err := recover()
		if err != nil {
			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
		}
	}()
	// Use secret here...
	proxywasm.LogInfof("secret: %v", ctx.pluginContext.Secret())
	return types.ActionContinue
}

Rust

Konfigurationsdaten werden aus einem RootContext-Trait gelesen, das einmal beim Start des Plug-ins instanziiert wird und für die Lebensdauer der Wasm-Laufzeit, in der das Plug-in gehostet wird, aktiv bleibt. RootContext-Traits sind nützlich, um Vorgänge auszuführen oder den Status über viele Anfragen hinweg beizubehalten.

Der Plug-in-Code kann über die Methode set_root_context steuern, welche Klasse für den Stammkontext verwendet wird. Der Stammkontext instanziiert Streamkontexte. Mit dem folgenden Plug-in-Code wird beispielsweise MyRootContext registriert, wodurch MyHttpContext nach Bedarf instanziiert wird. Der Stammkontext liest einen Secret-Wert aus den Plug-in-Konfigurationsdaten und übergibt ihn an Streamkontexte.

use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use std::rc::Rc;

proxy_wasm::main! { {
    proxy_wasm::set_log_level(LogLevel::Trace);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(MyRootContext { secret: Rc::new("missing".to_string()) })
    });
} }

struct MyRootContext {
    secret: Rc<String>,
}

impl Context for MyRootContext {}

impl RootContext for MyRootContext {
    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.secret = Rc::new(String::from_utf8(config_bytes).unwrap())
        }
        true
    }

    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(MyHttpContext {
            secret: self.secret.clone(), // shallow copy, ref count only
        }))
    }

    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}

struct MyHttpContext {
    secret: Rc<String>,
}

impl Context for MyHttpContext {}

impl HttpContext for MyHttpContext {
    fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        // Use secret here...
        info!("secret: {}", self.secret);
        Action::Continue
    }
}

Konfigurationsdatei hochladen

Wenn die Größe der Daten, die an Ihr Plug-in in on_configure übermittelt werden sollen, 900 KiB überschreitet, laden Sie sie in Artifact Registry hoch. Folgen Sie dazu der Methode, die unter Kompilierten Plug-in-Code in Artifact Registry hochladen beschrieben ist. Speichern Sie die Konfigurationsdatei in diesem Fall unter dem Namen plugin.config (und nicht plugin.wasm).

Im nächsten Schritt erstellen Sie ein Plug-in.

Beim Erstellen des Plug-ins müssen Sie den URI zum hochgeladenen Wasm-Modul oder -Image angeben.

Neue Version des Plug‑in-Codes erstellen

Wenn Sie eine neue Version des Plug-in-Codes erstellen möchten, bearbeiten Sie die Plug-in-Datei. Kompilieren Sie dann, wie in den vorherigen Abschnitten beschrieben, den Plug‑in-Code, packen Sie ihn neu und laden Sie ihn in Artifact Registry hoch.

Callbacks

Der Code, den Sie in Wasm kompilieren, kann beliebige Methoden oder Funktionen definieren, aber einige davon haben eine besondere Bedeutung. Dies sind die Methoden, die im Proxy-Wasm SDK für die Sprache Ihrer Wahl definiert sind und den Spezifikationen der Proxy-Wasm Application Binary Interface (ABI) entsprechen. Service Extensions ruft diese Callbacks als Reaktion auf Nutzeranfragen oder auf Ereignisse im Plugin-Lebenszyklus auf.

Diese Callbacks sind in der folgenden Tabelle in der Reihenfolge aufgeführt, in der sie normalerweise aufgerufen werden:

Callback-Name und ‑Beschreibung C++-Methodenname Go-Methodenname Rust-Methodenname
START_PLUGIN: Wird aufgerufen, wenn ein Plug-in gestartet wird. RootContext::onStart VMContext.OnVmStart RootContext::on_vm_start
CONFIGURE_PLUGIN: Wird nach dem Start eines Plug-ins aufgerufen, um dem Plug-in Konfigurationsdaten bereitzustellen. RootContext::onConfigure PluginContext.OnPluginStart RootContext::on_configure
CREATE_CONTEXT: Wird aufgerufen, wenn ein neuer Streamkontext erstellt wird. Jeder Stream entspricht einer HTTP-Clientanfrage. Context::onCreate PluginContext.NewHttpContext RootContext::create_http_context
HTTP_REQUEST_HEADERS: Wird aufgerufen, um HTTP-Anfrageheader zu verarbeiten. Context::onRequestHeaders HttpContext.OnHttpRequestHeaders HttpContext::on_http_request_headers
HTTP_REQUEST_BODY: Wird wiederholt aufgerufen, um HTTP-Anfragetextkörper-Chunks zu verarbeiten. Context::onRequestBody HttpContext.OnHttpRequestBody HttpContext::on_http_request_body
HTTP_RESPONSE_HEADERS: Wird aufgerufen, um HTTP-Antwortheader zu verarbeiten. Context::onResponseHeaders HttpContext.OnHttpResponseHeaders HttpContext::on_http_response_headers
HTTP_RESPONSE_BODY: Wird wiederholt aufgerufen, um HTTP-Antworttextblöcke zu verarbeiten. Context::onResponseBody HttpContext.OnHttpResponseBody HttpContext::on_http_response_body
DONE: Wird aufgerufen, wenn die Verarbeitung eines Plug-ins abgeschlossen ist. Context::onDone HttpContext.OnHttpStreamDone Context::on_done
DELETE: Wird aufgerufen, wenn das Streamkontextobjekt, das einer HTTP-Anfrage des Clients entspricht, gelöscht wird. Context::onDelete (kein Rückruf) (kein Callback)

Nächste Schritte