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 uno | Puede esperar a que duela |
|---|---|
| Correr tests en cada push | Matriz de cinco versiones de Python |
| Cachear dependencias | Builds de contenedor multi-arquitectura |
| Bloquear el merge si el CI falla | Entornos de preview por cada rama |
| Un secreto para el deploy | Gestor de secretos dedicado (Vault) |
| Deploy con un solo comando | Blue-green y despliegues canary |
| Rollback manual documentado | Rollback 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.