volver al blog

CI/CD para proyectos pequeños: lo justo para dormir tranquilo

devopsci-cd

El pipeline que no montaste también tiene coste

Hay una idea muy extendida de que CI/CD es cosa de equipos grandes. Que para un proyecto de una o dos personas es sobreingeniería, un yak que no toca afeitar todavía. Así que despliegas a mano: build en tu portátil, scp al servidor, cruzar los dedos.

El problema es que ese “no montar nada” tampoco es gratis. Se paga en despliegues de viernes por la tarde que rompen producción, en el test que llevabas dos semanas sin ejecutar, en el “en mi máquina funciona” que resulta ser una variable de entorno que solo existe en tu portátil. Esa factura no la ves, pero la pagas en madrugadas.

La buena noticia: para un proyecto pequeño no necesitas una plataforma. Necesitas lo justo. Y lo justo cabe en un archivo YAML que lees de una sentada.

Qué significa “lo justo”

Lo justo es el conjunto mínimo de comprobaciones automáticas que te dejan mergear y desplegar sin pararte a pensar. Ni más, ni menos. Cuatro trabajos cubren casi cualquier proyecto de tamaño humano:

Primero, lint y formato, para que las revisiones no se pierdan discutiendo comillas simples o dobles. Segundo, tests, aunque sean cuatro, porque un pipeline sin tests solo automatiza el desplegar rápido lo que está roto. Tercero, build, para descubrir en el CI y no en producción que ese import nuevo no existía en el requirements.txt. Y cuarto, deploy, disparado solo cuando lo anterior pasa en verde.

Ese es el suelo. Todo lo demás (matrices de diez versiones, escaneo de contenedores, entornos de preview por rama) es techo, y el techo se añade cuando duele algo concreto, no por si acaso.

Los cuatro trabajos, en un archivo

Aquí va un pipeline completo para un proyecto Python con GitHub Actions. No es un esqueleto de documentación: es lo que de verdad pongo en proyectos pequeños, comentado.

# .github/workflows/ci.yml
name: ci

on:
  push:
    branches: [main]      # el deploy solo sale de main
  pull_request:           # en las PR, validamos pero no desplegamos

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip        # cachear dependencias: de 90 s a 15 s

      - run: pip install -r requirements.txt

      - run: ruff check .    # lint y formato en un solo paso
      - run: pytest -q       # si esto falla, no hay deploy. Punto.

  deploy:
    needs: test              # la clave: deploy depende de que test pase
    if: github.ref == 'refs/heads/main'   # nunca desde una rama de PR
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Desplegar
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}  # secreto, no en el YAML
        run: ./scripts/deploy.sh

Fíjate en dos líneas que hacen casi todo el trabajo. needs: test es la que convierte esto en una red de seguridad de verdad: si los tests fallan, el deploy ni se lanza. Y el if con refs/heads/main es la que evita el susto clásico de desplegar desde una rama a medias. Con eso solo, ya duermes mejor.

Lo que sí, y lo que puede esperar

La tentación en CI/CD es copiar el pipeline de una empresa de 200 personas. No lo hagas. Para un proyecto pequeño, mucho de eso es coste sin retorno todavía.

Merece la pena desde el día unoPuede esperar a que duela
Correr tests en cada pushMatriz de cinco versiones de Python
Cachear dependenciasBuilds de contenedor multi-arquitectura
Bloquear el merge si el CI fallaEntornos de preview por cada rama
Un secreto para el deployGestor de secretos dedicado (Vault)
Deploy con un solo comandoBlue-green y despliegues canary
Rollback manual documentadoRollback automático por métricas

La regla es sencilla: añades una pieza cuando puedes nombrar el problema que resuelve. “Por si algún día escalamos” no es un problema, es una excusa para tres horas de YAML que no vas a mantener.

Mantén el deploy aburrido

El paso de despliegue es donde más gente se complica. La mejor versión de deploy.sh en un proyecto pequeño es la más aburrida: idempotente, repetible y legible en treinta segundos.

Sea rsync a un VPS, un push a un contenedor gestionado o un firebase deploy, dos propiedades importan por encima del resto. Que puedas ejecutarlo dos veces seguidas sin romper nada, y que volver atrás sea un comando que ya tienes escrito, no una arqueología a las tres de la mañana. Si tu plan de rollback es “vuelvo a hacer deploy del commit anterior”, perfecto, pero tenlo apuntado antes de necesitarlo.

Un detalle que ahorra disgustos: haz que el deploy falle ruidoso. Si el script no puede subir algo, que devuelva un código de salida distinto de cero y tiña el pipeline de rojo. Un deploy que falla en silencio es peor que no tener deploy, porque te da una falsa sensación de que todo fue bien.

Secretos: lo mínimo bien hecho

No hace falta un gestor de secretos para empezar, pero sí hace falta no meter la pata con lo básico. Nada de tokens en el YAML ni en el código; van en los secretos del repositorio (Settings → Secrets) y se leen por variable de entorno, como en el ejemplo de arriba.

Dos hábitos más que cuestan poco y evitan sustos. Da a cada token el permiso mínimo que necesita: un PAT que solo despliega no tiene por qué poder borrar el repositorio. Y rota los secretos cuando alguien deja el proyecto o cuando sospechas de una fuga, sin dramatizar pero sin dejarlo para nunca. Con eso cubres el 90 % del riesgo real de un proyecto pequeño.

Por dónde empezar mañana

No intentes tener el pipeline perfecto a la primera. Empieza por lo que corta más hemorragias con menos esfuerzo.

Crea .github/workflows/ci.yml con un solo trabajo que instale dependencias y corra los tests en cada push. Diez líneas. En cuanto lo veas verde un par de veces, activa la protección de rama para que no se pueda mergear a main con el CI en rojo. Solo entonces añade el trabajo de deploy con su needs y su if. Y ahí paras, hasta que un problema concreto te pida la siguiente pieza.

CI/CD en un proyecto pequeño no va de imitar a Google. Va de automatizar las tres o cuatro comprobaciones que ya haces a mano y siempre acabas olvidando justo el día que importa. Veinte líneas de YAML no te hacen sofisticado. Te hacen alguien que despliega un viernes sin que se le acelere el pulso, y eso vale más que cualquier diagrama de arquitectura.