containerd con Wasm: cargas mixtas en producción
Actualizado: 2026-05-03
La promesa de WebAssembly como tiempo de ejecución de servidor ha pasado por varias fases desde 2019. Con runwasi estable, runtimes como WasmEdge y wasmtime integrados sin fricciones y soporte de Kubernetes vía RuntimeClass maduro, es razonable preguntarse si ha llegado el momento de mezclar cargas Wasm con contenedores Linux clásicos en producción. La respuesta es matizada y depende mucho del caso de uso.
Puntos clave
- containerd soporta shims alternativos vía runwasi desde containerd 1.7 sin parches externos.
- Los runtimes más maduros para producción son WasmEdge (orientado a servidor, WASI Preview 2 nativo) y wasmtime (referencia técnica de Bytecode Alliance).
- Las ventajas reales de Wasm sobre contenedores Linux son arranque (<10 ms vs cientos de ms), tamaño de imagen (1–5 MB vs 20–40 MB) y seguridad por diseño (sandbox de memoria sin kernel compartido).
- Los límites reales son: ecosistema de lenguajes (Rust y C maduro, Java y Python experimental), acceso a red más limitado que Linux estándar y observabilidad menos madura.
- La adopción tiene sentido para serverless interno, edge distribuido y ejecución de código no confiable; no para servicios de larga duración con ecosistemas de lenguaje maduros.
Cómo se integra Wasm en containerd
containerd tiene una arquitectura de shims: pequeños procesos que implementan la interfaz de bajo nivel entre containerd y el motor real que ejecuta el contenedor. El shim por defecto es runc para contenedores Linux. El proyecto runwasi, iniciado por Microsoft y hoy bajo CNCF sandbox, proporciona shims alternativos que conectan containerd con runtimes WebAssembly.
Desde containerd 1.7 la integración se soporta sin parches externos:
# Instalación del shim WasmEdge wget https://github.com/containerd/runwasi/releases/download/v0.4.0/ containerd-shim-wasmedge-v1-linux-amd64.tar.gz tar -xzf containerd-shim-wasmedge-v1-linux-amd64.tar.gz sudo mv containerd-shim-wasmedge-v1 /usr/local/bin/ # Reiniciar containerd para que detecte el nuevo shim sudo systemctl restart containerd
En Kubernetes, el mecanismo de integración es el objeto RuntimeClass:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: wasmedge
handler: wasmedge
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: function-router
spec:
selector:
matchLabels: {app: function-router}
template:
metadata:
labels: {app: function-router}
spec:
runtimeClassName: wasmedge
containers:
- name: router
image: registry.local/router:v1.2.0-wasm
resources:
limits:
memory: 64Mi
cpu: 100m
El modelo mental es limpio: el nodo puede correr contenedores Linux y módulos Wasm simultáneamente, el planificador lo sabe, y el desarrollador solo elige la clase apropiada. El nodo que tiene instalado el shim WasmEdge puede servir ambos tipos de carga sin reconfiguraciones. Este modelo de runtime mixto es análogo al patrón de gVisor y runtimes alternativos donde distintos niveles de aislamiento conviven en el mismo clúster.
Dónde la diferencia es real
Arranque. Un contenedor Linux bien optimizado arranca en decenas o cientos de milisegundos desde imagen caliente; un módulo Wasm equivalente arranca en menos de 10 ms, a veces en 1 ms. Para funciones que arrancan y terminan bajo demanda, la diferencia es decisiva.
Tamaño de imagen. Una imagen OCI Linux para un servicio en Go ronda los 20–40 MB; su equivalente Wasm compilado suele estar entre 1 y 5 MB, sin dependencias de distribución base. Para edge con centenares de ubicaciones, la diferencia en ancho de banda es real.
Seguridad por construcción. Un módulo Wasm corre dentro de una máquina virtual de memoria segura por diseño, con acceso al sistema solo a través de WASI explícitamente concedido. La superficie de ataque es cualitativamente menor que la de un contenedor Linux. Para cargas no confiables o código de terceros, esta postura es superior.
Portabilidad entre arquitecturas. Un módulo Wasm compilado corre igual en x86_64, arm64 o plataformas raras sin recompilar. Para flotas heterogéneas de nodos edge, esto simplifica el pipeline de construcción.
Las limitaciones que hay que reconocer
Ecosistema de lenguajes. Rust compila a Wasm WASI Preview 2 con soporte muy maduro. Go lo hace con limitaciones mediante TinyGo o experimentalmente con el compilador principal. C y C++ vía wasi-sdk funcionan bien. Java, Python, Node.js y .NET siguen siendo difíciles o experimentales. Si el stack principal es Java o Python con dependencias nativas, migrar a Wasm no es opción realista.
Red y acceso a sistema. WASI Preview 2 añadió soporte robusto para sockets TCP y UDP, pero la API sigue siendo más limitada que Linux estándar. Servicios que usan epoll avanzado, señales específicas o ioctl necesitan reescribir o evitar esas partes.
Observabilidad. Las herramientas estándar de observabilidad en Kubernetes (cAdvisor, Prometheus con exporters) asumen procesos Linux con /proc y cgroups. Un módulo Wasm tiene su propia API de métricas que hay que conectar explícitamente. OpenTelemetry tiene soporte razonable para módulos Wasm, pero la madurez no es comparable al ecosistema Linux. Integrar esto desde el inicio con el stack de observabilidad 2026 es fundamental para no quedar operacionalmente ciego.
Cuándo compensa y cuándo no
Compensa en tres escenarios:
-
Plataforma serverless interna: Wasm sobre containerd da arranque frío mínimo, aislamiento fuerte y costes de recursos bajos comparado con Knative o OpenFaaS sobre contenedores Linux.
-
Edge y despliegue geográficamente distribuido: si se distribuye lógica a cientos de nodos con ancho de banda limitado y necesidad de arranque rápido, Wasm es claramente mejor.
-
Ejecución de código no confiable: marketplaces donde clientes suben código, análisis de datos con scripts de usuarios, plugins dinámicos. El aislamiento por diseño de Wasm es cualitativamente superior a contenedores Linux para este caso.
No compensa para servicios de larga duración con ecosistemas de lenguaje maduros (el arranque frío no es problema y las bibliotecas nativas cuentan), cargas con requisitos complejos de red o acceso a sistema, o equipos sin capacidad operativa para mantener dos superficies de runtime.
Cómo evaluar antes de adoptar
Mi recomendación práctica para un equipo que se plantea introducir Wasm en containerd es evaluar antes de adoptar:
- Identificar una carga concreta donde el beneficio de Wasm sea claro (lambda-like, edge, código no confiable).
- Montar un clúster de pruebas con runwasi y WasmEdge.
- Desplegar esa carga y medir: arranque, memoria, latencia y coste comparado con la versión contenedor clásica.
- Si los números justifican la complejidad añadida, continuar. Si no, no introducir dos superficies a mantener.
El segundo principio es no migrar servicios existentes por el gusto de migrar. Wasm brilla para cargas nuevas diseñadas aprovechando sus características, no como reemplazo forzado de cargas que funcionan bien en contenedores Linux.
El tercer principio es integrar observabilidad desde el inicio. OpenTelemetry con soporte Wasm desde el primer despliegue, no como añadido posterior.