Introducción a la creación de un pipeline de CI/CD con FastAPI × GitHub Actions — Automatización de pruebas, compilación de Docker, registro de contenedores y despliegue en Kubernetes
Resumen (primero la visión general)
- Crearemos un pipeline de CI/CD con GitHub Actions para que los cambios en una aplicación FastAPI fluyan automáticamente desde el push hasta la publicación en producción.
- El pipeline se basa en tres etapas: Pruebas (CI) → Compilación y push de Docker → Despliegue en Kubernetes, y conmuta de forma segura entre los entornos de desarrollo, staging y producción.
- Usaremos GitHub Container Registry (GHCR) como ejemplo de registro de contenedores, pero la estructura se puede aplicar a cualquier registro.
- El despliegue a Kubernetes es un enfoque basado en push (ejecutando
kubectletc. directamente desde GitHub Actions), dejando espacio para evolucionar más adelante hacia enfoques basados en pull como Argo CD. - Organizaremos puntos de diseño que facilitan la operación: secretos, reglas de protección específicas por entorno, granularidad de las pruebas, estrategias de rollback y más.
A quién va dirigido (muy concreto)
-
Desarrolladores individuales / estudiantes
Alojas tu aplicación FastAPI en GitHub, pero ejecutas las pruebas, construyes la imagen de Docker y despliegas manualmente cada vez.
→ Apuntamos a un flujo de trabajo “semiautomático” donde al hacer push del código se ejecutan automáticamente las pruebas y se despliega al entorno de staging. -
Equipos pequeños (3–5 personas) de ingenieros web / backend
Las revisiones, pruebas y despliegues a staging para cada Pull Request suelen ser ad hoc y depender de cada persona.
→ Convertimos el workflow de GitHub Actions en la regla compartida para que las pruebas y despliegues se conviertan en el “proceso estándar” del equipo. -
Equipos de startups que ejecutan FastAPI en Kubernetes
Ya usas Kubernetes, pero estás acumulando scripts ad hoc ykubectl applymanuales, y nadie sabe con claridad qué script es la fuente de la verdad.
→ Centralizamos “Build → Registro → Despliegue en K8s” dentro del workflow y unificamos el flujo de publicación a producción.
Evaluación de accesibilidad
-
Estructura de la información
El artículo avanza paso a paso: visión general al principio → diseño de CI → diseño de CD → integración con Kubernetes → gestión de entornos y secretos → consejos operativos → resumen. -
Terminología
Los términos se explican brevemente la primera vez que aparecen y luego se usan de forma consistente para evitar confusiones. No se introducen términos en inglés más de lo necesario. -
Código y YAML
Se muestran en bloques de ancho fijo con comentarios cortos y abundantes líneas en blanco para facilitar el escaneo visual. -
Rango del público objetivo
Para lectores nuevos en CI/CD, cada paso incluye el razonamiento de fondo. Para lectores experimentados, el contenido es lo bastante profundo como para reutilizarlo como “plantilla”.
En conjunto, el objetivo es un nivel de legibilidad AA para un artículo técnico.
1. Lo primero a decidir: política de diseño de CI/CD para FastAPI
Esto no solo se aplica a FastAPI sino a aplicaciones web en general: si decides primero los siguientes tres puntos, tendrás menos dudas más adelante al diseñar el CI/CD.
- Cuándo ejecutar las pruebas (en el push, en el PR, al hacer merge a
main, etc.). - Hasta dónde automatizar y a partir de qué punto insertar aprobación humana.
- Dónde almacenar los artefactos (por ejemplo, imágenes de Docker) y cuándo distribuirlos a cada entorno.
En este artículo seguiremos una configuración común con las siguientes políticas.
-
Al hacer push a la rama
main:- Ejecutar pruebas (CI)
- Construir la imagen de Docker y hacer push al registro
- Desplegar automáticamente al entorno de staging
-
Para el despliegue a producción, usar Environments de GitHub Actions y disparadores manuales (
workflow_dispatch) para añadir aprobación humana.
Esta estructura logra un buen equilibrio que es fácil de operar tanto en proyectos individuales como en equipos pequeños, sin crear malos hábitos.
2. Alineando las suposiciones del repositorio FastAPI
2.1 Ejemplo de estructura de directorios
fastapi-app/
├─ app/
│ ├─ main.py
│ ├─ routers/
│ └─ core/
├─ tests/
│ └─ test_*.py
├─ Dockerfile
├─ requirements.txt / pyproject.toml
└─ .github/
└─ workflows/
└─ ci-cd.yaml # Por crear
2.2 Unificar el comando de pruebas
El comando de pruebas que se ejecuta en CI debe ser el mismo que ejecutas localmente.
Ejemplo (en [tool.pytest.ini_options] de pyproject.toml, etc.):
pytest -q
O si también quieres incluir formateador y chequeo de tipos:
ruff check .
pytest -q
mypy app
Este hábito de “ejecutar el mismo comando localmente y en CI” facilita mucho la resolución de problemas cuando algo falla.
3. Conceptos básicos de GitHub Actions: esqueleto de un workflow
GitHub Actions ejecuta automáticamente los workflows definidos en .github/workflows/*.yaml ante eventos como push y PR.
Empecemos con la configuración mínima que solo ejecuta pruebas.
3.1 Workflow solo de pruebas
# .github/workflows/ci-cd.yaml
name: CI/CD for FastAPI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
# Si es necesario: pip install -r requirements-dev.txt
- name: Run tests
run: pytest -q
Ahora las pruebas se ejecutarán automáticamente en los pushes y PR a la rama main.
Puntos de decisión:
- Si las pruebas se vuelven lentas, puedes dividir linting, pruebas unitarias y pruebas de integración en jobs separados y ejecutarlos en paralelo.
- También puedes dividir los workflows por eventos, por ejemplo “solo pruebas en ramas que no sean main y build + deploy al hacer merge a main.”
4. Construir imágenes Docker y hacer push a un registro
Si usas una aplicación FastAPI en producción, en muchos casos se recomienda distribuirla como una imagen de Docker.
Aquí agregaremos un job para construir y enviar una imagen a GitHub Container Registry (GHCR).
4.1 Preparación para GHCR
- En Settings → Packages del repositorio, confirma que GHCR está disponible.
- Una convención común para nombres de imagen:
ghcr.io/<OWNER>/<REPO>:<TAG>
<OWNER> suele ser tu nombre de usuario u organización en GitHub.
4.2 Añadir el job de Build & Push
Al usar la acción oficial docker/build-push-action, puedes escribir el build y el push de forma concisa.
jobs:
test:
# ... (el job de test anterior)
build-and-push:
needs: test # Solo se ejecuta si las pruebas pasan
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # Solo construir en la rama main
permissions:
contents: read
packages: write
id-token: write # Para usar OIDC, etc.
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }} # owner/repo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
Puntos clave:
needs: testgarantiza que el build solo se ejecute si las pruebas tienen éxito.- Usando
GITHUB_TOKEN, puedes hacer push a GHCR sin crear un token aparte (pero presta atención a la visibilidad y la configuración de la organización). - Además de
latest, etiqueta las imágenes con el SHA del commit de Git para facilitar el rollback a una versión específica.
5. Automatizar el despliegue a Kubernetes
A continuación, agregaremos una etapa de CD que despliegue la imagen de Docker construida a un clúster de Kubernetes. La documentación oficial de GitHub y varios artículos ya muestran ejemplos de cómo usar kubectl o kustomize desde GitHub Actions para desplegar en Kubernetes.
Aquí mostraremos un despliegue basado en push mínimo que ejecuta kubectl apply directamente desde Actions.
5.1 Registrar la información de conexión del clúster en GitHub
La autenticación con el clúster depende de tu proveedor cloud y configuración, pero estos son patrones comunes:
- Almacenar el contenido de
kubeconfigcomo un Secret de GitHub y reconstruir el archivo en el workflow. - Usar acciones específicas del proveedor (
setup-*, por ejemplogcloudpara GKE) para la autenticación.
En este ejemplo usaremos un patrón sencillo de poner todo el kubeconfig en un secret.
- Desde tu
~/.kube/configlocal, extrae la parte del clúster de destino y guárdala como un Secret de GitHub llamadoKUBECONFIG_CONTENT(o similar). - En el workflow, escríbelo en un archivo y configúralo como
KUBECONFIG.
5.2 Ejemplo de job de despliegue
deploy-staging:
needs: build-and-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: staging
url: https://stg.example.com # URL de staging (opcional)
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v4
with:
version: "v1.30.0"
- name: Configure kubeconfig
run: |
echo "${KUBECONFIG_CONTENT}" > kubeconfig
chmod 600 kubeconfig
env:
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG_STAGING }}
- name: Set KUBECONFIG env
run: echo "KUBECONFIG=$PWD/kubeconfig" >> $GITHUB_ENV
- name: Update image in manifest
run: |
IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
sed -i "s|image: .*|image: ${IMAGE}|g" k8s/deployment.yaml
- name: Apply manifests
run: |
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml
Puntos clave:
- Al especificar
environment: staging, puedes usar la función Environment de GitHub para establecer reglas de protección y revisores por entorno. - Sobrescribir el campo
image:en el YAML consedes un enfoque sencillo. Para más flexibilidad puedes usar herramientas comokustomizeo Helm. - Para producción, crea un job
deploy-production, estableceenvironment.name: productiony configura disparadores manuales y revisiones obligatorias.
6. Cambio de entorno y reglas de protección
Normalmente, staging y producción difieren en estos dos aspectos:
- El contenido de Secrets / ConfigMaps (endpoints de BD, claves de APIs externas, etc.).
- El flujo de despliegue en términos de automatización frente a pasos manuales (staging es automático, producción es manual + aprobación).
6.1 Uso de GitHub Environments
GitHub Actions proporciona la función Environments, que permite tener Secrets y reglas de protección específicos por entorno.
-
Entorno
staging:- Secrets:
KUBECONFIG_STAGING,DATABASE_URL_STAGING, etc. - Se permite despliegue automático (con reglas de protección más laxas).
- Secrets:
-
Entorno
production:- Secrets:
KUBECONFIG_PROD,DATABASE_URL_PROD, etc. - Requiere aprobación manual y puede restringir quién puede aprobar.
- Secrets:
En los workflows, especificar un environment en un job permite usar los Secrets específicos de ese entorno.
environment:
name: production
url: https://app.example.com
6.2 Integración con la configuración de FastAPI
Usando pydantic-settings y variables de entorno como ENV=stg / ENV=prod, puedes inyectar valores específicos por entorno desde Kubernetes y cambiar configuraciones sin modificar el código de tu aplicación.
7. Secretos y precauciones de seguridad
Los Secrets de GitHub Actions están cifrados en el lado de GitHub y no se muestran directamente en los logs, pero aun así hay que tener cuidado con cómo se manejan en los workflows.
7.1 Lo que no debes hacer
- Imprimir secretos en los logs usando
echotal cual. - Mantener
set -xsiempre activado mientras se ejecutan comandos que incluyen secretos como argumentos. - Incrustar kubeconfig directamente en manifiestos o hacer commit de él en el repositorio.
7.2 Consejos para un manejo seguro
- Pasar al workflow solo los secretos mínimos necesarios (no meter “de todo” en él).
- Separar los Secrets entre producción y staging para evitar accidentes como actualizar producción con credenciales de staging.
- Eliminar archivos temporales (como kubeconfig) al final del job para mayor seguridad.
8. Cómo vincular tu estrategia de pruebas con el CI
La calidad de tu CI/CD depende en última instancia de qué tipo de pruebas ejecutas y cuánto las automatizas.
8.1 Capas de pruebas de ejemplo
- Linting (estilo / análisis estático):
ruff,flake8,mypy, etc. - Pruebas unitarias: funciones y clases de la capa de servicio.
- Pruebas de API: validación de endpoints de FastAPI usando
TestClientohttpx.AsyncClient. - Pruebas de integración: pruebas end-to-end usando BD reales y middleware.
En GitHub Actions, puedes dividir esto en jobs separados, ejecutarlos en paralelo y exponer el resultado como insignias de estado en tu README para poder ver de un vistazo la salud del proyecto.
8.2 Alcance práctico para cada etapa
- En PR: Lint + pruebas unitarias + pruebas críticas de API
- Al hacer merge a
main: Lo anterior más algunas pruebas de integración - En ejecuciones nocturnas o programadas: Pruebas de integración de larga duración o pruebas de carga
Si tu equipo se pone de acuerdo en “cuándo está bien ejecutar pruebas más pesadas”, será más fácil equilibrar el tiempo de CI y la cobertura de pruebas.
9. Rollback y operación en caso de problemas
Una vez que tienes CI/CD, la capacidad de revertir rápidamente una “versión rota” se vuelve crucial.
9.1 Aprovechar las etiquetas de imagen Docker
Como se mencionó antes, etiquetar las imágenes de Docker no solo con latest sino también con los SHA de Git facilita el rollback a un commit específico.
- Ejemplo:
ghcr.io/owner/repo:3f2a9c1
Simplemente puedes reemplazar el image: en tu manifiesto de Kubernetes por esta etiqueta y volver a aplicarlo para restaurar el estado anterior.
9.2 Workflows de rollback en GitHub Actions
Una vez que domines lo básico, es útil crear un workflow específico de rollback usando workflow_dispatch (disparador manual).
- Aceptar como input el objetivo de rollback (tag o SHA de commit).
- Aplicar los manifiestos a Kubernetes siguiendo los mismos pasos que el job de despliegue.
Con esto en marcha, incluso los incidentes nocturnos se pueden manejar de forma segura usando un “procedimiento estandarizado”.
10. Impacto del CI/CD según el tipo de lector
10.1 Desarrolladores individuales / aprendices
- Simplemente con hacer push del código se ejecutan pruebas automáticamente, por lo que se reducen mucho accidentes como “olvidé probar, desplegué código roto”.
- Como las compilaciones de Docker están automatizadas, dejarás de depender de la memoria para cosas como “¿cómo construí la imagen de producción de ayer?”.
- Aunque todavía no uses Kubernetes, una vez que aprendas esta “plantilla de CI” podrás aplicarla a cualquier entorno futuro.
10.2 Equipos pequeños / desarrollo por encargo
- El flujo desde PR → pruebas → revisión → despliegue a staging se automatiza, por lo que los revisores pueden centrarse en el contenido de la revisión.
- Como los pasos de publicación se codifican en workflows, eliminas problemas del tipo “cada quien tiene un método de despliegue distinto”.
- Los nuevos miembros pueden sentirse seguros sabiendo que “puedes entender todo el flujo de publicación solo leyendo este YAML”.
10.3 Equipos SaaS de startups
- Al centralizar el acceso a producción en GitHub Actions, eliminas la necesidad de que cada persona toque producción directamente desde su máquina local.
- Los secretos y reglas de protección específicos por entorno facilitan diseñar permisos granulares para los lanzamientos a producción.
- Si más adelante adoptas Helm o Argo CD y pasas a un estilo GitOps, podrás evolucionar a partir de los workflows actuales como una base sólida.
11. Errores frecuentes y cómo evitarlos
| Síntoma | Causa | Contramedida |
|---|---|---|
| El CI es lento y nadie espera a que termine | Ejecutar la suite completa de pruebas cada vez | Dividir las pruebas entre PR y main, paralelizar jobs |
| Solo falla producción | Diferencias en secretos o variables de entorno | Gestionar configuraciones por entorno usando Environments, mantener .env.example y documentación |
| Se pierde / filtra el kubeconfig | Información en bruto escrita en workflows o logs | Guardar kubeconfig en Secrets, nunca loguearlo, borrar archivos temporales |
| El despliegue falla sin que nadie se entere | Configuración insuficiente de notificaciones | Activar notificaciones de GitHub, integrar con Slack o email para no perder fallos |
| El YAML se vuelve demasiado complejo | Intentar hacerlo todo en un solo workflow | Separar CI / CD, y staging / producción en workflows distintos |
12. Hoja de ruta de introducción (gradual, paso a paso)
- Crear un workflow de CI solo de pruebas (para push / PR).
- Añadir una etapa que construya imágenes de Docker y las envíe a un registro de contenedores como GHCR.
- Automatizar el despliegue al clúster de staging e integrarlo con la configuración de FastAPI usando
ENV=stg. - Usar Environments y Secrets de GitHub para crear un job
deploy-production(disparador manual + aprobación) para producción. - Evolucionar según sea necesario: workflows de rollback, integración con Helm / kustomize, HPA conectado a métricas personalizadas, etc.
13. Enlaces de referencia
Aquí tienes documentación oficial y artículos confiables para quienes quieran profundizar.
-
GitHub Actions
-
Relacionado con el despliegue de FastAPI
-
Docker / registros de contenedores
-
Kubernetes × GitHub Actions
-
CI/CD y Kubernetes en general
14. Resumen
- Con GitHub Actions, puedes combinar pruebas, builds de Docker, pushes al registro y despliegues en Kubernetes para una aplicación FastAPI en un único workflow automatizado.
- Aprovechando Environments y Secrets, puedes gestionar fácilmente las diferencias y permisos entre staging y producción, reduciendo el error humano.
- Usando etiquetas de imagen de Docker, workflows de rollback y una estrategia de pruebas bien pensada, tendrás un sistema que te permita responder con calma incluso cuando se produzcan incidencias.
- En lugar de buscar la perfección desde el primer día, empieza con los tres pasos de “Pruebas → Build → Despliegue a staging” y luego expande gradualmente hacia producción y mecanismos más avanzados.
Por hoy, da el primer paso creando un workflow solo de pruebas, y después ve superponiendo los builds de Docker y los despliegues encima.
Ver cómo tu aplicación FastAPI se acerca a un estado de “push-to-release” será una experiencia muy emocionante.
