Juan Diego Andrés PRADA··RAMÍREZ Entrar
Lección 4 de 7
Contenido de la lección 10 tramos

CI/CD con GitHub Actions

¿Qué es?

CI/CD son dos siglas que van juntas. CI (Integración Continua) significa que cada vez que subes código, un robot lo descarga, instala dependencias y corre tus pruebas automáticamente. CD (Entrega/Despliegue Continuo) significa que, si esas pruebas pasan, ese mismo robot construye la imagen y la lleva a producción sin que tú toques nada. GitHub Actions es el motor que usaremos: ejecuta tareas (workflows) en respuesta a eventos de tu repositorio, como un push o un Pull Request.

¿Cómo funciona?

Defines un archivo YAML dentro de .github/workflows/. Ese archivo describe:

  • un evento disparador (on:) — por ejemplo, "cuando alguien haga push a main";
  • uno o más trabajos (jobs:) que corren en máquinas virtuales limpias que GitHub te presta gratis (los runners);
  • pasos (steps:) dentro de cada trabajo: descargar el código, instalar Python, correr pruebas, construir la imagen, desplegar.

Cuando ocurre el evento, GitHub arranca un runner desde cero, ejecuta los pasos en orden y te muestra en verde o rojo si todo salió bien. Si un paso falla, los siguientes no se ejecutan. Los secretos (contraseñas, llaves SSH) se guardan cifrados en GitHub y se inyectan como variables sin aparecer nunca en los logs.

¿Para qué sirve?

Sirve para que nadie pueda romper main sin enterarse, para no depender de "el que sabe desplegar" y para que pasar a producción sea tan simple como hacer merge. En este curso es el pegamento del despliegue: conecta lo que dockerizamos con el servidor que configuraremos después. Cuando termines este módulo, cada push a main probará tu API, construirá la imagen y la subirá a un registro, lista para desplegarse.

Pieza del despliegue que construye este módulo

Construimos dos workflows: uno de CI que corre las pruebas en cada Pull Request, y uno de CD que, al hacer merge a main, construye la imagen Docker y la publica en GitHub Container Registry (GHCR).

Paso 1: una prueba que el robot pueda correr

# tests/test_api.py
from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

def test_saludo():
 respuesta = client.get("/saludo")
 assert respuesta.status_code == 200
 assert respuesta.json() == {"mensaje": "Hola desde el contenedor"}

def test_health():
 assert client.get("/health").status_code == 200

Agrega pytest==8.2.0 y httpx==0.27.0 a un requirements-dev.txt.

Paso 2: workflow de CI (pruebas en cada Pull Request)

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

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

jobs:
 pruebas:
 runs-on: ubuntu-latest
 steps:
 - name: Descargar el código
 uses: actions/checkout@v4

 - name: Instalar Python
 uses: actions/setup-python@v5
 with:
 python-version: "3.12"

 - name: Instalar dependencias
 run: |
 pip install -r requirements.txt
 pip install -r requirements-dev.txt

 - name: Correr pruebas
 run: pytest -v

Fija siempre las acciones a una versión mayor (@v4), no a una rama. Una etiqueta como @main puede cambiar bajo tus pies y romper tu pipeline sin que tú hayas tocado nada.

Paso 3: workflow de CD (construir y publicar la imagen al hacer merge)

# .github/workflows/cd.yml
name: CD

on:
 push:
 branches: [main]

jobs:
 construir-y-publicar:
 runs-on: ubuntu-latest
 permissions:
 contents: read
 packages: write # necesario para publicar en GHCR
 steps:
 - uses: actions/checkout@v4

 - name: Iniciar sesión en GHCR
 uses: docker/login-action@v3
 with:
 registry: ghcr.io
 username: ${{ github.actor }}
 password: ${{ secrets.GITHUB_TOKEN }} # token que GitHub provee solo

 - name: Construir y subir imagen
 uses: docker/build-push-action@v6
 with:
 context: .
 push: true
 tags: |
 ghcr.io/${{ github.repository }}:latest
 ghcr.io/${{ github.repository }}:${{ github.sha }}

El tag con ${{ github.sha }} etiqueta la imagen con el hash exacto del commit, así siempre sabes qué versión está corriendo en producción.

Nunca escribas contraseñas o llaves directamente en el YAML. Cualquiera con acceso al repo las vería en el historial. Usa Settings → Secrets and variables → Actions y refiérelas con ${{ secrets.NOMBRE }}.

Paso 4: protege main para que CI sea obligatorio

En Settings → Branches → Add rule activa "Require status checks to pass before merging" y selecciona el job pruebas. Ahora nadie puede fusionar a main con las pruebas en rojo.

Tech English: workflow = flujo de trabajo automatizado; runner = la máquina que ejecuta el flujo; job = trabajo; artifact = archivo resultante de un job; secret = secreto cifrado; to trigger = disparar.

Ejercicios

  1. CI que falla cuando debe. Introduce un cambio que rompa una prueba a propósito en una rama, abre un Pull Request y muestra (captura) que GitHub Actions bloquea el merge. Luego corrígelo y muestra el check en verde. Se evalúa que la protección de rama impida realmente fusionar con pruebas rotas.

  2. Imagen publicada por hash. Haz que un push a main publique la imagen en GHCR con dos tags: latest y el SHA del commit. Se evalúa que la imagen aparezca en el registro y que docker pull ghcr.io/tu-usuario/mi-api:latest funcione.

Tu progreso se guarda en este navegador. Inicia sesión para guardarlo en tu cuenta y verlo desde cualquier dispositivo.

¿Le sirvió esta lección?

Sirve para saber qué reescribir. Se puede cambiar cuando quiera.

0 votos
Sin nombre todavía

Su avance y su nombre se guardan en este navegador. No hace falta registrarse.

¿Va por el certificado?

Practicar y comentar no exige nada. Para el certificado sí hace falta verificar el correo, el nombre completo, la institución, el grado, porque el certificado dice quién es usted.

Comentarios (0)

Pregunte lo que no entendió. Alguien más tiene la misma duda y no se atreve.

  • Todavía no hay comentarios. Estrene usted.