All Products
Search
Document Center

Alibaba Cloud Service Mesh:Buat plug-in Wasm dalam Go untuk proxy Envoy

Last Updated:Mar 12, 2026

Service Mesh (ASM) mendukung spesifikasi WebAssembly for Proxies, yang memungkinkan Anda memperluas perilaku proxy Envoy dengan plug-in portabel yang dikompilasi ke WebAssembly (Wasm). Plug-in ini dapat berjalan di berbagai server proxy, dieksekusi dalam sandbox yang aman secara memori dengan kecepatan mendekati native, serta dapat diperbarui tanpa perlu me-restart proxy.

Topik ini menjelaskan langkah-langkah untuk membuat plug-in Wasm berbasis Go yang menerapkan otorisasi berbasis header, mengemasnya sebagai image Open Container Initiative (OCI), dan men-deploy-nya ke gerbang masuk ASM.

Cara kerja plug-in Wasm di Envoy

Plug-in Wasm dieksekusi di dalam lingkungan sandbox dengan API terdefinisi dengan baik untuk berkomunikasi dengan host proxy. Arsitektur ini memberikan beberapa manfaat:

ManfaatDeskripsi
Hot-reloadablePerbarui plug-in tanpa me-restart proxy Envoy, sehingga traffic tetap mengalir
Fault-isolatedKeruntuhan plug-in tidak menyebabkan proxy Envoy down
SecureSandbox membatasi kemampuan plug-in hanya pada permukaan API yang terdefinisi dengan baik
PolyglotTulis plug-in dalam C++, Go, dan Rust

Untuk detail lebih lanjut, lihat WebAssembly in Envoy, dan ikhtisar proxy-wasm-go-sdk.

Alur kerja end-to-end

Plug-in yang Anda buat dalam tutorial ini memeriksa apakah permintaan masuk berisi header allow: true. Permintaan tanpa header ini akan menerima tanggapan 403 Forbidden, sedangkan permintaan dengan header tersebut diteruskan ke layanan backend.

  1. Tulis logika plug-in dalam Go menggunakan proxy-wasm-go-sdk.

  2. Kompilasi kode Go menjadi binary Wasm dengan TinyGo.

  3. Kemas binary tersebut sebagai image OCI dan dorong ke Container Registry Enterprise Edition.

  4. Buat resource WasmPlugin di ASM untuk menerapkan plug-in ke proxy Envoy.

Prasyarat

Sebelum memulai, pastikan Anda telah memiliki:

Langkah 1: Siapkan lingkungan pengembangan

Instal tool berikut di mesin lokal Anda:

ToolTujuanReferensi
GoKompilator dan rantai alat Gogo.dev
DockerBangun dan dorong image OCIdocker.com
TinyGoKompilasi Go ke Wasm (kompilator Go standar tidak mendukung output Wasm)Panduan instalasi TinyGo

Plug-in ini bergantung pada proxy-wasm-go-sdk, yang menyediakan API SDK Go lengkap beserta contoh tambahan.

Langkah 2: Tulis kode plug-in

  1. Buat direktori proyek dan tambahkan file main.go dengan konten berikut:

    Tampilkan file 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{})
    }
    
    // vmContext mengimplementasikan types.VMContext.
    // Embedding DefaultVMContext menyediakan implementasi default untuk semua metode.
    type vmContext struct {
    	types.DefaultVMContext
    }
    
    // NewPluginContext membuat konteks plug-in baru untuk setiap Wasm VM.
    func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
    	return &pluginContext{}
    }
    
    // pluginContext mengimplementasikan types.PluginContext.
    type pluginContext struct {
    	types.DefaultPluginContext
    }
    
    func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus {
    	return types.OnPluginStartStatusOK
    }
    
    // NewHttpContext membuat konteks HTTP untuk setiap permintaan.
    func (ctx *pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
    	return &HeaderAuthorizationHandler{}
    }
    
    // HeaderAuthorizationHandler memeriksa header "allow" pada setiap permintaan.
    type HeaderAuthorizationHandler struct {
    	types.DefaultHttpContext
    }
    
    // OnHttpRequestHeaders memeriksa header permintaan.
    // Jika header "allow" tidak ada atau nilainya bukan "true", permintaan ditolak dengan kode 403.
    func (ctx *HeaderAuthorizationHandler) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
    	const AuthorizationKey = "allow"
    	value, err := proxywasm.GetHttpRequestHeader(AuthorizationKey)
    	if err != nil || value != "true" {
    		proxywasm.LogDebugf("request header: 'allow' adalah %v, hanya true yang dapat diteruskan", value)
    		return ctx.DenyRequest()
    	}
    	return types.ActionContinue
    }
    
    // DenyRequest mengirim tanggapan 403 dan menghentikan pemrosesan lebih lanjut.
    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. Inisialisasi modul Go dan unduh dependensi:

    go mod init
    go mod tidy
  3. Kompilasi kode menjadi binary Wasm. Perintah ini menghasilkan file plugin.wasm di direktori saat ini.

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

Langkah 3: Kemas dan dorong image OCI

  1. Di direktori proyek yang sama, buat Dockerfile:

    FROM scratch
    ADD ./plugin.wasm ./plugin.wasm
  2. Bangun image:

    docker build -t header-authorization:v0.0.1 .
  3. Buat repository image di Container Registry Enterprise Edition. Untuk langkah-langkah detail, lihat sublangkah 2.a dan 2.b Langkah 1 dalam Gunakan plug-in Wasm Coraza untuk menerapkan kemampuan WAF pada gerbang ASM. Dalam contoh ini, namespace adalah test-oci dan nama repository adalah header-authorization.

    image

  4. Beri tag dan dorong image ke instans Container Registry Enterprise Edition Anda. Ikuti instruksi Push image to the registry yang ditampilkan di halaman detail repository.

Langkah 4: Terapkan plug-in Wasm ke gerbang masuk

  1. Buat Secret untuk menarik image. Untuk latar belakangnya, lihat Langkah 2: Konfigurasikan izin untuk menarik image. Ganti placeholder berikut dengan nilai aktual Anda:

    PlaceholderDeskripsi
    <your-registry-domain>Nama domain instans Container Registry Enterprise Edition
    <your-username>Username registri
    <your-password>Password registri
    kubectl create secret docker-registry -n istio-system wasm-secret \
      --docker-server=<your-registry-domain> \
      --docker-username=<your-username> \
      --docker-password=<your-password>
  2. Buat file bernama asm-plugin.yaml dengan konten berikut. Ganti <your-registry-domain> dengan nama domain instans Container Registry Enterprise Edition Anda.

    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://<your-registry-domain>/test-oci/header-authorization:v0.0.1
      phase: AUTHN
  3. Sambungkan ke instans ASM menggunakan file kubeconfig-nya dan terapkan resource tersebut:

    kubectl apply -f asm-plugin.yaml

Langkah 5: Verifikasi plug-in

  1. Aktifkan logging debug untuk plug-in Wasm pada gerbang masuk. Gunakan file kubeconfig kluster data-plane tempat gerbang masuk berjalan. Ganti <ingress-gateway-pod> dengan nama Pod yang menjalankan gerbang masuk.

    kubectl -n istio-system exec <ingress-gateway-pod> -c istio-proxy -- \
      curl -XPOST "localhost:15000/logging?wasm=debug"
  2. Kirim permintaan tanpa header allow. Output yang diharapkan:

    curl <ingress-gateway-ip>/status/418
    Forbidden by ASM Wasm Plugin
  3. Periksa log Pod gerbang masuk. Entri log ini mengonfirmasi bahwa plug-in memblokir permintaan:

    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' adalah , hanya true yang dapat diteruskan	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. Kirim permintaan dengan header allow: true. Output yang diharapkan: Tanggapan teapot mengonfirmasi bahwa aplikasi HTTPBin dapat diakses dan plug-in berfungsi dengan benar.

    curl <ingress-gateway-ip>/status/418 -H "allow: true"
       -=[ teapot ]=-
    
              _...._
            .'  _ _ `.
           | ."` ^ `". _,
           \_;`"---"`|//
             |       ;/
             \_     _/
               `"""`

Perbaiki kebocoran memori TinyGo dengan nottinygc

Plug-in Wasm yang dikompilasi dengan TinyGo mungkin mengalami kebocoran memori. Komunitas proxy-wasm-go-sdk merekomendasikan penggunaan nottinygc sebagai garbage collector kustom untuk mengatasi masalah ini.

  1. Tambahkan import berikut di bagian atas file main.go. Jika dependensi ini belum tersedia, jalankan go mod tidy untuk mengunduhnya.

    import _ "github.com/wasilibs/nottinygc"
  2. Bangun ulang binary Wasm dengan flag GC kustom. Flag -gc=custom menggantikan garbage collector default TinyGo dengan nottinygc, dan -tags='custommalloc nottinygc_envoy' mengaktifkan allocator yang dioptimalkan untuk Envoy.

    tinygo build -o plugin.wasm -gc=custom -tags='custommalloc nottinygc_envoy' \
      -target=wasi -scheduler=none main.go
  3. Bangun ulang image OCI dan dorong versi yang diperbarui ke Container Registry Enterprise Edition, lalu terapkan ulang resource WasmPlugin untuk menerapkan perbaikan tersebut.