Marcio Cunha

Pipelines CI/CD con GitHub Actions, Docker Multi-Stage y Despliegue Sin Interrupción

Aprender a construir pipelines CI/CD modernas es crucial para entregas de software ágiles y confiables. Este artículo detalla cómo integrar GitHub Actions para la automatización, optimizar imágenes Docker con builds multi-stage e implementar estrategias de despliegue sin interrupción (zero-downtime) para asegurar la continuidad del servicio. Comprenda los conceptos, trade-offs y pasos prácticos para elevar su entrega continua.

Marcio Cunha•3 min
También disponible en:EnglishPortuguês
Resumen
  • La Integración Continua (CI) automatiza las pruebas de código con cada cambio, identificando problemas tempranamente y asegurando la salud del proyecto.
  • Las imágenes Docker multi-stage optimizan el tamaño y la seguridad de los contenedores, separando las dependencias de construcción de las de tiempo de ejecución.
  • GitHub Actions facilita la automatización de todo el ciclo CI/CD, desde la compilación y prueba hasta la construcción y envío de imágenes Docker a un registro.
  • El despliegue sin interrupción (zero-downtime) se logra mediante estrategias como las actualizaciones continuas, que reemplazan versiones antiguas sin detener el servicio.
  • La implementación de una pipeline CI/CD robusta con estas tecnologías se traduce en entregas más rápidas, menor riesgo de fallas y mayor satisfacción del usuario.

¿Qué Significa CI/CD en el Mundo del Software Actual?

En el panorama actual del desarrollo de software, la entrega continua de valor es más que un diferenciador; es una expectativa. Aquí es donde entran los conceptos de CI/CD, que representan la Integración Continua (CI) y la Entrega Continua o Despliegue Continuo (CD). En la práctica, CI es un proceso que implica la integración y prueba de código de forma automática y frecuente. Cada vez que un desarrollador envía ('hace commit') un cambio al repositorio central, la integración continua activa una serie de pruebas automatizadas para asegurar que el nuevo código no ha roto funcionalidades existentes.

Por otro lado, CD, o entrega continua, extiende CI al automatizar el proceso de llevar todos los cambios de código a un entorno de prueba o de producción después de una fase de integración exitosa. Si se trata de despliegue continuo, el código se despliega automáticamente en producción. El objetivo principal es hacer que el proceso de lanzamiento de software sea más rápido, más seguro y más confiable, minimizando errores manuales y asegurando que el software esté siempre en un estado listo para ser entregado a los usuarios.

Construyendo la Base con GitHub Actions para CI

GitHub Actions es una plataforma de automatización que permite a los desarrolladores crear flujos de trabajo personalizados (workflows) directamente en sus repositorios de GitHub. Estos workflows se pueden configurar para reaccionar a eventos específicos, como un nuevo commit o la apertura de un 'pull request', y ejecutar una serie de tareas, como compilar código, ejecutar pruebas unitarias y de integración, e incluso desplegar aplicaciones. La gran ventaja es que reside junto al código fuente, haciendo que la gestión de la automatización sea una parte integral del proyecto.

Para configurar la Integración Continua, primero definimos un archivo YAML en la carpeta .github/workflows/ de nuestro proyecto. Este archivo describe los 'jobs' (tareas) y 'steps' (pasos) que se ejecutarán. Por ejemplo, para una aplicación Node.js, un workflow de CI puede incluir pasos para instalar dependencias, ejecutar pruebas y verificar la calidad del código. Con esto, cualquier nuevo cambio en el código se valida automáticamente, proporcionando retroalimentación rápida al equipo sobre la salud del proyecto.

name: CI de la Aplicación Node.js

on: [push, pull_request]

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout del código
uses: actions/checkout@v3

- name: Configurar Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Instalar dependencias
run: npm ci

- name: Ejecutar pruebas
run: npm test

- name: Linter de código
run: npm run lint

Optimización de Imágenes Docker con Builds Multi-Stage

Docker revolucionó la forma en que empaquetamos y ejecutamos aplicaciones, aislándolas en contenedores que incluyen todo lo necesario para funcionar: código, entorno de ejecución, bibliotecas y configuraciones. Sin embargo, los primeros enfoques para crear imágenes Docker a menudo resultaban en imágenes voluminosas, que contenían herramientas de construcción y dependencias de desarrollo que no eran necesarias en producción, aumentando la superficie de ataque y el tiempo de descarga.

Los builds multi-stage, o construcciones en múltiples etapas, resuelven este problema de manera elegante. Permiten usar múltiples instrucciones FROM en su Dockerfile, donde cada FROM puede usar una imagen base diferente. Cada instrucción FROM inicia una nueva etapa de construcción, y se pueden copiar artefactos de una etapa a otra. Esto significa que las herramientas de compilación (como compiladores de C++ o SDKs de lenguajes) se mantienen en una etapa temporal y solo los artefactos esenciales (el binario compilado o el código interpretado) se copian a la imagen final de producción, que puede ser una imagen base minimalista. Esto resulta en imágenes de contenedor mucho más pequeñas, seguras y eficientes.

# Etapa 1: Construcción (entorno de construcción)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Etapa 2: Producción (entorno de ejecución)
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD [