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
needssolo para dependencias reales. - Ignorar el cache: No cachear dependencias, lo que aumenta el tiempo de ejecución. Solución: Usa
actions/cachepara 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
- He definido un trigger adecuado (push, pull request) para mi workflow.
- He organizado jobs en etapas logicas: lint, test, build, deploy.
- Uso GitHub Secrets para manejar credenciales de forma segura.
- He configurado dependencias entre jobs usando
needspara optimizar el flujo. - Incluyo cache de dependencias para acelerar ejecuciones.
- Tengo un plan de rollback o aprobacion manual para despliegues a produccion.
- 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:
- Crea un nuevo repositorio en GitHub llamado mi-pipeline-cicd.
- Inicializa un proyecto Node.js simple con un archivo
index.jsque contenga un servidor Express y un test unitario usando Jest. - En la raíz del repositorio, crea un archivo
.github/workflows/pipeline.yml. - 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).
- Configura los jobs para que se ejecuten en secuencia: test debe pasar antes de build, y build antes de deploy-staging.
- Añade un trigger para que el pipeline se ejecute en cada push a la rama main.
- Usa GitHub Secrets si necesitas credenciales (p.ej., para un despliegue real), o simula con un echo en el deploy.
- Ejecuta el pipeline haciendo un push a main y verifica que todos los jobs pasen.
- 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.