ruta backend / módulo 3

M3 — DevOps & Cloud

Outcome del módulo: un servicio se despliega solo (push → prod) y su infra está en código, no en clicks. Podés recrearla desde cero con un comando.


Concepto 1 — Docker production-grade

Idea núcleo: empaquetar la app con su entorno exacto. La diferencia entre “funciona en mi máquina” y una imagen que corre igual en cualquier lado.

Entender (capa 1)

Texto: un Dockerfile describe cómo construir la imagen. Lo que separa una imagen de juguete de una de producción: multi-stage (compilar en una etapa, copiar solo el resultado a una imagen final chica), imagen base slim, usuario non-root, y capas ordenadas para cachear bien.

Visual:

flowchart LR
    subgraph Build["stage 1: builder"]
        A[base full + deps de build] --> B[instala/compila]
    end
    subgraph Final["stage 2: runtime"]
        C[base slim] --> D[copia SOLO artefactos] --> E[user non-root]
    end
    B -.copia artefactos.-> D

Video: How to containerize a Python application with a multi-stage build using Chainguard Images — Chainguard

Ejemplo (mal → bien):

# ❌ imagen gorda, root, cache mal aprovechada
FROM python:3.12
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

# ✅ multi-stage, slim, non-root, capas cacheables
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt   # deps primero: cachea si no cambian

FROM python:3.12-slim
RUN useradd -m app
WORKDIR /app
# copiar bajo el HOME del user, no /root (0700 = ilegible para non-root → crashea)
COPY --from=builder --chown=app:app /root/.local /home/app/.local
COPY --chown=app:app . .
USER app                                       # non-root
ENV PATH=/home/app/.local/bin:$PATH
CMD ["python", "app.py"]

Fijar (capa 2)

Nota atómica:

Feynman: “Multi-stage es cocinar en una cocina industrial llena de equipo, pero servir el plato en una bandeja limpia. El comensal no recibe toda la cocina, solo la comida.”

Aplicar (capa 3)

Tomá una app tuya, hacé un Dockerfile multi-stage con usuario non-root. Compará el tamaño de la imagen final contra una single-stage con python:3.12 completo.

Límites


Concepto 2 — Infraestructura como código (IaC / Terraform)

Idea núcleo: definir la infra (servidores, DBs, redes) en archivos versionados, no clicando en la consola. Reproducible, revisable, destruible.

Entender (capa 1)

Texto: con Terraform declarás el estado deseado de tu infra; terraform plan te muestra el diff contra lo real, apply lo aplica. La infra queda en git: revisable en PR, recreable, y sin recursos fantasma (los que quedan cobrando porque nadie recuerda que existen — el clásico EC2/Elastic-IP olvidado en la consola).

Visual:

flowchart LR
    CODE[main.tf · estado deseado] --> PLAN[terraform plan · diff] --> APPLY[terraform apply] --> CLOUD[infra real]
    CLOUD -.state.-> PLAN

Video: Terraform Explained | Terraform Tutorial for Beginners — S3CloudHub

Ejemplo:

resource "google_cloud_run_service" "api" {
  name     = "my-api"
  location = "us-central1"
  template {
    spec {
      containers { image = "gcr.io/proj/my-api:v1" }
    }
  }
}
# terraform apply crea/actualiza; terraform destroy borra TODO lo declarado

Fijar (capa 2)

Nota atómica:

Feynman: “La consola es armar un mueble sin instrucciones y sin acordarte cómo lo hiciste. IaC es tener el plano: cualquiera lo rearma igual, y si sobra un tornillo, lo ves en el plano.”

Aplicar (capa 3)

Describí un servicio simple (una Cloud Run / un bucket) en un main.tf. Hacé plan, apply, y después destroy. Confirmá que la infra desaparece limpia.

Límites


Concepto 3 — CI/CD (GitHub Actions)

Idea núcleo: automatizar build → test → deploy en cada push. La máquina despliega, no vos a mano.

Entender (capa 1)

Texto: un pipeline se dispara en eventos (push, PR). Corre etapas: instala deps → lint → tests → build imagen → deploy. Si una etapa falla, no llega a prod. CI = integrar y validar; CD = desplegar automático.

Visual:

flowchart LR
    PUSH[git push] --> LINT[ruff] --> TEST[pytest] --> BUILD[docker build] --> DEPLOY[deploy prod]
    LINT -->|falla| STOP[❌ corta]
    TEST -->|falla| STOP

Video: Integrating CI/CD Pipeline in Python Project with GitHub Actions — Siddhardhan

Ejemplo:

name: ci
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.12" }
      - run: pip install -r requirements.txt
      - run: ruff check .
      - run: pytest
      # deploy solo si lo anterior pasó

Fijar (capa 2)

Nota atómica:

Feynman: “El pipeline es una línea de montaje con inspectores: si una pieza sale defectuosa en cualquier puesto, la cinta se detiene y nunca llega al cliente.”

Aplicar (capa 3)

Armá un workflow que corra ruff + pytest en cada push. Rompé un test a propósito y verificá que el pipeline falla en rojo antes de deployar.

Límites


Concepto 4 — Serverless vs contenedores/K8s

Idea núcleo: serverless (Cloud Run, Lambda) cubre el ~80% de casos backend sin operar servidores; K8s es para orquestación compleja que la mayoría no necesita todavía.

Entender:

flowchart TD
    Q{¿necesito control fino de red/estado/multi-servicio complejo?} -->|no, la mayoría| SL[Serverless · Cloud Run]
    Q -->|sí, a escala real| K8[Kubernetes]

Video: Kubernetes Vs Lambda Detailed Comparison | Containers Vs Serverless — Cloud With Raj Nota atómica: Front: ¿cuándo serverless y cuándo K8s? Back: serverless (Cloud Run) para la mayoría de APIs/servicios: escala a cero, cero ops. K8s cuando hay muchos servicios con necesidades finas de red/estado/scheduling y equipo para operarlo. Feynman: “Serverless es tomar Uber: subís y bajás, no mantenés el auto. K8s es tener flota propia: máximo control, pero pagás mecánicos, seguros y garage.” Aplicar: desplegá el mismo contenedor en Cloud Run; observá el escalado a cero. Leé qué serían pod/service/deployment equivalentes en K8s. Límites: serverless tiene cold starts y límites de ejecución; para procesos largos/stateful puede no encajar.


Concepto 5 — Redes cloud y secretos

Idea núcleo: VPC, DNS, TLS y gestión de secretos son el plumbing que todo servicio necesita y casi nadie estudia hasta que algo falla.

Entender (compacto):


Concepto 6 — Estrategias de deploy y costos

Idea núcleo: desplegar sin downtime y sin fugas de plata. Un deploy que tumba el servicio o una infra que cobra sola son fallas de senior.

Entender (compacto):

flowchart LR
    subgraph Canary
      LB[load balancer] -->|95%| V1[versión actual]
      LB -->|5%| V2[versión nueva] --> OK{¿métricas sanas?}
      OK -->|sí| MORE[subir a 100%]
      OK -->|no| BACK[volver a 0%]
    end

Nota atómica: Front: ¿blue-green o canary? Back: blue-green = switch total instantáneo, rollback simple, cuesta doble infra. Canary = exposición gradual (5%→100%), detecta problemas con impacto acotado, más complejo de orquestar. Feynman: “Blue-green es tener dos escenarios y apagar uno mientras encendés el otro. Canary es dejar entrar primero a 5 personas a probar el puente antes de abrirlo a la multitud.” Aplicar: configurá un split de tráfico canary en Cloud Run (revisiones con %). Y activá una alerta de presupuesto en tu cloud. Límites: blue-green duplica costo mientras coexisten; canary necesita buenas métricas (M5) para decidir el avance — sin observabilidad, el canary es a ciegas.


Checklist de dominio M3

Marcás cuando podés explicar (Feynman) + aplicar:

Salida verificable del módulo: un servicio con Dockerfile multi-stage + pipeline GitHub Actions (push→prod) + su infra en un main.tf que la recrea desde cero, con secretos fuera del repo y una alerta de presupuesto activa.