Pipeline CI/CD explicado: del código a producción paso a paso
Hice push a main un viernes por la tarde. Sin tests, sin staging, sin nada. Solo git push origin main y un script de despliegue que se ejecutaba con cada merge. Cerré la laptop, manejé a casa, y empecé a preparar pasta.
Para cuando el agua estaba hirviendo, mi teléfono no paraba de vibrar. Slack. PagerDuty. Un mensaje de mi jefe que solo decía “el sitio está caído.” Pasé las siguientes cuatro horas haciendo rollback de un cambio CSS de tres líneas que de alguna manera rompió el formulario de login en producción. Un viernes por la noche. Con pasta fría.
Esa fue la noche en que decidí aprender lo que un pipeline CI/CD realmente es, en lugar de fingir que mi script de despliegue era uno.
CI vs CD vs CD (sí, hay dos CDs)
La sopa de acrónimos confunde a todo el mundo. Voy a desenredarla.
Integración Continua (CI) es la práctica de mergear código en una rama compartida frecuentemente — varias veces al día, idealmente — y ejecutar verificaciones automatizadas cada vez. Tests, linting, escaneos de seguridad, lo que tu equipo considere importante. El punto es detectar problemas temprano, cuando el cambio es pequeño y el contexto todavía está fresco en tu cabeza.
Antes de CI, los equipos desarrollaban en aislamiento durante semanas y luego mergeaban todo de golpe. Ese día de merge siempre era un desastre. CI hace que el dolor sea pequeño y continuo en lugar de grande y catastrófico. Cortecitos de papel en vez de fracturas expuestas.
Entrega Continua (CD #1) significa que tu código siempre está en un estado desplegable. Cada commit que pasa el pipeline podría ir a producción. Pero un humano todavía presiona el botón. Tienes un candidato de release esperando ahí, testeado y empaquetado, hasta que alguien diga “adelante.”
Despliegue Continuo (CD #2) elimina al humano. Cada commit que pasa todas las verificaciones va directo a producción automáticamente. Sin botón. Sin espera. ¿Da miedo? Un poco. Pero si tus tests son sólidos, en realidad es menos riesgoso que acumular dos semanas de cambios y desplegarlos todos a la vez mientras cruzas los dedos.
La mayoría de los equipos empiezan con CI, agregan Entrega Continua, y solo pasan a Despliegue Continuo cuando confían en su suite de tests. Esa confianza toma tiempo. Y así debe ser.
Un pipeline en español simple
Quita las herramientas y un pipeline es solo una serie de pasos automatizados por los que pasa tu código entre “lo escribí” y “los usuarios lo ven.” Este es el recorrido:
1. Commit. Haces push de código a un repositorio. Git lo recoge. Este es el disparador — el pistoletazo de salida.
2. Build. El pipeline compila tu código, instala dependencias, empaqueta assets. Lo que sea que “preparar el código” signifique para tu stack. Para una app Node, es npm install y quizás un build de webpack. Para Go, es go build. Si este paso falla, nada más se ejecuta. No tiene sentido testear código que no compila.
3. Test. Tests unitarios primero — rápidos, aislados, cubriendo funciones individuales. Después tests de integración — verificando que los componentes se comuniquen correctamente. Quizás tests end-to-end si los tienes. El pipeline se detiene en el primer fallo. Esta es la red de seguridad. Esto es lo que habría atrapado mi desastre del viernes.
4. Verificaciones de calidad. Linting, formateo de código, escaneo de seguridad, quizás un umbral de cobertura de tests. Algunos equipos bloquean en todo. Otros eligen los que más les importan. El punto es la consistencia — estas verificaciones se ejecutan cada vez, no solo cuando alguien se acuerda.
5. Despliegue a staging. Si todo pasa, el código aterriza en un entorno que replica producción. Aquí es donde atrapas lo que los tests automatizados no detectan — bugs visuales, problemas de rendimiento, casos raros que solo aparecen con datos casi reales.
6. Despliegue a producción. El paso final. O un humano lo aprueba (Entrega Continua) o sucede automáticamente (Despliegue Continuo). De cualquier forma, el código ya está en vivo.
Eso es todo. Seis pasos. Todos los sistemas CI/CD del mundo son alguna variación de esta secuencia, con pasos extra añadidos según las necesidades del equipo.
Un ejemplo real con GitHub Actions
La teoría está bien. Déjame mostrarte cómo se ve en la práctica. Aquí tienes un workflow de GitHub Actions para una app Node.js — el tipo de archivo que pondrías en .github/workflows/ci.yml:
name: Pipeline CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Build
run: npm run build
deploy:
needs: build-and-test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to production
run: ./scripts/deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
Te lo explico.
El bloque on define los disparadores. Este pipeline se ejecuta con cada push a main y cada pull request que apunte a main. Los pull requests pasan por el build y los tests — sabes si tu código está roto antes de mergear. Los pushes a main tienen el pipeline completo, despliegue incluido.
build-and-test es un job. Corre en una máquina Ubuntu nueva. Los pasos se ejecutan en orden: clonar el repo, configurar Node, instalar dependencias con npm ci (instalaciones deterministas, no npm install), lint, test, build. Si un paso falla, todo el job falla.
deploy es un job separado que solo corre después de que build-and-test tenga éxito (needs: build-and-test). La condición if lo restringe a pushes en main — los pull requests no disparan despliegues. El script de despliegue usa un token secreto almacenado en los secrets de GitHub, nunca en texto plano en el código.
Treinta líneas de YAML. Es suficiente para atrapar la mayoría de los problemas catastróficos. Mi desastre de la pasta del viernes se habría detenido en el paso de tests, y habría recibido una marca roja en mi pull request en vez de una alerta de PagerDuty durante la cena.
Herramientas comunes (elige una, apréndela bien)
El mercado de herramientas CI/CD está abarrotado. Estas son las que importan:
GitHub Actions. Integrado en GitHub. Gratis para repos públicos, free tier generoso para privados. Si tu código ya está en GitHub, empieza aquí. El ecosistema de acciones pre-construidas es enorme, y la sintaxis YAML es clara una vez que superas la curva de aprendizaje inicial.
GitLab CI/CD. Integrado en GitLab. Misma idea, formato YAML diferente. Si tu equipo usa GitLab, no pelees contra eso. El CI de GitLab es genuinamente bueno — algunos argumentarían que mejor que GitHub Actions para pipelines complejos.
Jenkins. La vieja guardia. Open source, auto-hospedado, infinitamente configurable. También infinitamente frustrante de mantener. Jenkins puede hacer cualquier cosa, pero requiere más trabajo para configurarlo y mantenerlo. He visto servidores Jenkins tratados como mascotas — con nombre, mimados, temidos. Si tu empresa ya usa Jenkins, aprenderás Jenkins. Si empiezas de cero, elige algo hospedado.
CircleCI. Hospedado en la nube, interfaz limpia, buen soporte para Docker. Popular entre startups. Hace el trabajo sin complicaciones.
Honestamente, la herramienta importa menos de lo que piensas. Los conceptos se transfieren. He usado las cuatro, y el modelo mental es el mismo en todas partes: disparador, build, test, despliegue. El YAML es diferente. Los dashboards son diferentes. El ciclo central es idéntico.
Si estás aprendiendo, usa GitHub Actions. Es gratis, es donde viven la mayoría de los proyectos open source, y tendrás algo funcionando en menos de una hora.
Anti-patrones de pipelines (aprende de mis errores)
He construido malos pipelines. Más de los que me gustaría admitir. Esto es lo que aprendí por las malas.
Sin tests en el pipeline. Un pipeline que solo hace build y despliega es un script de FTP glorificado. El objetivo es atrapar problemas antes de producción. Si tu pipeline no ejecuta tests, no es un pipeline CI/CD. Es imprudencia automatizada.
Tests que tardan 45 minutos. Trabajé en un proyecto donde la suite de tests tardaba casi una hora. La gente empezó a hacer push sin esperar resultados. Mergeaban PRs con una actitud de “seguro que está bien”, y no estaba bien. Si tu pipeline es demasiado lento, la gente lo va a rodear. Optimiza los tests lentos. Paraleliza. Ejecuta los rápidos primero para fallar temprano.
Desplegar el viernes por la tarde. Ya te conté esta historia. No despliegues el viernes. O hazlo, pero solo si tienes una estrategia de rollback sólida y nada planeado para la noche. Y tal vez ni así.
Secrets en el repo. He visto API keys commiteadas en .github/workflows/ci.yml en texto plano. Una vez. Ese repo era público. La key era de un servicio de pago. Te imaginas cómo terminó eso. Usa la gestión de secrets de tu herramienta CI. Todas la tienen.
Ignorar tests inestables. Un test que pasa el 90% de las veces no es un test. Es un generador de números aleatorios que ocasionalmente te dice que tu código está roto. Arregla los tests inestables inmediatamente o elimínalos. No vuelvas a ejecutar el pipeline hasta que pase en verde — eso le enseña a tu equipo a desconfiar de todo el sistema.
Sin entorno de staging. Desplegar directamente de “los tests pasan” a producción es audaz. A veces demasiado. Un entorno de staging atrapa lo que los tests no detectan. Bugs de layout. Regresiones de rendimiento. Esa cosa rara que solo pasa cuando la base de datos tiene más de diez mil filas.
Tu primer pipeline: paso a paso
Si nunca has configurado un pipeline, así es como empezar. Veinte minutos, máximo.
-
Crea un repositorio en GitHub con un proyecto simple. Una app Node.js con algunos tests, un script Python con pytest, lo que sea tu stack. La app no importa. El pipeline sí.
-
Crea el archivo de workflow. Haz un directorio
.github/workflows/en tu repo. Agrega un archivo llamadoci.yml. Pega el ejemplo de arriba, ajustado para tu lenguaje. -
Haz push. Commit y push. Ve a la pestaña “Actions” en tu repo de GitHub. Míralo ejecutarse. Hay algo satisfactorio en ver esas marcas verdes aparecer una por una. Y algo útil en ver una X roja cuando rompes un test a propósito.
-
Rompe algo a propósito. Escribe un test que falle. Haz push. Mira cómo el pipeline lo atrapa. Este es el momento en que hace clic — el pipeline es tu red de seguridad, no un obstáculo burocrático.
-
Agrega un paso de despliegue. Aunque solo haga un echo de “Deploying…” por ahora. La estructura importa. Después, vas a reemplazar ese echo con un comando de despliegue real.
-
Configura la protección de rama. En los ajustes de tu repo, exige que el check de CI pase antes de mergear pull requests. Aquí es donde el pipeline pasa de “estaría bien tenerlo” a “realmente se aplica.”
Eso es un pipeline CI/CD funcional. Es básico, pero es real. A partir de aquí, agregas complejidad según la necesites — caché de dependencias para acelerar, builds en matriz para testear en múltiples versiones, despliegue a entornos cloud. Si vas rumbo a la infraestructura cloud, nuestra guía para aprender cloud computing desde cero cubre las bases que necesitarás para despliegues en producción.
Pero el esqueleto siempre es el mismo: disparador, build, test, despliegue.
Dónde encaja CI/CD en el panorama general
CI/CD no existe en el vacío. Es una pieza de un ecosistema más amplio. Herramientas de Infrastructure as Code como Terraform definen dónde corre tu código. La orquestación de contenedores con Kubernetes gestiona cómo escala. Herramientas de monitoreo como Prometheus te dicen si realmente está funcionando después del despliegue.
Si estás pensando en certificaciones para formalizar estos conocimientos, nuestra ruta de certificación cloud puede ayudarte a decidir qué camino tiene sentido para donde estás ahora.
Pero CI/CD es la pieza que conecta todo el workflow. Sin él, todo lo demás es manual. Con él, entregas más rápido y duermes mejor. Literalmente. Yo duermo mejor ahora que tengo pipelines. Viernes por la noche incluidos.
FAQ
¿Necesito saber Docker para usar CI/CD?
No. Docker es común en los pipelines — la mayoría de los runners CI usan contenedores por detrás — pero no necesitas entender Docker para configurar un pipeline básico. GitHub Actions, por ejemplo, maneja la parte de contenedores por ti. Solo escribes tus pasos y los ejecuta. Dicho esto, cuando empieces a construir pipelines más complejos con entornos personalizados, el conocimiento de Docker se vuelve genuinamente útil.
¿Cuál es la diferencia entre CI/CD y DevOps?
DevOps es la cultura más amplia y el conjunto de prácticas alrededor de la colaboración entre desarrollo y operaciones. CI/CD es una práctica técnica específica dentro de eso. Puedes hacer CI/CD sin llamarte equipo DevOps, y puedes decir que eres un equipo DevOps sin tener CI/CD — aunque no recomendaría esto último.
¿Cuánto debería tardar un pipeline?
Menos de diez minutos es el objetivo. Menos de cinco es ideal. Una vez que pasas de quince minutos, los desarrolladores empiezan a cambiar de contexto mientras esperan, y eso mata el impulso. Si tu pipeline es lento, mira la paralelización de tests, el caché de dependencias, y ejecuta la suite completa solo en main mientras los PRs tienen un subconjunto más rápido.
¿Puedo usar CI/CD para proyectos personales?
Totalmente. Lo uso para todo, incluso proyectos personales pequeños. Toma cinco minutos configurarlo y te salva del problema de “funciona en mi máquina” para siempre. Además, tener CI/CD en tus repos personales se ve bien en un CV. Demuestra que te importa la calidad del código incluso cuando nadie está mirando.
¿Listo para estructurar tu aprendizaje? Descubre SkillRealm Learn —>