green snake
Photo by Pixabay on Pexels.com
目次

Da el salto a Kubernetes en producción: Guía práctica para desplegar FastAPI × Kubernetes

Deployment / Service / Ingress / ConfigMap / Secret / HPA / Health Checks


Introducción: Qué serás capaz de hacer y para quién es esto

Una vez que puedes ejecutar tu aplicación FastAPI con Docker, lo siguiente que probablemente quieras es: “quiero ejecutarla en un clúster” o “quiero que escale”. En este artículo desplegaremos una app FastAPI en Kubernetes (K8s) y recorreremos una configuración casi de producción donde podrás experimentar escalado, gestión de configuración, health checks y autoescalado, usando un ejemplo concreto y explicaciones detalladas.

Lectores objetivo (muy específicos)

  • Desarrolladores individuales (estudiantes / autodidactas / profesionales)
    Has usado Docker Compose, pero “Kubernetes da miedo y parece complicado”.
    → Caminaremos juntos a través de poner un único servicio FastAPI en un clúster como primer paso.

  • Ingenieros en equipos pequeños (3–5 personas)
    Ya ejecutas imágenes Docker en producción, pero los despliegues escalables y las actualizaciones sin cortes se están volviendo dolorosos.
    → Piensa en esto como una “plantilla” que puedes llevarte, con Deployment / Service / Ingress / ConfigMap / Secret / HPA cableados entre sí.

  • Equipos de desarrollo SaaS en startups
    Estás pensando en un futuro de microservicios en el que varios servicios FastAPI correrán en Kubernetes.
    → Este artículo se centra en un solo servicio, pero también comentaremos separación de manifiestos por servicio, namespaces y patrones para configuración compartida.


Notas de accesibilidad (sobre legibilidad)

  • La estructura sigue un triángulo invertido: “visión general primero → recursos clave (Deployment / Service / Ingress, etc.) → gestión de configuración → escalado → consejos operativos → recap final”.
  • El código y el YAML se muestran en bloques de ancho fijo, y los ejemplos muy largos se trocean por propósito.
  • Los términos técnicos se explican brevemente la primera vez, y después mantenemos la terminología consistente para evitar confusiones.
  • Usamos bastante espacio en blanco y encabezados para que los lectores de pantalla puedan seguir fácilmente la estructura del documento.

En conjunto, este artículo apunta a una legibilidad equivalente a WCAG AA para lectores con algo de base técnica.


1. Entender el panorama general del despliegue en Kubernetes

Primero alineemos el modelo mental de cómo se descompone una app FastAPI en recursos y cómo se ejecuta en Kubernetes.

1.1 Actores principales

  • Deployment
    Define el número deseado de Pods (contenedores) y su plantilla. Es el núcleo de los rolling updates y el self-healing.

  • Service
    Dado que las IP de los Pods son efímeras, un Service proporciona un punto de entrada estable y con nombre a tu app. Puede ser de tipo LoadBalancer, ClusterIP, etc.

  • Ingress
    Enruta peticiones HTTP/HTTPS externas hacia el Service adecuado. Es la puerta de enlace entre el clúster y el exterior.

  • ConfigMap / Secret
    Recursos para externalizar configuración y secretos como variables de entorno, ajustes, contraseñas y tokens.

  • Horizontal Pod Autoscaler (HPA)
    Recurso que escala automáticamente el número de Pods en función de CPU u otras métricas.

  • Liveness / Readiness Probes
    Ajustes de health check para determinar si el contenedor “está vivo” y “listo para recibir tráfico”.

1.2 Montaje mínimo que construiremos esta vez

  1. Usar una imagen Docker de FastAPI existente (por ejemplo, my-fastapi:latest.

  2. Preparar los siguientes manifiestos de Kubernetes:

    • Deployment (contenedor FastAPI + probes de liveness/readiness)
    • Service (ClusterIP / NodePort, etc.)
    • Ingress (routing para /api)
    • ConfigMap (configuración no sensible)
    • Secret (contraseña de BD, etc.)
    • HPA (autoescalado basado en CPU)
  3. Ejecutar y verificar la app en un clúster local (Minikube, kind) o en un K8s gestionado (EKS/GKE/AKS, etc.).


2. Confirmar los supuestos de la imagen FastAPI

Antes de meternos en Kubernetes, confirmemos cómo está estructurada la imagen de contenedor FastAPI.

2.1 Dockerfile típico (repaso)

FROM python:3.11-slim AS base

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

WORKDIR /app

COPY requirements.txt /app/
RUN pip install --upgrade pip && pip install -r requirements.txt

COPY app /app/app

# Ejecutar como usuario no root
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

ENV HOST=0.0.0.0 \
    PORT=8000

EXPOSE 8000

CMD ["bash", "-lc", "exec uvicorn app.main:app --host ${HOST} --port ${PORT}"]

Aquí arrancamos con uvicorn directamente, pero también podrías usar Gunicorn + UvicornWorker (no entraremos en ese detalle aquí).

2.2 Supuestos del lado de Kubernetes

  • El contenedor arranca con directorio de trabajo /app.
  • HOST y PORT se pueden cambiar mediante variables de entorno.
  • Los endpoints de health check como /health/liveness y /health/readiness ya están implementados (como se introdujo en artículos previos).

Escribiremos los manifiestos basándonos en estos supuestos.


3. Deployment: colocar contenedores FastAPI en el clúster

3.1 Manifiesto básico de Deployment

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-app
  labels:
    app: fastapi-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: fastapi-app
  template:
    metadata:
      labels:
        app: fastapi-app
    spec:
      containers:
        - name: fastapi
          image: my-fastapi:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8000
          env:
            - name: HOST
              value: "0.0.0.0"
            - name: PORT
              value: "8000"
          livenessProbe:
            httpGet:
              path: /health/liveness
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 10
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health/readiness
              port: 8000
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 3
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"

Puntos clave

  • replicas: 2 mantiene siempre dos Pods (redundancia mínima).

  • selector.matchLabels y template.metadata.labels deben coincidir para vincular el Deployment con sus Pods.

  • livenessProbe y readinessProbe hacen health checks de FastAPI:

    • Si falla liveness → Kubelet reinicia el contenedor.
    • Si falla readiness → el Pod se saca de los endpoints del Service y deja de recibir nuevas peticiones.
  • resources define peticiones y límites de recursos, lo que ayuda al comportamiento del HPA y al scheduling en los nodos.


4. Service: crear un punto de entrada estable

Un Deployment por sí solo no basta, porque no se puede acceder a los Pods de forma estable. Necesitamos un Service.

4.1 Ejemplo ClusterIP (acceso dentro del clúster)

# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
  labels:
    app: fastapi-app
spec:
  type: ClusterIP
  selector:
    app: fastapi-app
  ports:
    - name: http
      port: 80         # Puerto del Service
      targetPort: 8000 # Puerto del contenedor
  • selector.app: fastapi-app enruta el tráfico a los Pods creados por el Deployment.
  • Dentro del clúster, el Service es accesible vía el nombre DNS fastapi-service (por ejemplo, http://fastapi-service).

4.2 Exponer el Service al exterior (NodePort / LoadBalancer)

En un Minikube local, a menudo se usa NodePort; en K8s gestionado en la nube, lo habitual es LoadBalancer.

Ejemplo: Service tipo LoadBalancer (entorno cloud)

apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
spec:
  type: LoadBalancer
  selector:
    app: fastapi-app
  ports:
    - port: 80
      targetPort: 8000

Sin embargo, para un routing HTTP flexible y terminación TLS, generalmente es mejor usar un Ingress Controller, así que veamos un ejemplo de Ingress.


5. Ingress: conectando el tráfico HTTP externo con FastAPI

Ingress define reglas para enrutar tráfico HTTP hacia múltiples Services según paths u otras condiciones. Aquí vamos a usar una configuración sencilla para un solo servicio FastAPI.

5.1 Ingress simple (ruta /api hacia FastAPI)

Un Ingress Controller común es NGINX Ingress. El ejemplo siguiente lo asume.

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fastapi-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  ingressClassName: nginx   # Cambia según tu IngressClass
  rules:
    - host: example.local   # En producción, tu FQDN real
      http:
        paths:
          - path: /api(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: fastapi-service
                port:
                  number: 80
  • host permite enrutar según el nombre de dominio.
  • path envía todas las rutas bajo /api al Service de FastAPI.
  • En la práctica también necesitas configuración TLS (un Secret con el certificado), pero aquí nos centramos en los conceptos básicos.

6. ConfigMap y Secret: externalizar configuración y secretos

Como en artículos anteriores, usar pydantic-settings para leer config desde variables de entorno es una buena opción para FastAPI. En Kubernetes, ConfigMap y Secret son la forma estándar de aportar esas variables.

6.1 ConfigMap (configuración no sensible)

# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fastapi-config
data:
  APP_NAME: "My FastAPI on K8s"
  ENV: "prod"
  LOG_LEVEL: "info"
  CORS_ORIGINS: "https://app.example.com"

6.2 Secret (configuración sensible)

# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: fastapi-secret
type: Opaque
data:
  SECRET_KEY: cHJvZC1zZWNyZXQ=      # base64("prod-secret")
  DATABASE_URL: cG9zdGdyZXNxbCtwc3ljcGc6Ly91c2VyOnBhc3NAaG9zdDoyNTQzL2FwcA==

Nota: Los valores bajo data deben ser cadenas en base64 (por ejemplo, echo -n "prod-secret" | base64).

6.3 Usarlos como variables de entorno en el Deployment

# k8s/deployment.yaml (extracto de la sección env)
      containers:
        - name: fastapi
          image: my-fastapi:latest
          envFrom:
            - configMapRef:
                name: fastapi-config
            - secretRef:
                name: fastapi-secret
          # Además puedes definir env individuales
          env:
            - name: HOST
              value: "0.0.0.0"
            - name: PORT
              value: "8000"
  • envFrom inyecta todas las claves del ConfigMap y del Secret como variables de entorno.
  • En lugar de usar un .env con pydantic-settings, lees estas variables proporcionadas por Kubernetes.

7. Horizontal Pod Autoscaler (HPA) para autoescalado

El HPA de Kubernetes escala el número de Pods cuando el uso de CPU pasa un umbral definido.

7.1 Ejemplo simple de HPA

# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: fastapi-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: fastapi-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
  • averageUtilization: 60 significa “escala hacia fuera si el uso medio de CPU entre todos los Pods supera el 60 %”.
  • Para usar HPA, tu clúster debe tener metrics-server o un sistema equivalente de métricas (la mayoría de K8s gestionados lo traen de serie).

7.2 Cosas a tener en cuenta del lado de FastAPI

  • Diseña tu app para aprovechar I/O asíncrona en vez de depender fuertemente de operaciones bloqueantes, de modo que el uso de CPU refleje mejor la carga y el escalado sea más efectivo.
  • Si expones métricas en formato Prometheus, luego podrás controlar el HPA con métricas personalizadas (fuera del alcance de este artículo).

8. Flujo de despliegue de ejemplo en un clúster local (con kubectl)

Hemos visto los YAML; ahora organicemos brevemente los pasos reales para desplegarlos con kubectl.

8.1 Flujo de trabajo de ejemplo

  1. Construir la imagen Docker

    docker build -t my-fastapi:latest .
    
  2. Poner la imagen a disposición del clúster (para Minikube)

    • Ejecuta eval $(minikube docker-env) antes del build
      o bien
    • Empuja la imagen a un registry (ECR/GCR/Docker Hub, etc.)
  3. Aplicar los manifiestos de Kubernetes

    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
    kubectl apply -f k8s/hpa.yaml
    
  4. Comprobar estado

    kubectl get pods
    kubectl get svc
    kubectl get ingress
    kubectl get hpa
    
  5. Ver logs de Pods

    kubectl logs -f deploy/fastapi-app
    
  6. Acceder vía Ingress (ejemplo Minikube)

    minikube ip
    # Luego visita: http://<minikube-ip>/api/meta
    

Los detalles varían según tu entorno local (Minikube, kind, Docker Desktop, etc.).


9. Claves operativas: rolling updates y rollbacks

9.1 Rolling updates

Cuando cambias la etiqueta de imagen o variables de entorno en el Deployment y haces kubectl apply del nuevo manifiesto, se dispara un rolling update.

Por debajo, Kubernetes:

  • Arranca un nuevo Pod con la spec actualizada.
  • Espera a que el readinessProbe sea exitoso.
  • Luego detiene un Pod antiguo.
  • Repite el proceso, minimizando el downtime.

9.2 Rollbacks

Si la nueva versión da problemas, puedes volver a una revisión anterior:

kubectl rollout history deploy/fastapi-app
kubectl rollout undo deploy/fastapi-app

Del lado de FastAPI, presta mucha atención a las migraciones de base de datos. Si cambias el esquema, tendrás que decidir un orden seguro; por ejemplo, aplicar las migraciones primero y después desplegar la nueva versión de la app.


10. Logs y métricas (visión rápida)

10.1 Logs

  • Como regla general, escribe logs estructurados (por ejemplo, JSON) a stdout, y revísalos mediante kubectl logs o una plataforma de agregación (Cloud Logging, Elasticsearch, Loki, etc.).
  • No confíes en escribir archivos de log dentro del contenedor; en su lugar, deja que Kubernetes y tu stack de logging recojan lo que sale por stdout/stderr.

10.2 Métricas y trazas

  • Con Prometheus u OpenTelemetry, puedes ejecutar agentes como sidecars o Pods separados.
  • Cuando tu arquitectura crezca a varios servicios, el tracing distribuido (Jaeger, Tempo, etc.) será importante para identificar qué servicio está introduciendo latencia.

Esta área es profunda, así que aquí nos quedamos en palabras clave.


11. Errores habituales y cómo evitarlos

Síntoma Causa probable Contramedida
El Pod arranca y se para inmediatamente Faltan variables de entorno o el nombre del Secret es incorrecto Revisa los eventos con kubectl describe pod, inspecciona env y los logs para confirmar las claves
No se puede acceder a la app vía Service Selector de labels incorrecto / puertos mal configurados Verifica labels/selector y port/targetPort en Deployment y Service
Ingress devuelve 404 IngressClass o path no coinciden Confirma ingressClassName, la configuración del Ingress Controller y la configuración de path/regex
HPA no funciona metrics-server no instalado Configura métricas en el clúster (sigue la documentación de tu proveedor cloud)
Pequeños cortes durante el rolling update Readiness probe ausente o demasiado permisiva Revisa tu implementación de /health/readiness y los tiempos de las probes para dar tiempo suficiente de arranque

12. Resumen de beneficios según tipo de lector

  • Desarrolladores individuales

    • Las plantillas concretas para Deployment / Service / Ingress / HPA hacen que “¿por dónde empiezo con Kubernetes?” sea mucho menos intimidante.
    • Practicar en un clúster local (Minikube, etc.) facilita imaginar el salto a un clúster real de producción.
  • Equipos pequeños

    • Obtienes una “checklist mínima” para migrar de Docker Compose a Kubernetes.
    • Combinando rolling updates y HPA puedes reducir downtime y hacer tu servicio más resistente a picos de carga.
  • Equipos SaaS en startups

    • Con ConfigMap / Secret / HPA y compañía, cimentas una arquitectura que puede escalar con seguridad mientras cambias configs por entorno.
    • Puedes empezar a imaginar un futuro de microservicios con un Deployment / Service / Ingress por servicio.

13. Referencias (principalmente docs oficiales)


14. Cierre: convertir FastAPI en “ciudadano de primera” en Kubernetes

Hemos recorrido los recursos y ajustes básicos necesarios para desplegar una app FastAPI en Kubernetes:

  • Usar un Deployment para gestionar el número y la plantilla de Pods, con probes de liveness/readiness para health checks.
  • Usar un Service como punto de entrada estable, y enlazarlo con el exterior vía Ingress si hace falta.
  • Usar ConfigMap y Secret para externalizar configuración y secretos, y leerlos como variables de entorno en FastAPI.
  • Usar HPA para escalar Pods automáticamente según la utilización de CPU.
  • Usar rolling updates y rollbacks para actualizar versiones con seguridad y depurar problemas.

Al principio, la cantidad de YAML puede parecer abrumadora, pero una vez que entiendes el rol de cada componente, Kubernetes deja de dar tanto miedo.

Usa esta plantilla como base y ve adaptándola poco a poco a tus propios proyectos.
Que tu app FastAPI prospere como “ciudadano de primera clase” en el mundo Kubernetes ✨

por greeden

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)