Skip to content
← Todas las publicaciones
· Delta1 Labs KeyrightAutoalojamientoOperacionesActualizaciones

Actualiza una instancia de Keyright autoalojado con seguridad: migraciones, cero tiempo de inactividad, rollback

Actualizar Keyright autoalojado es poco dramático porque la app es sin estado y ejecuta sus propias migraciones de esquema al arrancar — nada de SQL a mano. Pero aun así quieres un procedimiento seguro: respalda Postgres primero, prueba en no-producción, fija la etiqueta de imagen y actualiza un nodo cada vez tras tu balanceador de carga. Aquí tienes la secuencia, incluido por qué el rollback significa restaurar la copia de la base de datos, no degradar contra una base de datos ya migrada.

Actualizar una pieza de infraestructura de licencias suena al tipo de mantenimiento que programas para las 2 de la madrugada conteniendo la respiración. Keyright autoalojado es deliberadamente aburrido aquí, y esa es la idea. La app es un contenedor sin estado que es dueño de su propio esquema de base de datos y lo migra al arrancar, así que una actualización es en su mayoría “descarga una imagen más nueva y reinicia”. Pero “en su mayoría” no es “siempre”, y un servidor de licencias se sienta en la ruta de activación de tus clientes, así que aun así quieres un procedimiento que sea seguro y no solo rápido. Este artículo es ese procedimiento —cómo funcionan realmente las actualizaciones, la secuencia segura, cómo hacerlo con cero tiempo de inactividad en varios nodos, y lo único del rollback que pilla a la gente.

Conclusión clave: Las actualizaciones son poco dramáticas porque la app es sin estado y aplica sus migraciones de EF Core automáticamente al arrancar —nada de SQL a mano. La secuencia segura sigue siendo: respalda Postgres primero, prueba en no-producción, fija la etiqueta de imagen y actualiza un nodo cada vez. El rollback significa restaurar la copia de la base de datos y redesplegar la etiqueta antigua —las migraciones van hacia delante, así que no degradas contra una base de datos ya migrada.

Cómo funciona realmente una actualización

Keyright tiene exactamente dos partes móviles: una app sin estado y tu base de datos. Esa división es lo que hace simples las actualizaciones.

La app es la imagen ghcr.io/delta1-labs/keyright —un servicio ASP.NET Core en el puerto 8080, sin base de datos dentro. Cada versión de la app lleva sus propias migraciones de esquema compiladas dentro de la imagen. Al arrancar, se conecta al PostgreSQL al que la apuntas con KEYRIGHT_DB y ejecuta db.Database.Migrate() —el primer arranque crea cada tabla y siembra el inquilino por defecto, y una actualización aplica solo las migraciones nuevas. Nunca ejecutas SQL a mano y nunca importas un esquema. Una nueva versión que necesita un cambio de esquema trae ese cambio consigo y lo aplica en el momento en que arranca.

Como las migraciones se ejecutan al arrancar, la base de datos debe ser alcanzable cuando el nuevo contenedor arranca. El endpoint de readiness lo hace seguro de automatizar: GET /health/ready comprueba la conectividad con la base de datos y devuelve 503 hasta que Postgres sea alcanzable y el esquema esté al día, mientras que GET /health es un 200 de liveness estático. Conecta tu balanceador de carga y tu orquestador a /health/ready y un nodo simplemente no recibirá tráfico hasta que haya migrado y esté realmente listo para servir. Si un nodo no puede alcanzar la base de datos al arrancar, sale y se reinicia en vez de levantarse a medio romper —un fallo que ves de inmediato, no uno que filtra respuestas malas.

La secuencia segura

Aunque la mecánica es un solo paso, haz estos cuatro en orden.

1. Respalda PostgreSQL primero. Esta es toda la red de seguridad, porque la vía limpia de vuelta de una mala actualización es restaurar la base de datos (más sobre esto abajo). Toma un pg_dump o un snapshot gestionado justo antes de actualizar, y confirma que sigues teniendo tu KEYRIGHT_KEK y tu KEYRIGHT_SIGNING_KEY en su almacén de secretos separado —la disciplina completa está en copia de seguridad y recuperación de una instancia de Keyright autoalojado. Una actualización sin una copia reciente es una puerta de un solo sentido.

2. Prueba en no-producción. Restaura una copia de producción en una base de datos de staging, apunta una instancia de staging a ella con la nueva etiqueta de imagen y déjala migrar. Aquí es donde una migración de esquema o bien se aplica limpiamente contra datos con forma real o te dice algo que quieres saber antes de que toque producción. Haz una prueba de humo de la instancia de staging (abajo) y solo entonces promueve la etiqueta.

3. Despliégala. Descarga la nueva etiqueta fijada y reinicia. En Docker Compose:

docker compose pull
docker compose up -d

Compose recrea el contenedor desde la nueva imagen; migra al arrancar y vuelve con el mismo KEYRIGHT_DB, KEYRIGHT_KEK y autolicencia. En Kubernetes con el chart de Helm, sube la etiqueta de imagen:

helm upgrade keyright delta1/keyright --reuse-values \
  --set image.tag=2.2.3

4. Verifica. Confirma que la nueva versión está activa y sigue licenciada (ver la sección de verificación abajo).

La guía de operaciones tiene esta misma secuencia como una lista de comprobación escueta que puedes pegar en un runbook.

Actualización progresiva con cero tiempo de inactividad

Si ya ejecutas dos o tres nodos para alta disponibilidad, una actualización deja de ser una caída. La app es sin estado y retrocompatible dentro de una línea menor, así que puedes actualizar una réplica cada vez mientras el balanceador de carga sigue sirviendo desde las demás.

El patrón es: saca un nodo del pool, vuélvelo a levantar con la nueva etiqueta, espera a que GET /health/ready pase, y pasa al siguiente. Como no hay afinidad de sesión —cualquier nodo puede responder cualquier petición— nada queda varado cuando un nodo sale del pool, y la concurrencia sigue siendo segura porque los puestos y los créditos usan un check-and-deduct serializable en Postgres sin importar qué nodo atienda la petición.

En Kubernetes esto es simplemente un RollingUpdate con la sonda de readiness apuntada a /health/ready:

# values.yaml
replicaCount: 3
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1   # una réplica cada vez
    maxSurge: 1
helm upgrade keyright delta1/keyright -f values.yaml --set image.tag=2.2.3

Kubernetes reemplaza un pod cada vez, cada pod nuevo ejecuta sus migraciones y solo se une al Service una vez que /health/ready está en verde, y los pods antiguos siguen sirviendo hasta que su reemplazo esté listo. Puedes seguirlo con kubectl rollout status deploy/keyright y pausar o deshacer el despliegue del Deployment a mitad si un pod nuevo nunca llega a estar listo —aunque ten en cuenta que deshacer el despliegue revierte los pods, no la base de datos, lo que importa para la historia del rollback de abajo.

Un despliegue de un solo nodo no obtiene esto gratis: docker compose up -d tiene una breve ventana de reinicio mientras el único contenedor se recrea y migra. Para un servidor de licencias eso suele estar bien, porque los clientes cachean un lease firmado y validan sin conexión entre activaciones, así que un reinicio corto lo absorbe su gracia —pero si quieres mantenimiento con cero tiempo de inactividad de verdad, ese es el argumento para ejecutar dos nodos.

Fija tus etiquetas de imagen

No uses latest flotante. Fija una versión concreta —image.tag=2.2.3 en Helm, una etiqueta explícita en tu archivo de Compose— para que lo que probaste en staging sea byte a byte lo que va a producción, y para que un pod reprogramado a las 3 de la madrugada no descargue en silencio una imagen más nueva que nunca validaste. Los despliegues reproducibles son la diferencia entre una actualización que realizaste y una que te ocurrió. La referencia de configuración cubre la fijación de etiquetas junto al resto de los valores de Helm; esa misma disciplina de fijación es la que hace reproducibles los traslados de imagen air-gapped cuando llevas un tarball a través del aislamiento.

Rollback: restaura la copia, no degrades

Aquí está la parte que hay que interiorizar. Las migraciones van hacia delante. Una nueva versión puede haber alterado el esquema al arrancar, y la imagen antigua no sabe ejecutarse contra ese esquema más nuevo. Así que no haces rollback apuntando la etiqueta de imagen antigua a una base de datos ya migrada —ese es el único movimiento que convierte una situación recuperable en una desastrosa.

El rollback admitido es:

  1. Restaura la copia de PostgreSQL que tomaste en el paso uno, devolviendo el esquema y los datos a su estado exacto previo a la actualización.
  2. Redespliega la etiqueta de imagen anterior contra la base de datos restaurada.

Como la imagen antigua y la base de datos restaurada (con esquema antiguo) coinciden, la instancia vuelve a levantarse directamente. Por esto exactamente la secuencia segura empieza con una copia y prueba en no-producción: quieres pillar una mala actualización en staging, y si alguna vez llega a producción, quieres un punto de restauración limpio en vez de un esquema que tengas que editar a mano. (En Kubernetes, helm rollback o kubectl rollout undo revierten los pods a la etiqueta antigua —útil si la nueva imagen simplemente no arranca—, pero no revierten la base de datos, así que acompáñalo de una restauración de la BD si una migración ya se ejecutó.)

Verifica después de actualizar

Tres comprobaciones confirman una buena actualización:

  • GET /health reporta la nueva version y devuelve 200 —la nueva imagen está activa y migrada.
  • GET /admin/self-license sigue reportando tu edición y una fase activa —Keyright es fail-closed, así que tiene que seguir habiendo una KEYRIGHT_SELF_LICENSE válida tras la actualización o cada petición de cliente devuelve 402. La clave no cambia entre actualizaciones; esta comprobación solo confirma que se arrastró y que la instancia está sirviendo, no bloqueada. (/admin/self-diagnostics da lo mismo en una sola llamada: versión, migraciones pendientes y fase de licencia.)
  • Un GET /v1/validate de prueba contra una licencia conocida devuelve un lease válido —prueba de que la clave de firma sigue produciendo leases que tus clientes aceptan de extremo a extremo.

Si las tres pasan, la actualización está hecha y sigues en la ruta de activación.

Dónde encaja esto

Las actualizaciones son la cuarta pieza de ejecutar Keyright autoalojado en producción, junto a la alta disponibilidad, la copia de seguridad y recuperación y la operación air-gapped. Como Keyright es un solo producto en ambos modos de despliegue, la forma de app-sin-estado-más-tu-base-de-datos —y por tanto toda esta historia de actualización— es idéntica ejecutes un nodo en un portátil o tres tras un balanceador de carga. Keyright autoalojado se licencia por despliegue entre Standard, Pro y Enterprise (precios); las actualizaciones progresivas con cero tiempo de inactividad requieren los dos o tres nodos que cubren Pro y Enterprise, pero la mecánica de migrar-al-arrancar y la disciplina de copia-primero son las mismas en cada nivel.

Prueba Nebula.NET

Endurece tu código .NET en minutos — empieza con la edición gratuita.