Service Mesh (ASM), özel istek işleme amacıyla Envoy sunucularında Wasm eklentilerini destekler. Bu öğretici, HTTP istek başlıklarını inceleyen ve sonuca göre isteklere izin veren ya da bunları engelleyen bir Wasm eklentisinin Rust dilinde nasıl yazılacağını adım adım açıklar.
Eklenti, gelen bir isteğin allow: true başlığını içerip içermediğini kontrol eder. Başlık eksikse veya başka bir değere ayarlanmışsa eklenti, özel bir hata mesajıyla birlikte HTTP 403 durumu döndürür. Başlık mevcut ve true olarak ayarlanmışsa istek upstream hizmetine iletilir.
Nasıl çalışır
Wasm eklentisi, Envoy sunucusu içinde yalıtılmış bir modül olarak çalışır. Proxy-Wasm belirtimi, sunucu ana makinesi ile Wasm modülleri arasındaki iletişim için standart bir Application Binary Interface (ABI) tanımlar. Proxy-Wasm sunucudan bağımsız olduğundan bu ABI'ye göre oluşturulan eklentiler, belirtimi uygulayan herhangi bir sunucuda taşınabilir.
Proxy-Wasm Rust SDK'sı, eklenti mantığını üç trait türü etrafında düzenler:
| Trait | Rolü |
|---|---|
RootContext |
Eklentinin yaşam döngüsünü ve yapılandırmasını yönetir. Her istek için yeni HTTP veya akış bağlamları oluşturur. |
HttpContext |
Tek bir HTTP istek/yanıt döngüsünü işler. Trafiği incelemek veya değiştirmek için on_http_request_headers gibi geri aramaları uygulayın. |
Context |
Hem kök hem de HTTP bağlamlarının devraldığı paylaşılan yardımcı işlevleri (özellik erişimi, zamanlayıcılar vb.) sağlar. |
Envoy bir HTTP isteği aldığında RootContext aracılığıyla yeni bir HttpContext örneği oluşturur. HttpContext geri aramaları, istek işlemenin her aşamasında tetiklenerek eklentinin başlıklar, gövde ve altbilgiler üzerinde tam kontrol sahibi olmasını sağlar.
Arka plan bilgileri
Wasm, neredeyse yerel düzeyde yürütme performansı sunar ve bellek açısından güvenli bir yalıtılmış alanda çalışır; bu durum, sunucu ikili dosyasını yeniden derlemeye gerek kalmadan Envoy'u genişletmek için uygun hale getirir. Ancak, yerleşik çöp toplama özelliğine sahip diller Wasm ortamında performans ek yüküne neden olabilir. Bu nedenle manuel bellek yönetimi sunan C++ ve Rust dilleri önerilir.
Rust, C++ ile karşılaştırıldığında daha basit bir derleme ve oluşturma iş akışı sunar ancak öğrenme eğrisi daha dik olabilir. Seçiminizi ekibinizin ilgili dillere olan aşinalığına göre yapın.
Ön koşullar
Başlamadan önce aşağıdaki ön koşulları sağladığınızdan emin olun:
Sürüm %1,18 veya sonraki bir ASM örneğine eklenmiş bir küme. Daha fazla bilgi için bkz. ASM örneğine küme ekleme
Etkinleştirilmiş sidecar injection. Daha fazla bilgi için bkz. Sidecar injection ilkesini yapılandırma
Oluşturulmuş bir ingress gateway. Daha fazla bilgi için bkz. Ingress gateway oluşturma
Dağıtılmış ve erişilebilir HTTPBin uygulaması. Daha fazla bilgi için bkz. HTTPBin uygulamasını dağıtma
Oluşturulmuş bir Container Registry Enterprise Edition örneği. Daha fazla bilgi için bkz. Container Registry Enterprise Edition örneği oluşturma
İş akışı genel bakış
Uçtan uca süreç beş adımdan oluşur:
Geliştirme ortamını hazırlayın: Rust araç zincirini ve Wasm derleme hedefini yükleyin.
Eklentiyi yazın: Bir Rust kitaplığı projesi oluşturun, bağımlılıkları tanımlayın ve istek başlığı inceleme mantığını uygulayın.
Derleyin ve paketleyin: Rust kodunu bir Wasm ikili dosyasına derleyin ve bunu bir OCI görüntüsü olarak paketleyin.
Dağıtın: Görüntüyü Container Registry'ye gönderin ve ASM'de Wasm eklentisi kaynağını uygulayın.
Doğrulayın: Eklentinin trafiği beklendiği şekilde engellediğini ve izin verdiğini onaylamak için test istekleri gönderin.
Adım 1: Geliştirme ortamını hazırlayın
Rust araç zincirini rustup üzerinden yükleyin. Talimatlar için bkz. Rust yükleme.
-
wasm32-wasiderleme hedefini ekleyin:wasm32-wasihedefi, Rust kodunu Envoy'un Wasm çalışma zamanının beklediği WASI sistem arayüzüne erişim sağlayan WebAssembly'e derler. Rust zaten yüklüyse önce güncelleyin:rustup target add wasm32-wasirustup update
Adım 2: Eklentiyi yazın
Bu adım üç bölümü kapsar: projeyi oluşturma, bağımlılıkları yapılandırma ve eklenti mantığını uygulama.
Projeyi oluşturun
rust-example adında bir dizin oluşturun, bu dizine geçin ve yeni bir Rust kitaplığı başlatın:
mkdir rust-example && cd rust-example
cargo init --lib
Bağımlılıkları yapılandırın
Cargo.toml dosyasının içeriğini aşağıdakilerle değiştirin:
[package]
name = "rust-example"
version = "0.1.0"
edition = "2021"
[lib]
# Build as a C-compatible dynamic library so Envoy can load it
crate-type = ["cdylib"]
[dependencies]
log = "0.4.8"
proxy-wasm = "0.2.2"
cdylib crate türü, Wasm çalışma zamanıyla uyumlu bir dinamik kitaplık üretir. İki bağımlılık şunlardır:
**
log**: Yapılandırılmış günlük çıkışı için standart Rust günlük kaydı arabirimi.**
proxy-wasm**: Trait tanımlamalarını ve ana makine işlevi bağlamalarını sağlayan Proxy-Wasm Rust SDK'sı.
Eklenti mantığını uygulayın
Eklentinin aşağıdaki görevleri yerine getirmesi gerekir:
Envoy'a bu eklentinin HTTP trafiğini işlediğini bildiren bir
RootContextkaydedin.Gelen her HTTP isteği için istek başlıklarını inceleyen bir
HttpContextoluşturun.on_http_request_headersgeri çağrısındaallow: truebaşlığını kontrol edin. Başlık eksikse isteği HTTP 403 ile engelleyin, mevcutsa geçmesine izin verin.
src/lib.rs dosyasının içeriğini aşağıdakilerle değiştirin:
use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
proxy_wasm::main! {{
proxy_wasm::set_log_level(LogLevel::Trace);
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HttpHeadersRoot) });
}}
struct HttpHeadersRoot;
// Inherit shared utility functions (property access, timers, etc.)
impl Context for HttpHeadersRoot {}
impl RootContext for HttpHeadersRoot {
fn get_type(&self) -> Option<ContextType> {
Some(ContextType::HttpContext)
}
fn create_http_context(&self, context_id: u32) -> Option<Box<dyn HttpContext>> {
Some(Box::new(HttpHeaders { context_id }))
}
}
struct HttpHeaders {
context_id: u32,
}
impl Context for HttpHeaders {}
impl HttpContext for HttpHeaders {
fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
info!("#{} wasm-rust: on_http_request_headers", self.context_id);
match self.get_http_request_header("allow") {
Some(allow) if allow == "true" => {
Action::Continue
}
_ => {
info!("#{} wasm-rust: allow header not found or is not true, deny by default", self.context_id);
self.send_http_response(
403,
vec![("Content-Type", "text/plain")],
Some(b"Forbidden by ASM Wasm Plugin, rust version\n"),
);
Action::Pause
}
}
}
}
Kodun dökümü aşağıdaki gibidir:
| Bölüm | Amacı |
|---|---|
proxy_wasm::main! |
Giriş noktası makrosu. Günlük düzeyini Trace olarak ayarlar ve HttpHeadersRoot öğesini kök bağlam olarak kaydeder. |
HttpHeadersRoot + RootContext |
Envoy'a bu eklentinin HTTP trafiğini işlediğini bildirmek için ContextType::HttpContext döndürür. Her istek için yeni bir HttpHeaders örneği oluşturur. |
HttpHeaders + HttpContext |
on_http_request_headers yöntemini uygular. allow başlığını okur: değer "true" ise Action::Continue döndürür, aksi takdirde bir HTTP 403 yanıtı gönderir ve isteği durdurmak için Action::Pause döndürür. |
Eklentiyi derleyin
Eklentiyi wasm32-wasi hedefiyle derleyin:
cargo build --target wasm32-wasi --release
Başarılı bir derlemeden sonra Wasm ikili dosyası şu konumda bulunur:
target/wasm32-wasi/release/rust_example.wasm
Adım 3: Bir OCI görüntüsü oluşturun ve Container Registry'ye gönderin
ASM'nin görüntüyü çekip yükleyebilmesi için Wasm ikili dosyasını bir OCI görüntüsü olarak paketleyin.
-
Proje kökünde bir
Dockerfileoluşturun:FROM scratch # Copy the compiled Wasm binary into the image as plugin.wasm ADD target/wasm32-wasi/release/rust_example.wasm ./plugin.wasm -
Görüntüyü derleyin ve gönderin. Ayrıntılı adımlar için bkz. Wasm eklentisinin OCI görüntüsünü oluşturma ve Container Registry Enterprise Edition örneğine gönderme.
<your-registry>ve<tag>yerine gerçek kayıt defteri adresinizi ve görüntü etiketinizi girin:docker build -t <your-registry>/wasm-rust-example:<tag> . docker push <your-registry>/wasm-rust-example:<tag>
Adım 4: Wasm eklentisini ingress gateway'e uygulayın
Eklentiyi ingress gateway'in Envoy sunucusuna yüklemek için ASM'de WasmPlugin kaynağını yapılandırın.
Tam prosedür için bkz. Wasm eklentisini ingress gateway'e uygulama. url alanının 3. Adımda gönderdiğiniz görüntüyü işaret ettiğinden emin olun.
Adım 5: Eklentiyi doğrulayın
Eklentiyi dağıttıktan sonra allow: true başlığı içeren ve içermeyen istekler göndererek testi gerçekleştirin.
Hata ayıklama günlüğünü etkinleştirin
Gateway Pod'unda Wasm hata ayıklama günlüklerini etkinleştirmek için veri düzlemi kümesinin kubeconfig dosyasını kullanın:
kubectl -n istio-system exec <gateway-pod-name> -c istio-proxy -- \
curl -XPOST "localhost:15000/logging?wasm=debug"
<gateway-pod-name> yerine gateway Pod'unuzun gerçek adını girin.
Allow başlığı olmadan test edin
allow başlığı olmadan bir istek gönderin:
curl <ASM-gateway-IP>/status/418
Beklenen çıktı:
Forbidden by ASM Wasm Plugin, rust version
Eklenti isteği engeller ve HTTP 403 döndürür.
Gateway günlüklerini kontrol edin
Aşağıdakine benzer girişler için gateway Pod günlüklerini inceleyin:
2024-09-05T08:33:31.079869Z info envoy wasm wasm log istio-system.header-authorization: #2 wasm-rust: on_http_request_headers
2024-09-05T08:33:31.079943Z info envoy wasm wasm log istio-system.header-authorization: #2 wasm-rust: allow header not found or is not true, deny by default
{"authority_for":"xx.xx.xx.xx","bytes_received":"0","bytes_sent":"43","downstream_local_address":"xx.xx.xx.xx:80","downstream_remote_address":"xx.xx.xx.xx:xxxxx","duration":"0","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"d5250d1a-54b3-406d-8bea-5a51b617b579","requested_server_name":"-","response_code":"403","response_flags":"-","route_name":"httpbin","start_time":"2024-09-05T08:33:31.079Z","trace_id":"-","upstream_cluster":"outbound|8000||httpbin.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_response_time":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"curl/8.9.0-DEV","x_forwarded_for":"xx.xx.xx.xx"}
Bu günlük satırları, eklentinin yürütüldüğünü ve isteği reddettiğini doğrular.
Allow başlığı ile test edin
allow: true içeren bir istek gönderin:
curl <ASM-gateway-IP>/status/418 -H "allow: true"
Beklenen çıktı:
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
İstek, standart HTTP 418 çaydanlık yanıtını döndüren HTTPBin'e iletilir. Eklenti doğru şekilde çalışmaktadır.
Sonraki adımlar
Go diliyle bir Wasm eklentisi yazmak için bu öğreticinin Go sürümüne bakın.
HTTP yanıt gövdesi değişikliği, yapılandırma yükleme ve gRPC kimlik doğrulama dahil olmak üzere proxy-wasm Rust SDK deposundaki diğer eklenti örneklerini keşfedin.