Giriş
CLI araçlarını farklı işletim sistemlerine dağıtmak çoğu zaman zahmetlidir. Her platform için ayrı derlemeler, paylaşımlı kütüphane bağımlılıkları ve güvenlik kısıtları bir araya gelince, iş büyür. WebAssembly (WASM) ve WASI (WebAssembly System Interface), bu sorunu modern ve güvenli bir yaklaşımla çözüyor. WASI sayesinde uygulamanızı tek bir .wasm dosyası olarak paketleyip, Wasmtime gibi bir çalışma zamanı üzerinde Linux, macOS ve Windows’ta aynı şekilde çalıştırabilirsiniz. Bu öğreticide, Rust ile küçük bir CLI aracını WASI için derleyip Wasmtime ile çalıştırmayı ve pratik ipuçlarını paylaşacağım.
WASM ve WASI Nedir?
WASM, sandbox edilmiş bir bytecode formatıdır; bir kez derlediğiniz kodu farklı ortamlarda güvenle koşturmanıza olanak tanır. WASI ise dosya sistemi, çevre değişkenleri, saat ve benzeri sistem kaynaklarına erişim için standart bir arayüz sunar. En kritik avantajı, yetenek tabanlı (capability-based) güvenlik modelidir: Uygulama dosya sistemine, ağ veya diğer kaynaklara varsayılan olarak erişemez; hangi izinleri verdiyseniz yalnızca onlarla çalışır.
Gereksinimler
- Rust ve cargo (rustup ile kurulabilir)
- Wasmtime çalışma zamanı (brew install wasmtime ya da choco install wasmtime)
- Rust için WASI hedefi: rustup target add wasm32-wasi
Adım Adım: Rust CLI’yi WASI için Derlemek
1) Yeni bir proje oluşturun: cargo new hello-wasi komutundan sonra dizine girin.
2) src/main.rs içine basit bir örnek koyun. Argümanları yazdıran ve bir dosyayı okuyan minimal bir gövde şöyle olabilir: fn main() { let args: Vec<String> = std::env::args().collect(); eprintln!("Argümanlar: {:?}", args); let path = std::env::var("INPUT").unwrap_or("input.txt".into()); let data = std::fs::read_to_string(path).unwrap_or_default(); println!("{}", data); }
3) WASI hedefi için derleyin: cargo build --release --target wasm32-wasi. Üretilen dosya: target/wasm32-wasi/release/hello-wasi.wasm
Wasmtime ile Çalıştırma
WASI, dosya sistemi erişimine varsayılan izin vermez. Çalıştırırken hangi dizinlere erişileceğini belirtmelisiniz. Örneğin, geçerli dizine erişim verip bir argüman da geçmek için: wasmtime --dir=. target/wasm32-wasi/release/hello-wasi.wasm merhaba. Eğer program dosya okuyacaksa, çevre değişkenlerini de iletebilirsiniz: wasmtime --dir=. --env INPUT=input.txt target/wasm32-wasi/release/hello-wasi.wasm. Bu şekilde uygulama yalnızca izin verdiğiniz yollara ulaşır; kök sisteme doğrudan erişemez.
Paketleme ve Dağıtım Stratejileri
- Tek dosya yaklaşımı: Uygulamanızı yalnızca .wasm olarak paylaşın ve kullanıcılara Wasmtime kurmalarını söyleyin. Çoğu Linux/macOS/Windows ortamında kurulum dakikalar içinde yapılır.
- Önceden derlenmiş modüller: wasmtime compile -o app.cwasm app.wasm ile JIT yerine AOT derlenmiş bir çıktı üretip daha hızlı başlangıç süreleri elde edebilirsiniz.
- Küçük runner ekleme: Bazı takımlarda, Wasmtime binary’si ile .wasm dosyasını aynı pakete koyup basit bir wrapper script ile kullanım sağlamak yaygındır. Bu, “docker’sız, tek arşiv” dağıtımı kolaylaştırır.
Performans ve Boyut
WASM performansı, CPU-ağırlıklı olmayan CLI’larda çoğu kullanım için yeterince hızlıdır. Başlangıç süresi kısa, bellek tüketimi kontrollüdür. Rust tarafında LTO ve strip ayarlarıyla boyutu küçültebilirsiniz: [profile.release] lto = "thin", opt-level = "z" gibi ayarlar ve cargo build --release sonrası wasm-opt -Oz (Binaryen) ek sıkıştırma sağlayabilir. Tipik bir basit araç 300 KB – birkaç MB aralığında olur.
Sınırlamalar ve Çözüm Yolları
- Ağ erişimi: WASI’nin ağ API’leri hâlâ olgunlaşma aşamasında. Wasmtime deneysel soket uzantılarıyla çalışabilir, ancak üretimde dikkatle değerlendirin. Alternatif olarak, ağ erişimini bir proxy süreci veya HTTP üzerinden borulama (stdin/stdout) ile soyutlayabilirsiniz.
- Çoklu thread’ler: WASI-threads yaygınlaşsa da her çalışma zamanı aynı olgunlukta değil. CLI tarafında işbirlikçi asenkron mimari (ör. tokio + wasm32-wasi) çoğu senaryoda yeterli olur.
- Dinamik bağlama: Paylaşımlı kütüphaneler yerine statik ve portable bağımlılıklar tercih edin. Bu yaklaşım zaten WASM’in tasarım felsefesine daha uygundur.
Alternatif Diller ve Araçlar
Rust en iyi deneyimlerden birini sunar, ancak tek seçenek değil. TinyGo ile Go kodunu GOOS=js GOARCH=wasm yerine doğrudan wasm32-wasi hedefiyle derlemek mümkün. Zig ve C/C++ projeleri de WASI için güçlü adaylardır. JavaScript tarafında Node’un WASI modülü ile sınırlı ama işe yarar kullanım alanları mevcuttur.
Güvenlik ve Uyumluluk
WASI’nin yetenek tabanlı modeli, yanlışlıkla sistem dosyalarını silme veya gizli ortam değişkenlerine erişme riskini kökten azaltır. Komut satırında her hak açıkça verilir: --dir, --env gibi bayrakları kullanmadığınız sürece uygulamanız “kör ve sağır” bir kutuda çalışır. Bu, regülasyonlu ortamlarda denetlenebilirlik ve asgari ayrıcalık ilkesi açısından büyük bir artıdır.
Gerçek Dünya Senaryoları
- İç araçlar: Veri dönüştürücüler, şema doğrulayıcılar, log filtreleyiciler tek .wasm olarak dağıtılabilir.
- CI/CD adımları: Çoklu işletim sistemi matrislerinde aynı .wasm’ı koşarak “build once, run anywhere” elde edersiniz.
- Eklenti mimarileri: Ana uygulama, .wasm eklentilerini güvenli sandbox’ta çalıştırarak güvenlik yüzeyini daraltabilir.
Sonuç
WASI destekli WebAssembly, CLI araçlarının dağıtımını basitleştirirken güvenlik ve taşınabilirliği artırır. Wasmtime ile birkaç komutla hem geliştirme hem de çalıştırma deneyimi elde edersiniz. Ağ ve thread’ler gibi bazı alanlar hâlâ olgunlaşsa da, bugün itibarıyla dosya işleme, metin dönüştürme, doğrulama ve otomasyon görevleri için üretime hazır bir seçenek. Eğer farklı platformlarda aynı davranışı sunan, Docker kurulumuna bağımlı olmayan ve denetlenebilir izinlerle çalışan araçlar istiyorsanız, bir sonraki CLI’nızı WASI hedefiyle derlemeyi ciddi biçimde düşünün.