eclipse
+
backbone
+
+
[]
+
+
+
+
rb
+
+
!
+
+
+
+
dns
play
numpy
+
vim
+
+
py
+
junit
+
<-
+
+
+
+
+
::
rollup
travis
+
+
+
bun
rider
+
scheme
+
+
azure
+
toml
c++
webpack
+
+
%
+
+
+
+
+
+
+
gentoo
+
//
+
tf
preact
%
+
+
redis
+
+
mysql
clj
axum
echo
r
+
&&
+
sinatra
+
+
>=
+
+
+
#
Back to Blog
rocky-linux webassembly wasm

Building WebAssembly Runtime Platform with Wasmtime on Rocky Linux

Published Jul 15, 2025

Deploy a production-ready WebAssembly runtime platform using Wasmtime on Rocky Linux. Learn WASM module management, sandboxing, performance optimization, and cloud-native integration

19 min read
0 views
Table of Contents

WebAssembly (WASM) is revolutionizing application deployment by enabling near-native performance with language independence and strong sandboxing. This comprehensive guide demonstrates building a production-ready WebAssembly runtime platform using Wasmtime on Rocky Linux, covering module management, security, performance optimization, and integration with cloud-native ecosystems.

Understanding WebAssembly and Wasmtime

WebAssembly is a binary instruction format designed for safe, fast execution:

  • Language Agnostic: Compile from Rust, Go, C++, and more
  • Portable: Run anywhere with consistent behavior
  • Secure: Strong sandboxing and capability-based security
  • Fast: Near-native performance with ahead-of-time compilation
  • Lightweight: Smaller than containers, faster startup

Wasmtime Architecture

Wasmtime is a production-ready WebAssembly runtime:

  1. Cranelift: Fast compiler backend
  2. WASI: WebAssembly System Interface for system calls
  3. Security: Capability-based security model
  4. Performance: Optimizing compiler with caching
  5. Embedding: Easy integration into applications

Prerequisites

Before deploying Wasmtime:

  • Rocky Linux 9 with kernel 5.10+
  • Minimum 4GB RAM and 20GB storage
  • Development tools installed
  • Rust toolchain (for WASM development)
  • Basic understanding of WebAssembly concepts

Installing Wasmtime on Rocky Linux

System Preparation

# Update system packages
sudo dnf update -y

# Install development dependencies
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y \
    cmake \
    clang \
    lld \
    pkg-config \
    openssl-devel \
    python3-pip \
    jq

# Install performance monitoring tools
sudo dnf install -y \
    perf \
    sysstat \
    htop \
    iotop

# Configure system limits
cat <<EOF | sudo tee /etc/security/limits.d/wasmtime.conf
* soft nofile 65536
* hard nofile 65536
* soft nproc 32768
* hard nproc 32768
EOF

# Apply sysctl optimizations
cat <<EOF | sudo tee /etc/sysctl.d/99-wasmtime.conf
vm.max_map_count = 262144
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
EOF

sudo sysctl -p /etc/sysctl.d/99-wasmtime.conf

Installing Wasmtime

# Install Wasmtime using official installer
curl https://wasmtime.dev/install.sh -sSf | bash

# Add to PATH
echo 'export PATH="$HOME/.wasmtime/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

# Verify installation
wasmtime --version

# Install additional tools
# WASM-tools for module manipulation
cargo install wasm-tools

# wasm-pack for building WASM modules
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

# Install wabt (WebAssembly Binary Toolkit)
git clone --recursive https://github.com/WebAssembly/wabt
cd wabt
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install
cd ../..

Building a WASM Module Management System

Module Registry Service

// src/registry.rs - WASM module registry

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock};
use anyhow::{Result, Context};
use serde::{Deserialize, Serialize};
use sha2::{Sha256, Digest};
use wasmtime::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleMetadata {
    pub name: String,
    pub version: String,
    pub hash: String,
    pub size: u64,
    pub imports: Vec<String>,
    pub exports: Vec<String>,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub permissions: ModulePermissions,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModulePermissions {
    pub filesystem: Vec<String>,
    pub network: bool,
    pub env_vars: Vec<String>,
    pub memory_limit: u64,
    pub cpu_limit: f32,
}

pub struct ModuleRegistry {
    modules: Arc<RwLock<HashMap<String, ModuleMetadata>>>,
    storage_path: PathBuf,
    engine: Engine,
}

impl ModuleRegistry {
    pub fn new(storage_path: impl AsRef<Path>) -> Result<Self> {
        let mut config = Config::new();
        config.wasm_threads(true);
        config.wasm_simd(true);
        config.wasm_bulk_memory(true);
        config.cranelift_opt_level(OptLevel::Speed);
        
        let engine = Engine::new(&config)?;
        
        Ok(Self {
            modules: Arc::new(RwLock::new(HashMap::new())),
            storage_path: storage_path.as_ref().to_path_buf(),
            engine,
        })
    }
    
    pub fn register_module(&self, name: &str, version: &str, wasm_bytes: &[u8]) -> Result<ModuleMetadata> {
        // Validate WASM module
        let module = Module::new(&self.engine, wasm_bytes)
            .context("Failed to compile WASM module")?;
        
        // Calculate hash
        let mut hasher = Sha256::new();
        hasher.update(wasm_bytes);
        let hash = format!("{:x}", hasher.finalize());
        
        // Extract module information
        let imports = module.imports()
            .map(|import| format!("{}::{}", import.module(), import.name()))
            .collect();
        
        let exports = module.exports()
            .map(|export| export.name().to_string())
            .collect();
        
        // Create metadata
        let metadata = ModuleMetadata {
            name: name.to_string(),
            version: version.to_string(),
            hash,
            size: wasm_bytes.len() as u64,
            imports,
            exports,
            created_at: chrono::Utc::now(),
            permissions: ModulePermissions {
                filesystem: vec![],
                network: false,
                env_vars: vec![],
                memory_limit: 256 * 1024 * 1024, // 256MB default
                cpu_limit: 1.0,
            },
        };
        
        // Store module
        let module_path = self.storage_path
            .join(&metadata.name)
            .join(&metadata.version);
        
        std::fs::create_dir_all(&module_path)?;
        std::fs::write(module_path.join("module.wasm"), wasm_bytes)?;
        
        let metadata_json = serde_json::to_string_pretty(&metadata)?;
        std::fs::write(module_path.join("metadata.json"), metadata_json)?;
        
        // Update registry
        let key = format!("{}:{}", name, version);
        self.modules.write().unwrap().insert(key, metadata.clone());
        
        Ok(metadata)
    }
    
    pub fn get_module(&self, name: &str, version: &str) -> Result<Vec<u8>> {
        let module_path = self.storage_path
            .join(name)
            .join(version)
            .join("module.wasm");
        
        std::fs::read(&module_path)
            .with_context(|| format!("Module {}:{} not found", name, version))
    }
}

WASM Runtime Manager

// src/runtime.rs - WASM runtime management

use wasmtime::*;
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder};
use std::sync::Arc;
use anyhow::Result;

pub struct RuntimeConfig {
    pub memory_limit: u64,
    pub fuel_limit: Option<u64>,
    pub epoch_deadline: Option<u64>,
    pub allowed_paths: Vec<String>,
    pub env_vars: Vec<(String, String)>,
}

pub struct WasmRuntime {
    engine: Engine,
    config: RuntimeConfig,
}

impl WasmRuntime {
    pub fn new(config: RuntimeConfig) -> Result<Self> {
        let mut engine_config = Config::new();
        
        // Enable optimizations
        engine_config.cranelift_opt_level(OptLevel::Speed);
        engine_config.wasm_threads(true);
        engine_config.wasm_simd(true);
        
        // Enable fuel metering if specified
        if config.fuel_limit.is_some() {
            engine_config.consume_fuel(true);
        }
        
        // Enable epoch interruption
        engine_config.epoch_interruption(true);
        
        let engine = Engine::new(&engine_config)?;
        
        Ok(Self { engine, config })
    }
    
    pub fn create_instance(&self, module_bytes: &[u8]) -> Result<WasmInstance> {
        let module = Module::new(&self.engine, module_bytes)?;
        
        // Create store with limits
        let mut store = Store::new(&self.engine, WasmState::new());
        
        // Set memory limits
        store.limiter(|state| &mut state.limits);
        
        // Set fuel if configured
        if let Some(fuel) = self.config.fuel_limit {
            store.add_fuel(fuel)?;
        }
        
        // Create WASI context
        let wasi = self.create_wasi_context()?;
        store.data_mut().wasi = Some(wasi);
        
        // Create linker and add WASI
        let mut linker = Linker::new(&self.engine);
        wasmtime_wasi::add_to_linker(&mut linker, |state: &mut WasmState| {
            state.wasi.as_mut().unwrap()
        })?;
        
        // Instantiate module
        let instance = linker.instantiate(&mut store, &module)?;
        
        Ok(WasmInstance {
            store,
            instance,
            module,
        })
    }
    
    fn create_wasi_context(&self) -> Result<WasiCtx> {
        let mut builder = WasiCtxBuilder::new();
        
        // Configure filesystem access
        for path in &self.config.allowed_paths {
            builder = builder.preopened_dir(
                Dir::open_ambient_dir(path, ambient_authority())?,
                path,
            )?;
        }
        
        // Set environment variables
        for (key, value) in &self.config.env_vars {
            builder = builder.env(key, value)?;
        }
        
        // Inherit stdio
        builder = builder.inherit_stdio();
        
        Ok(builder.build())
    }
}

pub struct WasmInstance {
    store: Store<WasmState>,
    instance: Instance,
    module: Module,
}

pub struct WasmState {
    wasi: Option<WasiCtx>,
    limits: StoreLimits,
}

impl WasmState {
    fn new() -> Self {
        Self {
            wasi: None,
            limits: StoreLimitsBuilder::new()
                .memory_size(256 * 1024 * 1024) // 256MB
                .table_elements(10000)
                .instances(100)
                .memories(10)
                .build(),
        }
    }
}

Deploying WASM Applications

HTTP Server with WASM Handlers

// src/server.rs - HTTP server with WASM request handlers

use axum::{
    routing::{get, post},
    Router,
    extract::{Path, State},
    response::Json,
    http::StatusCode,
};
use std::sync::Arc;
use tokio::sync::RwLock;
use serde_json::Value;

pub struct WasmServer {
    runtime: Arc<WasmRuntime>,
    registry: Arc<ModuleRegistry>,
    handlers: Arc<RwLock<HashMap<String, WasmHandler>>>,
}

pub struct WasmHandler {
    module_name: String,
    module_version: String,
    instance: Arc<RwLock<WasmInstance>>,
}

impl WasmServer {
    pub async fn new(runtime: WasmRuntime, registry: ModuleRegistry) -> Result<Self> {
        Ok(Self {
            runtime: Arc::new(runtime),
            registry: Arc::new(registry),
            handlers: Arc::new(RwLock::new(HashMap::new())),
        })
    }
    
    pub async fn register_handler(
        &self,
        route: &str,
        module_name: &str,
        module_version: &str,
    ) -> Result<()> {
        // Load module from registry
        let module_bytes = self.registry.get_module(module_name, module_version)?;
        
        // Create instance
        let instance = self.runtime.create_instance(&module_bytes)?;
        
        // Register handler
        let handler = WasmHandler {
            module_name: module_name.to_string(),
            module_version: module_version.to_string(),
            instance: Arc::new(RwLock::new(instance)),
        };
        
        self.handlers.write().await.insert(route.to_string(), handler);
        Ok(())
    }
    
    pub async fn start(self: Arc<Self>, addr: &str) -> Result<()> {
        let app = Router::new()
            .route("/health", get(health_check))
            .route("/modules", get(list_modules))
            .route("/modules/:name/:version", post(upload_module))
            .route("/invoke/:handler", post(invoke_handler))
            .with_state(self);
        
        let listener = tokio::net::TcpListener::bind(addr).await?;
        axum::serve(listener, app).await?;
        
        Ok(())
    }
}

async fn invoke_handler(
    Path(handler): Path<String>,
    State(server): State<Arc<WasmServer>>,
    Json(input): Json<Value>,
) -> Result<Json<Value>, StatusCode> {
    let handlers = server.handlers.read().await;
    let handler = handlers.get(&handler)
        .ok_or(StatusCode::NOT_FOUND)?;
    
    let mut instance = handler.instance.write().await;
    
    // Call WASM function
    let func = instance.instance
        .get_func(&mut instance.store, "handle_request")
        .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // Serialize input
    let input_json = serde_json::to_string(&input)
        .map_err(|_| StatusCode::BAD_REQUEST)?;
    
    // Allocate memory for input
    let alloc_func = instance.instance
        .get_func(&mut instance.store, "alloc")
        .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?;
    
    let input_len = input_json.len() as i32;
    let input_ptr = alloc_func
        .typed::<i32, i32>(&instance.store)?
        .call(&mut instance.store, input_len)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // Write input to memory
    let memory = instance.instance
        .get_memory(&mut instance.store, "memory")
        .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?;
    
    memory.write(&mut instance.store, input_ptr as usize, input_json.as_bytes())
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // Call handler
    let result_ptr = func
        .typed::<(i32, i32), i32>(&instance.store)?
        .call(&mut instance.store, (input_ptr, input_len))
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // Read result
    let result_len_ptr = result_ptr + 4;
    let mut result_len_bytes = [0u8; 4];
    memory.read(&instance.store, result_len_ptr as usize, &mut result_len_bytes)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    let result_len = i32::from_le_bytes(result_len_bytes) as usize;
    let mut result_bytes = vec![0u8; result_len];
    memory.read(&instance.store, result_ptr as usize, &mut result_bytes)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    // Parse result
    let result: Value = serde_json::from_slice(&result_bytes)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    Ok(Json(result))
}

Building WASM Modules

Example: Image Processing Module

// image_processor/src/lib.rs - WASM image processing module

use wasm_bindgen::prelude::*;
use image::{DynamicImage, ImageFormat};

#[wasm_bindgen]
pub struct ImageProcessor {
    image: Option<DynamicImage>,
}

#[wasm_bindgen]
impl ImageProcessor {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        Self { image: None }
    }
    
    pub fn load_image(&mut self, data: &[u8]) -> Result<(), JsValue> {
        self.image = image::load_from_memory(data)
            .map_err(|e| JsValue::from_str(&e.to_string()))?
            .into();
        Ok(())
    }
    
    pub fn resize(&mut self, width: u32, height: u32) -> Result<(), JsValue> {
        if let Some(img) = &self.image {
            self.image = Some(img.resize(width, height, image::imageops::FilterType::Lanczos3));
            Ok(())
        } else {
            Err(JsValue::from_str("No image loaded"))
        }
    }
    
    pub fn blur(&mut self, sigma: f32) -> Result<(), JsValue> {
        if let Some(img) = &self.image {
            self.image = Some(img.blur(sigma));
            Ok(())
        } else {
            Err(JsValue::from_str("No image loaded"))
        }
    }
    
    pub fn to_bytes(&self, format: &str) -> Result<Vec<u8>, JsValue> {
        if let Some(img) = &self.image {
            let fmt = match format {
                "png" => ImageFormat::Png,
                "jpeg" => ImageFormat::Jpeg,
                "webp" => ImageFormat::WebP,
                _ => return Err(JsValue::from_str("Unknown format")),
            };
            
            let mut bytes = Vec::new();
            img.write_to(&mut bytes, fmt)
                .map_err(|e| JsValue::from_str(&e.to_string()))?;
            
            Ok(bytes)
        } else {
            Err(JsValue::from_str("No image loaded"))
        }
    }
}

// Export functions for non-wasm-bindgen usage
#[no_mangle]
pub extern "C" fn process_image(
    input_ptr: *const u8,
    input_len: usize,
    operation: *const u8,
    operation_len: usize,
) -> *mut u8 {
    // Implementation for direct WASM calls
    unsafe {
        let input = std::slice::from_raw_parts(input_ptr, input_len);
        let op = std::slice::from_raw_parts(operation, operation_len);
        let op_str = std::str::from_utf8_unchecked(op);
        
        let mut processor = ImageProcessor::new();
        if processor.load_image(input).is_err() {
            return std::ptr::null_mut();
        }
        
        match op_str {
            "thumbnail" => {
                let _ = processor.resize(200, 200);
            }
            "blur" => {
                let _ = processor.blur(2.0);
            }
            _ => return std::ptr::null_mut(),
        }
        
        match processor.to_bytes("png") {
            Ok(bytes) => {
                let len = bytes.len();
                let ptr = bytes.as_ptr();
                std::mem::forget(bytes);
                ptr as *mut u8
            }
            Err(_) => std::ptr::null_mut(),
        }
    }
}

Building and Optimizing WASM Modules

#!/bin/bash
# build_wasm_module.sh

# Set up Rust for WASM target
rustup target add wasm32-wasi
rustup target add wasm32-unknown-unknown

# Build the module
cargo build --target wasm32-wasi --release

# Optimize the WASM binary
wasm-opt -O3 \
    --enable-simd \
    --enable-threads \
    --enable-bulk-memory \
    target/wasm32-wasi/release/image_processor.wasm \
    -o image_processor_optimized.wasm

# Strip debug information
wasm-strip image_processor_optimized.wasm

# Validate the module
wasm-validate image_processor_optimized.wasm

# Generate bindings for different languages
wasm-bindgen \
    target/wasm32-wasi/release/image_processor.wasm \
    --out-dir ./bindings \
    --target nodejs

# Analyze module size
wasm-objdump -h image_processor_optimized.wasm

Security and Sandboxing

Capability-Based Security Configuration

# wasm_security_policy.toml

[default]
# Default security policy for all modules
max_memory = "256MB"
max_cpu_time = "30s"
max_file_handles = 10
network_access = false

[filesystem]
# Allowed filesystem paths (sandboxed)
read_paths = [
    "/tmp/wasm-sandbox/input",
    "/var/lib/wasm-data/readonly"
]
write_paths = [
    "/tmp/wasm-sandbox/output"
]
temp_path = "/tmp/wasm-sandbox/temp"

[network]
# Network access rules
allowed_hosts = []
allowed_ports = []
max_connections = 0

[resources]
# Resource limits
max_threads = 1
max_memory_pages = 4096  # 256MB with 64KB pages
stack_size = "1MB"
fuel_limit = 1000000000  # Computational steps

[capabilities]
# Fine-grained capabilities
clock_time = true
random = true
env_vars = ["WASM_*", "APP_*"]
args = false
stdin = false
stdout = true
stderr = true

Security Monitor

// src/security.rs - Security monitoring for WASM execution

use std::time::{Duration, Instant};
use tokio::sync::mpsc;

pub struct SecurityMonitor {
    tx: mpsc::Sender<SecurityEvent>,
}

#[derive(Debug)]
pub enum SecurityEvent {
    MemoryLimitExceeded { module: String, requested: u64, limit: u64 },
    CpuTimeExceeded { module: String, duration: Duration, limit: Duration },
    UnauthorizedFileAccess { module: String, path: String, operation: String },
    NetworkViolation { module: String, host: String, port: u16 },
    SuspiciousPattern { module: String, pattern: String },
}

impl SecurityMonitor {
    pub fn new() -> (Self, mpsc::Receiver<SecurityEvent>) {
        let (tx, rx) = mpsc::channel(1000);
        (Self { tx }, rx)
    }
    
    pub async fn monitor_execution<F, T>(
        &self,
        module_name: &str,
        time_limit: Duration,
        f: F,
    ) -> Result<T>
    where
        F: FnOnce() -> Result<T>,
    {
        let start = Instant::now();
        let module = module_name.to_string();
        let tx = self.tx.clone();
        
        // Set up monitoring
        let monitor_handle = tokio::spawn(async move {
            let mut interval = tokio::time::interval(Duration::from_millis(100));
            
            loop {
                interval.tick().await;
                
                if start.elapsed() > time_limit {
                    let _ = tx.send(SecurityEvent::CpuTimeExceeded {
                        module: module.clone(),
                        duration: start.elapsed(),
                        limit: time_limit,
                    }).await;
                    break;
                }
            }
        });
        
        // Execute function
        let result = f();
        
        // Clean up monitor
        monitor_handle.abort();
        
        result
    }
}

// Resource limiter using cgroups v2
pub struct CgroupLimiter {
    cgroup_path: PathBuf,
}

impl CgroupLimiter {
    pub fn new(name: &str) -> Result<Self> {
        let cgroup_path = PathBuf::from("/sys/fs/cgroup").join(name);
        std::fs::create_dir_all(&cgroup_path)?;
        
        Ok(Self { cgroup_path })
    }
    
    pub fn set_memory_limit(&self, limit_bytes: u64) -> Result<()> {
        let limit_path = self.cgroup_path.join("memory.max");
        std::fs::write(limit_path, limit_bytes.to_string())?;
        Ok(())
    }
    
    pub fn set_cpu_limit(&self, quota_us: u64, period_us: u64) -> Result<()> {
        let max_path = self.cgroup_path.join("cpu.max");
        std::fs::write(max_path, format!("{} {}", quota_us, period_us))?;
        Ok(())
    }
    
    pub fn add_process(&self, pid: u32) -> Result<()> {
        let procs_path = self.cgroup_path.join("cgroup.procs");
        std::fs::write(procs_path, pid.to_string())?;
        Ok(())
    }
}

Performance Optimization

JIT Compilation Cache

// src/cache.rs - Module compilation cache

use wasmtime::Module;
use lru::LruCache;
use std::sync::Mutex;

pub struct CompilationCache {
    cache: Mutex<LruCache<String, Module>>,
    persistent_path: Option<PathBuf>,
}

impl CompilationCache {
    pub fn new(capacity: usize, persistent_path: Option<PathBuf>) -> Self {
        Self {
            cache: Mutex::new(LruCache::new(capacity)),
            persistent_path,
        }
    }
    
    pub fn get_or_compile(
        &self,
        key: &str,
        engine: &Engine,
        wasm_bytes: &[u8],
    ) -> Result<Module> {
        // Check in-memory cache
        if let Some(module) = self.cache.lock().unwrap().get(key) {
            return Ok(module.clone());
        }
        
        // Check persistent cache
        if let Some(path) = &self.persistent_path {
            let cache_file = path.join(format!("{}.compiled", key));
            if cache_file.exists() {
                let compiled_bytes = std::fs::read(&cache_file)?;
                if let Ok(module) = unsafe { Module::deserialize(engine, &compiled_bytes) } {
                    self.cache.lock().unwrap().put(key.to_string(), module.clone());
                    return Ok(module);
                }
            }
        }
        
        // Compile module
        let module = Module::new(engine, wasm_bytes)?;
        
        // Store in cache
        self.cache.lock().unwrap().put(key.to_string(), module.clone());
        
        // Persist compiled module
        if let Some(path) = &self.persistent_path {
            let cache_file = path.join(format!("{}.compiled", key));
            let compiled_bytes = module.serialize()?;
            std::fs::write(cache_file, compiled_bytes)?;
        }
        
        Ok(module)
    }
}

Performance Monitoring

#!/bin/bash
# monitor_wasm_performance.sh

# Monitor WASM runtime performance
echo "=== WASM Performance Monitoring ==="

# CPU usage by WASM processes
echo -e "\n1. CPU Usage:"
top -b -n 1 | grep -E "wasmtime|wasm" | head -10

# Memory usage
echo -e "\n2. Memory Usage:"
ps aux | grep -E "wasmtime|wasm" | awk '{sum+=$6} END {print "Total RSS: " sum/1024 " MB"}'

# Module execution times
echo -e "\n3. Module Execution Times:"
journalctl -u wasm-runtime --since "1 hour ago" | grep "execution_time" | \
    awk '{print $NF}' | sort -n | \
    awk '{
        count++;
        sum+=$1;
        if(count==1) min=$1;
        if(count==NR) max=$1;
    } END {
        print "Min: " min "ms";
        print "Max: " max "ms";
        print "Avg: " sum/count "ms";
    }'

# JIT compilation stats
echo -e "\n4. JIT Compilation Stats:"
perf stat -e cycles,instructions,cache-misses \
    wasmtime run --profile=jitdump test.wasm 2>&1 | grep -E "cycles|instructions|cache"

# Module cache hit rate
echo -e "\n5. Cache Statistics:"
redis-cli --raw HGETALL wasm:cache:stats 2>/dev/null || echo "Cache not available"

Integration with Container Ecosystems

WASM in Kubernetes

# wasm-runtime-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wasm-runtime
  namespace: wasm-platform
spec:
  replicas: 3
  selector:
    matchLabels:
      app: wasm-runtime
  template:
    metadata:
      labels:
        app: wasm-runtime
    spec:
      containers:
      - name: wasmtime
        image: wasmtime/wasmtime:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "2000m"
        volumeMounts:
        - name: wasm-modules
          mountPath: /modules
        - name: wasm-cache
          mountPath: /cache
        env:
        - name: WASMTIME_CACHE_CONFIG
          value: "/cache/config.toml"
        - name: RUST_LOG
          value: "wasmtime=debug"
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
          capabilities:
            drop:
            - ALL
      volumes:
      - name: wasm-modules
        persistentVolumeClaim:
          claimName: wasm-modules-pvc
      - name: wasm-cache
        emptyDir:
          sizeLimit: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  name: wasm-runtime
  namespace: wasm-platform
spec:
  selector:
    app: wasm-runtime
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

Edge Deployment with WASM

// src/edge.rs - Edge computing with WASM

use std::sync::Arc;
use tokio::time::{timeout, Duration};

pub struct EdgeRuntime {
    runtime: Arc<WasmRuntime>,
    cache: Arc<CompilationCache>,
    config: EdgeConfig,
}

pub struct EdgeConfig {
    pub max_concurrent_executions: usize,
    pub execution_timeout: Duration,
    pub cache_size: usize,
    pub preload_modules: Vec<(String, String)>,
}

impl EdgeRuntime {
    pub async fn new(config: EdgeConfig) -> Result<Self> {
        let runtime_config = RuntimeConfig {
            memory_limit: 128 * 1024 * 1024, // 128MB for edge
            fuel_limit: Some(100_000_000),
            epoch_deadline: Some(30_000), // 30 seconds
            allowed_paths: vec!["/tmp/edge-wasm".to_string()],
            env_vars: vec![],
        };
        
        let runtime = Arc::new(WasmRuntime::new(runtime_config)?);
        let cache = Arc::new(CompilationCache::new(config.cache_size, None));
        
        let edge = Self {
            runtime,
            cache,
            config,
        };
        
        // Preload modules
        for (name, version) in &config.preload_modules {
            edge.preload_module(name, version).await?;
        }
        
        Ok(edge)
    }
    
    pub async fn execute_at_edge(
        &self,
        module_name: &str,
        function: &str,
        input: &[u8],
    ) -> Result<Vec<u8>> {
        // Execute with timeout
        timeout(
            self.config.execution_timeout,
            self.execute_internal(module_name, function, input)
        ).await?
    }
    
    async fn execute_internal(
        &self,
        module_name: &str,
        function: &str,
        input: &[u8],
    ) -> Result<Vec<u8>> {
        // Implementation
        todo!()
    }
}

Monitoring and Observability

Prometheus Metrics

// src/metrics.rs - Prometheus metrics for WASM runtime

use prometheus::{
    register_counter_vec, register_histogram_vec, register_gauge_vec,
    CounterVec, HistogramVec, GaugeVec,
};

lazy_static! {
    pub static ref MODULE_EXECUTIONS: CounterVec = register_counter_vec!(
        "wasm_module_executions_total",
        "Total number of WASM module executions",
        &["module", "function", "status"]
    ).unwrap();
    
    pub static ref EXECUTION_DURATION: HistogramVec = register_histogram_vec!(
        "wasm_execution_duration_seconds",
        "WASM execution duration in seconds",
        &["module", "function"],
        vec![0.001, 0.01, 0.1, 0.5, 1.0, 5.0, 10.0]
    ).unwrap();
    
    pub static ref MEMORY_USAGE: GaugeVec = register_gauge_vec!(
        "wasm_memory_usage_bytes",
        "Current memory usage by WASM modules",
        &["module"]
    ).unwrap();
    
    pub static ref COMPILATION_TIME: HistogramVec = register_histogram_vec!(
        "wasm_compilation_duration_seconds",
        "WASM module compilation time",
        &["module"],
        vec![0.01, 0.1, 0.5, 1.0, 5.0]
    ).unwrap();
    
    pub static ref CACHE_HITS: CounterVec = register_counter_vec!(
        "wasm_cache_hits_total",
        "Number of compilation cache hits",
        &["cache_type"]
    ).unwrap();
}

Best Practices and Production Deployment

Deployment Checklist

# wasm-deployment-checklist.yaml
deployment_checklist:
  security:
    - [ ] Enable sandboxing for all modules
    - [ ] Configure resource limits (memory, CPU, fuel)
    - [ ] Set up capability-based security policies
    - [ ] Enable execution monitoring and alerting
    - [ ] Regular security audits of WASM modules
  
  performance:
    - [ ] Enable JIT compilation caching
    - [ ] Configure appropriate memory limits
    - [ ] Set up performance monitoring
    - [ ] Enable SIMD and threads where appropriate
    - [ ] Profile and optimize hot paths
  
  operations:
    - [ ] Set up module registry and versioning
    - [ ] Implement health checks
    - [ ] Configure logging and tracing
    - [ ] Set up backup and recovery procedures
    - [ ] Document module dependencies
  
  integration:
    - [ ] Test with existing infrastructure
    - [ ] Set up CI/CD pipelines
    - [ ] Configure monitoring dashboards
    - [ ] Implement gradual rollout strategy
    - [ ] Plan for backward compatibility

Conclusion

Building a WebAssembly runtime platform with Wasmtime on Rocky Linux provides a powerful, secure, and performant environment for running portable applications. The combination of strong sandboxing, near-native performance, and language independence makes WASM an ideal choice for edge computing, serverless functions, and plugin systems.

By following the architecture and best practices outlined in this guide, you can deploy a production-ready WASM platform that scales efficiently while maintaining security and performance requirements.