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 amain"; - 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
-
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.
-
Imagen publicada por hash. Haz que un push a
mainpublique la imagen en GHCR con dos tags:latesty el SHA del commit. Se evalúa que la imagen aparezca en el registro y quedocker pull ghcr.io/tu-usuario/mi-api:latestfuncione.
Fin de la lección: abajo están las preguntas y los comentarios.
¿Le sirvió esta lección?
Sirve para saber qué reescribir. Se puede cambiar cuando quiera.
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.
Le llega un código de 6 dígitos. No hay contraseña que recordar.
Vence en 15 minutos.
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.