Tutorial

Actualizar un stack Docker Compose en producción

Despliegue9 min de lectura5 pasos

Un `docker compose pull` seguido de `up -d` siempre funcionó — hasta el día en que dejó de funcionar. Los cambios disruptivos recientes en Meilisearch v1.54, Supabase PostgreSQL 15→17, Langfuse v3→v4 y NocoDB 2026.09 lo confirmaron duramente: instancias de producción estables durante meses, inutilizables tras una actualización sin preparación. Esta guía te da un protocolo reproducible: haz un backup antes de hacer pull, revisa las notas de versión antes de relanzar y vuelve a la imagen anterior en menos de dos minutos si algo falla.

Contenido· Por qué `latest` es el verdadero culpable1/9
  1. 01Por qué `latest` es el verdadero culpable
  2. 02Qué cubre esta guía — y qué no
  3. 03Paso 1 — Fija todas tus imágenes
  4. 04Protocolo de actualización — los 5 pasos
  5. 05Mantén la versión anterior disponible localmente
  6. 06Los breaking changes recientes que derribaron instancias
  7. 07Estrategias de actualización: comparativa
  8. 08Integrar este protocolo en tu flujo de trabajo
  9. 09Automatizar sin perder el control

Por qué `latest` es el verdadero culpable

Cuando una imagen Docker etiquetada como latest se actualiza en el registry, tu docker compose pull la descarga en silencio. Sin advertencia, sin diff. Reinicias el stack y descubres que el nuevo contenedor no puede leer los datos que dejó el anterior.

Esto es exactamente lo que ocurrió con Meilisearch v1.54. Esta versión introdujo un nuevo formato de almacenamiento vectorial por defecto (cambio de arroy a HNSW) que hace el directorio de datos incompatible con versiones anteriores. Al iniciarse, Meilisearch rechaza abrir la base de datos y entra en crash-loop. El único camino de recuperación limpio es crear un dump antes de la actualización — imposible una vez que el contenedor está bloqueado.

El tag latest no resuelve a la misma imagen según el momento del pull. Dos desarrolladores que ejecutan docker compose pull con doce horas de diferencia pueden descargar versiones distintas. En un stack de producción, esta ambigüedad es inaceptable. La solución no es evitar las actualizaciones: es controlar explícitamente qué versión está en ejecución y decidir conscientemente cuándo pasar a la siguiente.

Qué cubre esta guía — y qué no

  • Qué cubre esta guía: el protocolo paso a paso para actualizar un stack Docker Compose en un VPS — version pinning, backup de volúmenes, revisión de notas de versión, rollback rápido, healthchecks como red de seguridad.
  • Cubierto en otras guías: el checklist de hardening inicial (docker-compose-production-checklist), la configuración de depends_on y service_healthy (docker-compose-depends-on-healthcheck), y la comparativa de herramientas de actualización automática como Watchtower o Diun.
  • Lo que esta guía no recomienda: Watchtower o cualquier herramienta de auto-pull en producción — ese es precisamente el antipatrón que ilustran los casos de breaking changes.
  • Público objetivo: desarrolladores y agencias que gestionan uno o más stacks Docker Compose en producción en un VPS, con acceso root y volúmenes persistentes.

Paso 1 — Fija todas tus imágenes

La primera acción, antes de cualquier actualización, es reemplazar cada image: meili/meilisearch:latest o image: supabase/postgres por una versión explícita.

Dos formas son aceptables:

- Tag de versión: image: getmeili/meilisearch:v1.53.0 — legible, versionable en git, fácil de parchear.
- Digest SHA256: image: getmeili/meilisearch@sha256:abc123… — inmutable, garantiza que descargas exactamente el mismo artefacto en cada redespliegue, incluso si el tag fue sobreescrito.

Para obtener el digest de una imagen ya en ejecución:

docker inspect --format='{{index .RepoDigests 0}}' getmeili/meilisearch:v1.53.0

Una vez fijadas tus imágenes, haz commit del docker-compose.yml en git. Cada bump de versión se convierte en un commit, lo que te da un historial claro y un rollback trivial (git revert + docker compose up -d).

Protocolo de actualización — los 5 pasos

  1. Lee las notas de versión antes de hacer pull

    Primero, consulta las notas de versión de la nueva versión. Busca las palabras breaking, migration, incompatible, pg_upgrade, dump. Esto no es opcional: Supabase documentó explícitamente que actualizar de PostgreSQL 15 a 17 requiere un pg_upgrade manual — el contenedor PG 17 se niega a arrancar sobre un volumen PG 15, y el proceso de inicialización no migra los datos automáticamente.

    Para Langfuse v4 (lanzado el 17 de agosto de 2026), los SDKs Python v2 y anteriores son rechazados en la ingesta por el nuevo stack — un cambio disruptivo que afecta a todos los servicios cliente que rastrean mediante la API antigua.

    Tres minutos de lectura te ahorran varias horas de recuperación de datos.

  2. Haz backup de los volúmenes antes del pull

    Nunca hagas pull sin tener un backup utilizable. Para volúmenes nombrados, dos enfoques:

    Dump aplicativo (recomendado para bases de datos) — el servicio debe estar healthy antes de hacer el dump:

    docker compose exec db pg_dump -U postgres -Fc mydb > backup_$(date +%Y%m%d_%H%M%S).dump

    Snapshot de volumen en crudo — útil para almacenes binarios (Meilisearch, Redis, MinIO):

    docker run --rm \
      --volumes-from $(docker compose ps -q meilisearch) \
      -v $(pwd)/backups:/backup \
      alpine tar czf /backup/meili_$(date +%Y%m%d_%H%M%S).tar.gz /meili_data

    Verifica que el backup es legible antes de continuar. Un archivo de dump corrupto descubierto durante la recuperación es el escenario más costoso que existe.

  3. Descarga la nueva imagen y pruébala fuera de producción

    Actualiza el tag en tu docker-compose.yml, luego descarga la imagen sin reiniciar el servicio:

    docker compose pull meilisearch

    Si tu entorno lo permite, prueba la nueva imagen sobre un clon del volumen en un entorno ddev o una VM de staging antes de tocar producción. Revisa los logs de arranque en busca de errores de migración:

    docker compose up -d meilisearch
    docker compose logs -f meilisearch

    Espera a que el healthcheck alcance el estado healthy antes de validar. Un servicio que arranca pero no está healthy todavía no es un servicio listo.

  4. Verifica los healthchecks

    Un healthcheck bien configurado es tu primera línea de detección. Debe estar presente en cada servicio crítico del stack, en formato Compose v2:

    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:7700/health || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

    El campo start_period es crítico para servicios de arranque lento (bases de datos, motores de búsqueda): evita que Docker declare el contenedor unhealthy durante la fase de inicialización y desencadene un reinicio prematuro.

    Consulta docker-compose-depends-on-healthcheck para la configuración completa de service_healthy en PostgreSQL — el mismo principio aplica a cualquier servicio que necesite un período de calentamiento.

  5. Rollback si algo falla

    Si la nueva versión no arranca o produce errores, el rollback debe tomar menos de dos minutos. El procedimiento:

    1. Vuelve al tag anterior en docker-compose.yml (o git revert si hiciste commit del bump).
    2. Reinicia únicamente el servicio afectado, sin recrear los volúmenes:

    docker compose up -d --no-deps --force-recreate meilisearch

    3. Revisa los logs inmediatamente:

    docker compose logs -f meilisearch

    El flag --no-deps es esencial: reinicia el servicio objetivo sin tocar los otros contenedores (base de datos, caché, proxy). Sin él, docker compose up -d puede recrear todo el stack.

    ⚠️ Si la nueva versión migró el formato de los datos en disco (Meilisearch v1.54, Supabase PG17), revertir la imagen no es suficiente — por eso el backup del volumen es una precondición, no una opción.

Mantén la versión anterior disponible localmente

Antes de descargar la nueva imagen, etiqueta la imagen actualmente en producción con un nombre de retención:

docker tag getmeili/meilisearch:v1.53.0 getmeili/meilisearch:rollback

Esto te permite volver al estado exacto de producción en caso de emergencia, incluso sin acceso al registry o con conexión lenta. En un VPS con ancho de banda limitado, este tag local te ahorra varios minutos de descarga en el peor momento.

Los breaking changes recientes que derribaron instancias

Estos cuatro ejemplos ilustran por qué el protocolo anterior no es teórico.

Meilisearch v1.53 → v1.54 (2026): introducción del almacén vectorial HNSW como formato por defecto. Meilisearch se niega a abrir un índice creado con el antiguo formato arroy. El arranque entra en crash-loop con Your database version is incompatible with your current engine version. La única salida limpia es haber exportado un dump antes de la actualización — importarlo en la nueva versión restaura tus datos.

Supabase Docker PostgreSQL 15 → 17 (migración activada el 17 de junio de 2026): el contenedor supabase/postgres:17 no puede leer un volumen inicializado por PG 15. Supabase documenta explícitamente que el salto requiere un pg_upgrade mediante un script dedicado — el proceso de inicialización del contenedor no lo hace automáticamente. Sin una migración previa, la base de datos no arranca.

Langfuse v3 → v4 (GA el 17 de agosto de 2026): la v4 abandona los endpoints de ingesta batch legacy en favor de OpenTelemetry. Los SDKs Python v2 y anteriores y los SDKs JS/TS v3 y anteriores son rechazados en la ingesta desde el momento en que arranca el stack v4. Si tus servicios cliente no han migrado antes de la actualización del servidor, pierden silenciosamente todos sus trazados.

NocoDB 2026.09.x: la serie 2026.09 reconstruye las imágenes Docker para eliminar dependencias vulnerables. Las instalaciones que usan bind-mounts (./postgres, ./nocodb) en lugar de volúmenes nombrados pueden arrancar sobre una base de datos vacía tras el pull — NocoDB no encuentra sus datos si la ruta de montaje cambió entre versiones. Se recomienda migrar a volúmenes nombrados antes de actualizar.

Estrategias de actualización: comparativa

Desplace la tabla

EstrategiaSeguridad de datosTiempo de preparaciónRollback
`docker compose pull` + `up -d` directoSin garantía — breaking changes no detectados< 1 minutoDifícil si los datos fueron migrados
Bump de tag versionado + backup de volumenAlta — datos guardados antes de cualquier cambio10 a 20 minutosTrivial: revertir tag + `up -d --no-deps`
Test en staging antes de prodMáxima — breaking changes detectados fuera de prodVariable según el entornoNo necesario si el test pasó
Imagen fijada por digest SHA256Alta — inmune al tag-overwriteIgual que tag versionadoIgual que tag versionado

Integrar este protocolo en tu flujo de trabajo

Un protocolo que queda en una guía no sirve de nada. Para aplicarlo sistemáticamente, externaliza la versión en un archivo .env versionado en git:

# .env
MEILISEARCH_VERSION=v1.53.0
POSTGRES_VERSION=15.6
# docker-compose.yml
services:
  meilisearch:
    image: getmeili/meilisearch:${MEILISEARCH_VERSION}

Actualizar una versión se convierte entonces en un único commit sobre .env — legible en git log, reversible con git revert, y desplegable por CI/CD sin modificar el archivo Compose principal.

Para agencias que gestionan múltiples stacks de clientes, crea un archivo CHANGELOG_INFRA.md por cliente: cada actualización queda registrada con la versión anterior, la fecha, el backup realizado y el resultado. Esto también te protege contractualmente ante un eventual incidente posterior.

Automatizar sin perder el control

Si quieres ser notificado de nuevas versiones sin auto-pull, Diun (Docker Image Update Notifier) monitoriza tu registry y te envía una notificación (Slack, email, webhook) cuando hay una nueva imagen disponible. Tú decides cuándo actualizar.

Esta es la diferencia fundamental con Watchtower: Diun notifica, Watchtower actúa. En un stack de producción con volúmenes persistentes, la notificación es el nivel correcto de automatización — la acción sigue siendo manual y precedida del protocolo anterior.

Un VPS con acceso root para aplicar este protocolo

Dumps completos, snapshots antes de actualizar, rollback a una imagen anterior: este protocolo requiere acceso root y almacenamiento local controlable. El hosting compartido no te da este nivel de control sobre los volúmenes Docker.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva