Diseña la arquitectura de tu pipeline CI/CD

Lectura
20 min~5 min lectura

Concepto clave

Diseñar la arquitectura de un pipeline CI/CD es como planificar una línea de montaje en una fábrica moderna. En lugar de piezas físicas, procesas código, pruebas y despliegues de manera automatizada. Un pipeline es una secuencia de etapas que transforma tu código fuente en una aplicación desplegada, con validaciones en cada paso para garantizar calidad y seguridad. La arquitectura define cómo fluye este proceso, qué herramientas se usan y cómo se manejan los errores.

En el contexto de GitHub Actions, la arquitectura se materializa en archivos YAML que describen workflows, jobs y steps. Un workflow es el proceso completo, los jobs son tareas paralelas o secuenciales (como build, test y deploy), y los steps son acciones individuales dentro de un job. Pensar en arquitectura te ayuda a evitar cuellos de botella, como pruebas lentas que retrasan el despliegue, y a crear pipelines escalables que crecen con tu aplicación.

Cómo funciona en la práctica

Imagina una aplicación web moderna con frontend en React y backend en Node.js. Tu pipeline debe manejar ambos componentes. Primero, define las etapas clave: 1) Build - compilar el código, 2) Test - ejecutar pruebas unitarias y de integración, 3) Deploy - desplegar en un entorno de staging o producción. En GitHub Actions, esto se traduce en un workflow que se dispara en eventos como push a main o pull request.

Paso a paso: Crea un archivo .github/workflows/ci-cd.yml. Configura el trigger para que se ejecute en push a la rama main. Define jobs: uno para build y test del frontend, otro para el backend, y un job de deploy que dependa de que ambos pasen. Usa acciones predefinidas de GitHub Marketplace, como actions/setup-node, para agilizar el setup. Asegúrate de que los jobs compartan artefactos, como el código compilado, usando actions/upload-artifact y actions/download-artifact.

Codigo en accion

Aquí tienes un ejemplo funcional de un pipeline básico para una aplicación Node.js. Este workflow hace build, test y deploy a un entorno de staging en Heroku.

name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
    - name: Install dependencies
      run: npm ci
    - name: Run tests
      run: npm test
    - name: Build application
      run: npm run build
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: app-build
        path: build/

  deploy-staging:
    runs-on: ubuntu-latest
    needs: build-and-test
    if: github.ref == 'refs/heads/main'
    steps:
    - name: Download artifacts
      uses: actions/download-artifact@v3
      with:
        name: app-build
    - name: Deploy to Heroku
      uses: akhileshns/[email protected]
      with:
        heroku_api_key: ${{secrets.HEROKU_API_KEY}}
        heroku_app_name: "myapp-staging"
        heroku_email: ${{secrets.HEROKU_EMAIL}}

Ahora, mejora este pipeline añadiendo un job para linting y otro para pruebas de integración. Esto muestra el "antes y después" de refactorizar para mayor robustez.

name: Enhanced CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: '18'
    - run: npm ci
    - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: '18'
    - run: npm ci
    - run: npm test
    - run: npm run test:integration

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: '18'
    - run: npm ci
    - run: npm run build
    - uses: actions/upload-artifact@v3
      with:
        name: app-build
        path: build/

  deploy-staging:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    steps:
    - uses: actions/download-artifact@v3
      with:
        name: app-build
    - uses: akhileshns/[email protected]
      with:
        heroku_api_key: ${{secrets.HEROKU_API_KEY}}
        heroku_app_name: "myapp-staging"
        heroku_email: ${{secrets.HEROKU_EMAIL}}

Errores comunes

  • No usar secrets de forma segura: Exponer claves API en el código. Solución: Usa GitHub Secrets para almacenar credenciales y referenciarlas con ${{secrets.NOMBRE}}.
  • Jobs bloqueantes innecesarios: Hacer que todos los jobs se ejecuten en serie, ralentizando el pipeline. Solución: Paraleliza jobs independientes, como lint y test unitario, usando needs solo para dependencias reales.
  • Ignorar el cache: No cachear dependencias, lo que aumenta el tiempo de ejecución. Solución: Usa actions/cache para almacenar node_modules o otros archivos recurrentes.
  • Despliegues sin rollback: Desplegar directamente a producción sin plan de contingencia. Solución: Implementa un job de deploy con aprobación manual y configura rollback automático en caso de fallo.
  • No probar en entorno similar a producción: Ejecutar pruebas solo en entornos de desarrollo. Solución: Usa contenedores Docker o servicios como GitHub Actions para simular producción en etapas de test.

Checklist de dominio

  1. He definido un trigger adecuado (push, pull request) para mi workflow.
  2. He organizado jobs en etapas logicas: lint, test, build, deploy.
  3. Uso GitHub Secrets para manejar credenciales de forma segura.
  4. He configurado dependencias entre jobs usando needs para optimizar el flujo.
  5. Incluyo cache de dependencias para acelerar ejecuciones.
  6. Tengo un plan de rollback o aprobacion manual para despliegues a produccion.
  7. He probado el pipeline en un repositorio real y verificado que pasa todas las etapas.

Diseña y ejecuta un pipeline CI/CD para una app simple

En este ejercicio, crearás un pipeline CI/CD desde cero para una aplicación web básica. Sigue estos pasos:

  1. Crea un nuevo repositorio en GitHub llamado mi-pipeline-cicd.
  2. Inicializa un proyecto Node.js simple con un archivo index.js que contenga un servidor Express y un test unitario usando Jest.
  3. En la raíz del repositorio, crea un archivo .github/workflows/pipeline.yml.
  4. Diseña el pipeline con tres jobs: test (ejecuta pruebas), build (crea un artefacto), y deploy-staging (simula despliegue subiendo a GitHub Pages o mostrando un log).
  5. Configura los jobs para que se ejecuten en secuencia: test debe pasar antes de build, y build antes de deploy-staging.
  6. Añade un trigger para que el pipeline se ejecute en cada push a la rama main.
  7. Usa GitHub Secrets si necesitas credenciales (p.ej., para un despliegue real), o simula con un echo en el deploy.
  8. Ejecuta el pipeline haciendo un push a main y verifica que todos los jobs pasen.
Pistas
  • Usa actions/setup-node@v3 para configurar Node.js en los jobs.
  • Para simular deploy, puedes usar un step con run: echo 'Desplegando a staging...' en lugar de una acción real.
  • Asegúrate de que el job de deploy-staging tenga needs: [build] para depender del job anterior.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.