PrintStash v0.12.1: fiabilidad en el arranque del contenedor
Por qué algunos contenedores de la API entraban en bucle tras las migraciones, las dos variables de entorno que lo arreglan y a quién afecta.
La v0.12.1 es un parche de fiabilidad de un solo arreglo para la imagen de la API. No cambia nada de las funciones, del esquema de la base de datos ni de la configuración. Si tus contenedores arrancan limpios hoy, actualizar sigue siendo solo descargar la imagen nueva, y puedes dejar de leer aquí. Si ejecutas PrintStash con actualizaciones automáticas al estilo de Watchtower, o si alguna vez has sobrescrito el comando del contenedor, este parche es para ti.
Qué salió mal
El 20 de agosto llegaron avisos de que printstash-api:latest estaba en bucle de fallos: el
contenedor arrancaba, ejecutaba todas las migraciones de base de datos hasta el final, y moría
justo después, una y otra vez (#77). Una
de las personas que lo reportaron contó más de 250 intentos de reinicio a lo largo de varias
horas. El frontend se mantuvo en pie todo el tiempo, lo que lo hacía parecer peor de lo que era:
detrás había una API que nunca llegaba a estar sana.
El error al final de cada arranque fallido:
error: Failed to initialize cache at `/tmp/.uv_cache` Caused by: failed to open file `/tmp/.uv_cache/sdists-v9/.git`: Permission denied (os error 13)Esa ruta pertenece a uv, el gestor de paquetes que la imagen usa en tiempo de construcción. La
imagen construye su entorno de Python como root y luego ejecuta la aplicación con un usuario sin
privilegios llamado printstash. En la v0.12.0, la construcción dejó de entregar a ese usuario el
directorio de caché de uv, y el paso de instalación de Chromium de la imagen completa lo volvía a
crear después con root como propietario. La ruta de la caché además se filtraba al tiempo de
ejecución a través de una variable de entorno pensada para la etapa de construcción.
Nada de eso importaba en la vía de arranque que se publica. El entrypoint ejecuta las migraciones y
después lanza uvicorn directamente desde el virtualenv, así que un despliegue de Compose de serie
nunca invoca uv en tiempo de ejecución y nunca tocó la caché. El fallo necesitaba un segundo
ingrediente: un despliegue que sobrescriba el comando del contenedor o que arranque la aplicación
de otra forma a través de uv run, que es lo que todavía hacen bastantes archivos Compose
antiguos y bastantes personalizaciones de quien administra. Cuando un despliegue así descargaba
:latest, uv intentaba inicializar como usuario sin privilegios una caché cuyo propietario era
root, fallaba, y se llevaba el contenedor con él. Que las migraciones terminaran limpias en cada
ciclo hacía que el bucle pareciera incomprensible; nunca fueron el problema.
Qué ha cambiado
Dos variables de entorno, puestas al final del Dockerfile para que apliquen en tiempo de ejecución y dejen en paz a la etapa de construcción:
UV_CACHE_DIR=/tmp/printstash-uv-cachele da a cualquier invocación de uv en tiempo de ejecución un directorio de caché nuevo en el que el usuarioprintstashpuede escribir.UV_NO_SYNC=1evita que uv vuelva a sincronizar el entorno en cada invocación. Las dependencias están fijadas y horneadas en la imagen en tiempo de construcción; volver a comprobarlas en tiempo de ejecución es trabajo desperdiciado incluso cuando sale bien.
Un test de regresión comprueba ahora los dos valores, su posición después de que se cree el usuario sin privilegios, y que el entrypoint y el CMD que se publican siguen ejecutando el virtualenv directamente.
Si mantienes una sobrescritura propia del comando, sigue funcionando, y ahora lo hace sin depender de los permisos de un directorio en el que nada de la imagen publicada escribe en tiempo de ejecución. Si además quieres dejar atrás la vía antigua por completo, la forma directa es la que la propia imagen publica:
command: ["/app/.venv/bin/uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]Actualizar
Sin migraciones de base de datos y sin cambios de configuración. Descarga y reinicia:
docker compose pulldocker compose up -d --waitWatchtower y los actualizadores automáticos parecidos no necesitan nada más; las imágenes
arregladas son ya a lo que resuelve :latest. Como siempre, haz primero una copia de seguridad si
vienes de muchas versiones atrás, y la guía de actualización tiene la
rutina completa. La lista completa de cambios está en las
notas de la versión v0.12.1.