Deployments Canary con TypeScript: lanzamiento sin problemas y sin miedo a romper producción

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué todavía tienes miedo de presionar "Deploy"?

\n\n

Escribiste el código. Lo probaste en tu máquina local. Las pruebas pasaron. Todo perfecto. Presionas el tan esperado botón Deploy... y después de 5 minutos ves cómo aparece el error 500, y los usuarios en pánico escriben al soporte. ¿Te suena familiar?

\n\n

Las estrategias de despliegue tradicionales (blue-green, rolling update) son buenas, pero tienen un inconveniente: o incluyen todo el código nuevo de una vez, o no lo incluyen en absoluto. ¿Y si pudieras enviar una nueva funcionalidad solo al 1% de los usuarios, observar las métricas, y solo después, asegurándote de la estabilidad, liberarla al 100%?

\n\n

Así es exactamente como funcionan los canary deployments (lanzamientos canary). El nombre proviene de una antigua práctica minera: llevar un canario a la mina para detectar a tiempo una fuga de gas. Si el pájaro se callaba, los mineros sabían: era hora de subir. En el mundo de la TI, el "canario" es un pequeño grupo de usuarios en los que se prueba el nuevo código. Si todo va bien, el lanzamiento continúa. Si no, reviertes más rápido de lo que dices "hotfix".

\n\n

En este artículo, escribiremos un sistema completo de canary deployment en TypeScript. Aprenderás cómo configurar el balanceo de tráfico, cómo automatizar el proceso a través de CI/CD y cómo monitorear la "salud" de tu canario. ¡Vamos allá!

\n\n

¿Qué es un Canary Deployment y por qué es necesario?

\n\n

Canary deployment es una estrategia de lanzamiento de nuevo código en la que la versión actualizada de la aplicación se envía primero a un pequeño porcentaje de usuarios (generalmente del 1 al 10%). El resto continúa trabajando con la versión anterior y estable. Si la nueva versión no presenta problemas (errores, caídas de rendimiento, aumento de latencia), aumentas gradualmente el porcentaje de tráfico hacia ella hasta que reemplace por completo a la anterior.

\n\n

Ventajas clave:

\n
    \n
  • Minimización de riesgos — los errores afectan solo a una pequeña parte de la audiencia.
  • \n
  • Reversión rápida — basta con redirigir el tráfico de vuelta a la versión estable.
  • \n
  • Pruebas A/B en condiciones reales — puedes comparar las métricas de la versión antigua y la nueva.
  • \n
  • Despliegue gradual — no sobrecargas el servidor con un aumento repentino de carga.
  • \n
\n\n

Ahora pasemos de la teoría a la práctica. Construiremos un sistema que consta de tres partes:

\n
    \n
  1. Backend en TypeScript (Express.js).
  2. \n
  3. Balanceador de tráfico en Nginx.
  4. \n
  5. Automatización a través de GitHub Actions.
  6. \n
\n\n

Paso 1. Escribir una aplicación en TypeScript con soporte de versionado

\n\n

Para empezar, crearemos una aplicación Express simple que pueda funcionar en dos modos: stable y canary. La diferencia estará solo en la respuesta al endpoint raíz, pero en un proyecto real podría ser cualquier nueva funcionalidad.

\n\n
// src/app.ts\nimport express, { Request, Response } from 'express';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\nconst VERSION = process.env.VERSION || 'stable'; // 'stable' o 'canary'\n\napp.get('/', (req: Request, res: Response) => {\n  res.json({\n    message: 'Hello from API!',\n    version: VERSION,\n    timestamp: new Date().toISOString(),\n  });\n});\n\n// Endpoint para health check\napp.get('/health', (req: Request, res: Response) => {\n  res.status(200).send('OK');\n});\n\napp.listen(PORT, () => {\n  console.log(`Server running on port ${PORT} in ${VERSION} mode`);\n});\n
\n\n

Ahora crearemos un Dockerfile para empaquetar la aplicación en un contenedor. Esto simplificará el despliegue y el balanceo.

\n\n
# Dockerfile\nFROM node:18-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\nCOPY . .\nRUN npm run build\n\nFROM node:18-alpine AS runner\nWORK                

Blogs

Book Recommendations