Skip to main content
Midaz aplica las migraciones de esquema de PostgreSQL mediante imágenes de runner de migración dedicadas (una para el Ledger, otra para Tracer), desacopladas de los binarios de la aplicación. Las aplicaciones ya no migran al iniciar. Arrancan contra un esquema que el runner ya migró.
Este modelo es el que se ejecuta bajo make up en desarrollo local y bajo el chart de Helm en Kubernetes. Si usas make up, no necesitas ningún paso manual. El stack de Compose bloquea la aplicación hasta que se complete el runner de migración.

Por qué un runner dedicado


El antiguo migrador en proceso se ejecutaba en cada arranque de la aplicación desde el directorio de trabajo. Bajo un contexto de seguridad de pod reforzado (distroless:nonroot, runAsUser: 1000, readOnlyRootFilesystem: true, capabilities: drop [ALL]), esa ruta fallaba con permission denied y el pod entraba en un ciclo de fallos. El runner dedicado evita eso:
  • Las migraciones se ejecutan una vez, como un paso separado, antes de que la aplicación arranque.
  • La imagen de la aplicación ya no incluye el SQL de migración y nunca escribe en el esquema.
  • La propia imagen del runner funciona sin problemas bajo el mismo contexto de seguridad reforzado (consulta Postura de seguridad).

Imágenes del runner


Cada versión incluye dos imágenes: Ambas imágenes comparten la misma forma:
  • Base: migrate/migrate v4.19.1 (fijada).
  • Se ejecuta como USER 65532:65532 (sin root, agnóstico al UID).
  • Punto de entrada en shell POSIX que arma un DSN a partir de variables de entorno, ejecuta migrate ... up y termina.
  • No escribe nada en disco. Postgres registra el progreso de la migración en la tabla schema_migrations, por lo que readOnlyRootFilesystem: true es seguro.
El runner del Ledger aplica primero onboarding y luego transaction, en una sola invocación. El runner de Tracer aplica su única base de datos en un solo paso.

Contrato de entorno


Cada punto de entrada acepta una anulación de URL ya construida o las variables individuales DB_*. La anulación de URL tiene prioridad cuando está definida.

Runner del Ledger

Runner de Tracer

Forma del DSN

Cuando el punto de entrada arma el DSN a partir de las variables DB_*, produce:
La contraseña se codifica en formato percent-encoding para que los caracteres reservados de URI (% @ : / ? # & + space [ ]) no rompan el DSN. El % se codifica primero para que los escapes ya insertados no se codifiquen dos veces. El punto de entrada solo registra marcadores de fase (applying onboarding migrations, applying transaction migrations, applying tracer migrations, migrations complete). Nunca imprime credenciales ni el DSN ensamblado.

Desarrollo local


make up

Desde la raíz del repositorio, make up:
  1. Inicia la infraestructura y espera hasta que Postgres esté disponible.
  2. Inicia los servicios de Compose de ejecución única ledger-migrate y tracer-migrate.
  3. Inicia cada servicio de la aplicación, que depende (depends_on) de su servicio de migración con condition: service_completed_successfully.
La aplicación nunca arranca contra una base de datos sin migrar.

Objetivos de make en el host

Cada componente expone objetivos de Make en el host que ejecutan migraciones directamente contra una base de datos local, por ejemplo cuando desarrollas una migración nueva. Los objetivos usan la CLI fijada de golang-migrate y leen la configuración de conexión desde .env. Ledger (components/ledger): Tracer (components/tracer):

Ejemplo: ejecutar el runner del Ledger manualmente

Rara vez necesitas invocar la imagen del runner manualmente, porque la puerta de Compose lo hace por ti. Cuando lo necesites, apunta el runner a tus bases de datos mediante DB_* (o *_DATABASE_URL) y ejecútalo una vez:
El runner sale con 0 en caso de éxito (incluido el caso idempotente sin efecto) y con un valor distinto de cero en caso de error.

Despliegue en Kubernetes


En producción, ejecuta cada runner de migración como un Job de Kubernetes (normalmente un Job PreSync de Argo CD o un hook de Helm) que se completa antes del rollout de la aplicación. El chart de Helm configura esto por ti. Las secciones siguientes cubren las propiedades que importan si escribes tus propios manifiestos.
En despliegues multi-tenant, el runner es intencionalmente agnóstico al tenant: migra las bases de datos indicadas por su entorno, una vez. El fan-out por tenant es un asunto del despliegue. Ejecuta el Job una vez por cada base de datos de tenant con los valores DB_* (o la anulación de URL) de ese tenant.

Postura de seguridad

El runner funciona bajo un contexto de seguridad de pod reforzado:
  • Sin root: la imagen establece USER 65532:65532.
  • Agnóstico al UID: los archivos de migración pertenecen a root y son legibles por cualquier usuario, de modo que cualquier UID puede leerlos.
  • Seguro para readOnlyRootFilesystem: migrate no escribe ningún estado en el sistema de archivos.
La misma imagen funciona sin problemas bajo runAsNonRoot: true, readOnlyRootFilesystem: true y capabilities: drop [ALL].

TLS

Los puntos de entrada respetan sslmode desde el entorno (DB_ONBOARDING_SSLMODE, DB_TRANSACTION_SSLMODE o DB_SSL_MODE), con disable como valor predeterminado. En producción se recomienda establecer require (o algo más estricto). El runner en shell no reproduce la aplicación de TLS en código, la clasificación de errores ni la telemetría que las aplicaciones usan para sus propias conexiones. Controlas el TLS de las migraciones únicamente a través de sslmode, a cambio de un runner mínimo y sin dependencias.

Convenciones e idempotencia


  • Up/down emparejados: cada migración tiene un archivo .up.sql y un archivo .down.sql.
  • Idempotente: ejecutar migrate up cuando el esquema ya está en la última versión no tiene efecto. Volver a ejecutar el runner después de una aplicación parcial o completa es seguro.
  • CLI fijada: las imágenes del runner y los objetivos de make en el host fijan todos golang-migrate en v4.19.1.

Actualización desde versiones anteriores


No necesitas ninguna migración manual de datos si actualizas desde una versión de Midaz en la que la aplicación migraba al iniciar. El esquema en disco es el mismo. Para adoptar el nuevo modelo:
  1. Descarga la versión que incluye las imágenes del runner.
  2. En Kubernetes, agrega los Jobs midaz-ledger-migrations y midaz-tracer-migrations a tu pipeline de despliegue para que se ejecuten antes del rollout de la aplicación. Si usas el chart de Helm oficial, esto ya está hecho por ti.
  3. En desarrollo local, make up sigue funcionando como antes. El stack de Compose ahora bloquea automáticamente las aplicaciones hasta que se completen los nuevos servicios de migración de ejecución única.

Páginas relacionadas