shm_size para un agente IA con Chromium: 64MB no alcanza
Resumen
Cómo no crashear Playwright en Docker: shm_size 1gb en Compose, /dev/shm distinto de mem_limit del cgroup. Si omites --shm-size el daemon usa 64m. ipc shareable no es host. Docs Compose y Engine, verificados con curl el 3 de septiembre de 2026.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
Chromium usa /dev/shm. En Docker el default es 64MB. Playwright “Target closed” / crashpad. shm_size: 1gb (o --shm-size). Distinto de límites de RAM: eso es cgroup; esto es el tmpfs de shm. Fuentes oficiales consultadas el 3 de septiembre de 2026.
La regla
shm_size: "1gb"
solo en el servicio que lanza browser. El webhook Node puro no lo necesita. Un worker de screenshots sí.
--disable-dev-shm-usage es parche: escribe a /tmp. Si readonly + tmpfs chico, igual explota. Prefiere shm real.
Relación con RAM
1gb shm cuenta hacia presión de memoria. Si mem_limit: 512m y shm 1gb, el cgroup gana: OOM. Sube RAM o baja shm. Mide tabs concurrentes.
cpu no arregla shm.
Tabla

| Servicio | shm | Por qué |
|---|---|---|
| agent HTTP | default | sin browser |
| agent+playwright | 1gb | Chromium |
| postgres | default | no usa shm de Chrome |
| migrate | default | one-shot |
Errores comunes

| Síntoma | Causa | Fix |
|---|---|---|
| Target closed | 64MB | shm_size 1gb |
| OOM a los 2s | shm > mem_limit | sube mem o baja shm |
| Fly sin campo | copy yaml | mounts / machine size |
| Workers | no Docker | no aplica |
| disable-dev-shm + read_only | /tmp lleno | shm o tmpfs mayor |
Relación con el resto
Checklist
- ¿El agente abre Chromium? Si no, skip
-
shm_size≥ 512mb, típico 1gb - mem_limit > shm + Node heap
- Ensayo: 1 screenshot sin crash
- No copies 1gb a postgres
- CI usa el mismo yaml
FAQ
¿Puppeteer igual? Sí. Misma shm.
¿headless shell? Menos, igual 256mb mínimo.
¿K8s? emptyDir medium: Memory sizeLimit.
El ensayo: df -h /dev/shm dentro del container. 64M = mal. 1G = ok. Un page.goto pesado no mata el browser.
No pongas 8gb “por si acaso” en un VPS de 2gb. Techo: tabs × ~100–200MB + margen.
Qué no hacer
No subas shm y dejes 10 browsers en paralelo en 1 CPU. cpu y cola de jobs. No uses privileged para “arreglar shm”.
Un tmpfs en /dev/shm a mano pisa shm_size. Un knob.
--ipc=host comparte shm del host: no en prod compartido.
Techos oficiales (curl 2026-09-03)
Compose shm_size (spec de servicios, hoy): configura el tamaño de memoria compartida — la partición /dev/shm en Linux — que el contenedor del servicio puede usar. Se expresa como byte value (entero o string tipo 1gb). No hay default escrito en esa página; el default lo pone el runtime.
docker run --shm-size (Engine, resource constraints, hoy):
- Formato
<number><unit>.numbermayor que 0. - Unidad opcional:
b,k,m,g. Sin unidad = bytes. - Si omites el tamaño, el sistema usa 64m.
CLI docker container run lista --shm-size como “Size of /dev/shm”. El 64m no vive en el yaml de Compose; vive en el daemon si no pones el campo.
mem_limit (Compose, hoy): tope de memoria que el contenedor puede allocar, byte value. Si lo pones, debe ser consistente con deploy.resources.limits.memory. mem_reservation es reserva, no tope. mem_swappiness 0–100; 0 apaga swap anónimo; 100 deja todo swappeable; default específico de plataforma. memswap_limit solo tiene sentido si también hay memory: es memoria + swap total. Ejemplo oficial: memory=300m y memswap_limit=1g → 300m RAM + el resto swap. shm de 1gb cuenta hacia esa presión; no es un cgroup aparte.
Resource constraints (Engine, hoy): hard limit = no más de X; soft = usa lo que necesite salvo presión del host. Sufijos b/k/m/g. No documentan /dev/shm en esa página: shm es el flag --shm-size, no -m.
Concurrencia
Un browser por job, cierra el context. 4 tabs × 1gb shm no es 4gb si son secuenciales. Si replicas cada replica tiene su shm.
El ensayo extra: compose exec agent df -h /dev/shm en CI. Assert ≥ 512M.
Imagen de browser
No metas Chromium en el mismo stage que el webhook si el 90% de mensajes no scrapean. profiles browser o un servicio agent-browser con shm. El HTTP queda liviano.
Playwright channel o executablePath de la imagen mcr.microsoft.com/playwright ya trae deps; shm sigue siendo tuyo.
Logs: no imprimas el dump entero de crashpad. json-file con max-size.
pids: Chromium spawnea procesos. pids_limit 64 puede matar tabs; sube si usas browser, no copies el valor del webhook.
USER 1000 debe poder escribir shm. Default sí. no-new-privileges no bloquea shm.
Si el crash es “page crashed” a los 30s, mira también stop_grace: un deploy mata el browser a media captura. Drain + shm juntos.
ipc y tmpfs: no son shm_size
Compose ipc (hoy): modo de aislamiento IPC.
shareable: namespace IPC propio, compartible con otros contenedores.service:{name}: se une al IPC shareable de otro servicio.
No hay ipc: host en el ejemplo oficial de Compose. El CLI sí tiene --ipc. Compartir IPC del host (--ipc=host) mezcla semáforos y shm del host con el bot: no en VPS compartido. Si dos sidecars de browser necesitan el mismo /dev/shm, el patrón documentado es shareable + service:agent-browser, no host.
Compose tmpfs (hoy): monta un tmpfs. Lista de paths. Opciones: mode, uid, gid. Ejemplo oficial: /data:mode=755,uid=1009,gid=1009 y /run. Un tmpfs en /dev/shm pisa el tamaño que puso shm_size. Un knob. Si readonly montas /tmp chico y Chromium usa --disable-dev-shm-usage, el crash se mueve a /tmp.
CLI --tmpfs monta un directorio tmpfs; no sustituye --shm-size.
privileged no “arregla” shm
Compose privileged (hoy): el contenedor corre con privilegios elevados. Soporte e impacto específicos de plataforma. Engine: --privileged da todas las caps, acceso a devices del host y relaja AppArmor/SELinux. No agranda /dev/shm. Si un gist de Playwright dice privileged: true para “arreglar Chrome”, es el peor trade. El knob correcto es shm_size.
--device da un device concreto sin privileged. /dev/shm ya es un tmpfs del runtime, no un device que montes a mano.
Fly / Railway / serverless
Fly y Railway no copian el campo shm_size de Compose. El tamaño de Machine/RAM es el techo; el default de shm del runtime puede seguir en 64m. Si el crashpad aparece ahí, mira el equivalente del runtime (docker extra en Fly, o un tmpfs explícito), no copies el yaml. Workers: isolates, sin /dev/shm. Vercel Functions: igual. No traduzcas el campo.
Cómo verificar
docker compose exec agent df -h /dev/shm
docker inspect --format '{{.HostConfig.ShmSize}}' "$(docker compose ps -q agent)"
df en 64M = el yaml no se aplicó (servicio mal nombrado, override, docker run sin flag). ShmSize del inspect está en bytes: 1073741824 ≈ 1g. CI: un page.goto pesado + screenshot; si “Target closed”, primero shm, después OOM.
Un solo screenshot de prueba en CI vale más que un wiki.
Siguiente paso: si shm está bien y igual OOM, memoria. Sin runtime: curso.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



