Ir al contenido

A Quarter of a Year with the Wrong Cause

An explanation fit every detail of the error and was still wrong. It lasted three months because it was never measured, only copied.
16 de agosto de 2026 por
A Quarter of a Year with the Wrong Cause
IT-Guy
Docker Solución de problemas Operación del servidor Asistente de IA

Durante un trimestre, la causa incorrecta

Una explicación encajaba con cada detalle del error y, sin embargo, era incorrecta. Se mantuvo durante tres meses porque nunca se midió, sino que solo se copió.

M
Martin Schmid
2026-08-16

Un contenedor no se inició. En el registro aparecía una línea, siempre la misma:

exec /app/bin/boot: no such file or directory

Esto suena a un Dockerfile roto. El archivo falta en la imagen, por lo que algo no está bien con la instrucción COPY. Se revisa el Dockerfile y no se encuentra nada; se examina el contexto de compilación y tampoco se encuentra nada.

A continuación, se inicia la imagen con /bin/ls en lugar del punto de entrada, y la respuesta es: stat /bin/ls: no such file or directory. No falta el punto de entrada. Falta todo el sistema de archivos. La compilación de Docker informó éxito, se generó una imagen con un tamaño plausible, pero esta imagen está vacía por dentro.

Para eso, desde julio tenía una explicación. Encajaba en cada detalle y sin embargo era incorrecta, y tardé un trimestre en darme cuenta de ello.

En julio la explicación encajaba demasiado bien

En aquel entonces el mismo síntoma afectaba a un servidor recién instalado. Docker había cambiado recientemente la configuración predeterminada: las nuevas instalaciones desde la versión 29 almacenan las imágenes en el almacén containerd en lugar del clásico. Y en el rastreador de errores de Docker había un informe de error abierto sobre exactamente ese almacén, en el que la exportación de imágenes se interrumpía en construcciones grandes — moby/moby#52431, abierto desde abril.

La cadena se cerró inmediatamente. Nuevo servidor, nuevo almacén, error conocido. Hemos identificado el controlador clásico en la daemon.json , lo hemos reconstruido y el problema desapareció.

Lo que no hice entonces: verificar si la explicación era correcta. Encajaba, el problema desaparecía y así el asunto quedaba resuelto.

Cómo una suposición se convierte en hecho

Se escribe por escrito. Primero como comentario en el script de configuración, justo encima de la línea que establece el controlador antiguo. La misma justificación figuró posteriormente en las notas del proyecto, en la documentación operativa y en varios mensajes de compromiso.

Ninguno de esos puntos era una medición; cada uno era una copia de la anterior.

Lo más evidente es una frase de mis notas: El pin no debe eliminarse hasta que se cierre el error en el origen. Eso suena a diligencia. Pero significa que había hecho depender el estado de mis propios servidores de un rastreador de errores ajeno.

A esto se suma mi herramienta. Trabajo con Claude como asistente de IA, y él lee exactamente estos archivos. Cuando el síntoma volvió a aparecer en agosto, sugirió reiniciar el servidor, respaldando su recomendación con las notas de julio. No preguntó si las notas eran correctas.

Eso no es un error del modelo. Lo que hace es garantizar la coherencia con lo que encuentra. Si lo encontrado es incorrecto, el error se distribuye solo más a fondo.

En agosto, la explicación ya no era válida.

El servidor que esta vez fue afectado había estado funcionando durante un mes con el antiguo controlador. Precisamente el que debería haber prevenido el problema.

Con eso, la hipótesis ya estaba prácticamente descartada. Una protección que no previene el problema no sirve de nada. Sin embargo, casi habría resuelto el asunto con otra explicación en lugar de una medición, porque el reinicio sonaba plausible y en el registro del kernel había mensajes compatibles.

La pregunta que resolvió el nudo vino de una persona. Fue algo como:¿No podría tratarse de un desliz único y el nuevo almacén ya está en orden?

Una tarde de mediciones frente a un trimestre de conjeturas.

La configuración fue sencilla. Una instancia desechable con Docker 29.7.2, dos ejecuciones, cada una con cinco rondas, utilizando una imagen de 2,2 gigabytes y 22 capas, construida en frío, en caliente y tras la orden de limpieza que nuestra herramienta de actualización ejecuta de todos modos.

Dos aspectos de ello eran más importantes que la configuración en sí.

En primer lugar, establecí las reglas de decisión:anteriormenteescrito, junto con los resultados que irían en contra mía. Si el nuevo almacén funciona sin errores, el pin sale volando. Si ambos ejecutivos fallan, nunca fue la cura. Quien establece la regla de evaluación solo después de los números siempre encontrará uno que coincida con su propia tesis.

En segundo lugar, hubo un brazo de control. El nuevo almacén también podría haber funcionado perfectamente por accidente.

El resultado: cinco de cinco sin errores en el nuevo almacén, ninguna sola advertencia del núcleo. El brazo de control con el antiguo controlador también cinco de cinco. Ambos almacenes generan imágenes utilizables, y las imágenes vacías provienen de ninguno de los dos.

El pin volvió, por otra razón

Al día siguiente medí el caso de uso real en lugar de una imagen de prueba: la compilación completa de nuestra aplicación, con archivos almacenados localmente previamente, tal como funciona en producción. Tres rondas en frío y dos en caliente por ejecución, en la misma máquina.

En frío 14 segundos frente a 37. Solo la exportación 3,5 frente a 19,7. Y la línea que decidió: la compilación en caliente, que debería durar fracciones de segundo, necesitó en el nuevo almacén los mismos 36 segundos que la en frío. Su caché de compilación no sobrevive al comando de limpieza que nuestro herramienta ejecuta después de cada actualización. Esta es mi medición en una máquina, no una propiedad documentada del producto.

Por lo tanto, el antiguo controlador vuelve a estar en el script de configuración. Por una razón medida, con los números al lado, y con un interruptor que lo desactiva.

La causa original de las imágenes vacías sigue siendo desconocida hasta hoy. Tengo una hipótesis que coincide con las marcas de tiempo, y la he escrito como hipótesis en las notas, junto con el comando que la confirmará o refutará si vuelve a ocurrir.

Esta es la única diferencia con julio.

Valores de medición

Dos ejecuciones en dos días, ambas en la misma instancia desechable: Debian 13, Docker 29.7.2. La parte superior responde a la pregunta sobre las imágenes vacías, la inferior a la de la velocidad. Solo la inferior ha recuperado el pin.

Medición overlay2 (controlador antiguo) almacén containerd
Imágenes defectuosas, 5 rondas de 2,2 GB y 22 capas 0 de 5 0 de 5
Mensajes overlayfs en el registro del kernel ninguno ninguno
Construcción sintética, tiempo total 20 s 36 s
Construcción Odoo, en frío 14 s 37 s
incluido el paso de exportación 3,5 s 19,7 s
Construcción Odoo, en caliente después de docker system prune -f 0–1 s 35–36 s

La ejecución sintética se realizó el 14.08.2026 con datos aleatorios no comprimibles y, por tanto, se compone casi totalmente del paso de exportación. La construcción Odoo del 15.08.2026 es el caso de uso real: 394 archivos de módulos estaban disponibles localmente con antelación, tres rondas en frío y dos en caliente por ejecución.

La última línea es la que importa. Nuestra herramienta de actualización invoca después de cada ejecución docker system prune -f y el caché de construcción del almacén containerd no lo soporta — cada actualización sería allí una reconstrucción completa.

Los datos de la penúltima y antepenúltima línea deben leerse juntos: Si los tiempos totales hubieran sido diferentes sin que el paso de exportación se moviera junto, el controlador de almacenamiento no habría sido la causa. Se mueve junto para el factor 5,6.


Creado por Martin Schmid, con el apoyo de Claude Opus 5 y aprobado tras revisión de contenido propia. Aplican nuestras indicaciones y exclusión de responsabilidad.

A Quarter of a Year with the Wrong Cause
IT-Guy 16 de agosto de 2026
Archivo
5,000 Tokens Less, No Lines Deleted
A report recommended that I delete 80 percent of my Claude Code configuration. I tested it, read the transcript, and built something else.