Tu primera App de Python en Producción con Antigravity y Google Cloud Run
El paradigma de DevOps artesanal y la configuración manual de infraestructura en consola están siendo reemplazados por el desarrollo agéntico. Descubre cómo transformar un script local de Python en un servicio serverless contenerizado y desplegado en Google Cloud Platform (GCP) mediante agentes autónomos en Antigravity, código declarativo con Terraform y el runtime de Cloud Run.
Puntos Clave del Flujo de Trabajo Agéntico
Matriz de Decisión Arquitectónica para Despliegues en GCP
Comparativa entre los diferentes modelos de ejecución para cargas de trabajo en Python según el nivel de abstracción y los requerimientos operacionales:
| Patrón de Cómputo | Latencia de Arranque | Escalado a Cero | Complejidad Operativa | Coste en Inactividad | Caso de Uso Recomendado |
|---|---|---|---|---|---|
| Google Cloud Run | Sub-segundo / Bajo | Sí (Nativo) | Mínima (Serverless) | $0.00 (Pago por petición) | Microservicios HTTP, APIs, Procesamiento ligero orientado a eventos. |
| Cloud Run Jobs | Segundos | Sí (On-demand) | Mínima | $0.00 | Scripts Batch, ETLs programadas, tareas de mantenimiento finitas. |
| Google Kubernetes Engine (GKE) | Inmediata (Pods calientes) | No (Requiere nodos mínimos) | Alta (Control plane, mallas) | Fijo por infraestructura base | Monolitos complejos, arquitecturas multi-tenant de gran escala. |
| Compute Engine (VMs) | Minutos | No | Media-Alta (Parches, SO) | Fijo (24/7) | Cargas legacy o dependencias a nivel de kernel/driver de hardware. |
⚠️ Antipatrones Críticos: Del Script Local al Entorno Serverless
Al migrar un script secuencial o en bucle infinito (por ejemplo, un monitor de precios de Binance) hacia un contenedor en Google Cloud Run, surgen dos fallos recurrentes:
- Fallo de Port Binding & Health Checks: Cloud Run inyecta la variable de entorno
PORT(por defecto 8080) y requiere que el contenedor acepte peticiones HTTP. Si el script se ejecuta en un bucle cerrado sin levantar un servidor web, el servicio fallará al inicializarse tras agotar el timeout de arranque. - Error HTTP 451 (Unavailable For Legal Reasons) y Geobloqueo de IP: Servicios de terceros y exchanges financieros frecuentemente bloquean las peticiones originadas desde rangos de IP de centros de datos públicos (como GCP, AWS o Azure). En producción, estos escenarios demandan proxies residenciales, Cloud NAT con IPs dedicadas o endpoints privados autorizados.
Implementación Técnica: Transformación y Despliegue
A continuación se detalla la arquitectura generada por el agente de Antigravity: la envoltura del script en una API REST, el empaquetado del contenedor y la orquestación mediante Terraform.
1. Código de la Aplicación con Adaptación HTTP (`app.py`)
import os
import requests
from flask import Flask, jsonify
app = Flask(__name__)
def obtener_precio_btc():
url = "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT"
headers = {"User-Agent": "Mozilla/5.0"}
try:
response = requests.get(url, headers=headers, timeout=5)
response.raise_for_status()
data = response.json()
return float(data.get("price", 0.0))
except Exception as e:
return {"error": str(e)}
@app.route("/", methods=["GET"])
@app.route("/health", methods=["GET"])
def health_check():
return jsonify({"status": "healthy", "service": "btc-monitor"}), 200
@app.route("/price", methods=["GET"])
def get_price():
precio = obtener_precio_btc()
if isinstance(precio, dict) and "error" in precio:
return jsonify({"status": "error", "message": precio["error"]}), 502
return jsonify({
"status": "success",
"symbol": "BTCUSDT",
"price_usd": precio
}), 200
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
app.run(host="0.0.0.0", port=port)
2. Definición del Contenedor Multi-Stage (`Dockerfile`)
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PORT=8080
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt gunicorn
COPY . .
# Cloud Run inyecta dinámicamente $PORT
CMD exec gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 app:app
3. Infraestructura como Código (`main.tf`)
terraform {
required_version = ">= 1.5.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider "google" {
project = var.project_id
region = var.region
}
# Habilitación de APIs requeridas
resource "google_project_service" "services" {
for_each = toset([
"run.googleapis.com",
"artifactregistry.googleapis.com",
"cloudbuild.googleapis.com"
])
project = var.project_id
service = each.key
disable_on_destroy = false
}
# Repositorio en Artifact Registry
resource "google_artifact_registry_repository" "repo" {
depends_on = [google_project_service.services]
location = var.region
repository_id = var.repository_id
description = "Docker repository para btc-monitor"
format = "DOCKER"
}
# Servicio en Cloud Run (v2)
resource "google_cloud_run_v2_service" "default" {
depends_on = [google_artifact_registry_repository.repo]
name = var.service_name
location = var.region
ingress = "INGRESS_TRAFFIC_ALL"
template {
containers {
image = "${var.region}-docker.pkg.dev/${var.project_id}/${var.repository_id}/btc-monitor:latest"
resources {
limits = {
cpu = "1"
memory = "512Mi"
}
}
}
}
}
# Acceso Público No Autenticado
resource "google_cloud_run_v2_service_iam_member" "public_access" {
name = google_cloud_run_v2_service.default.name
location = google_cloud_run_v2_service.default.location
role = "roles/run.invoker"
member = "allUsers"
}
output "service_url" {
value = google_cloud_run_v2_service.default.uri
description = "URL pública del servicio Cloud Run"
}
Framework de Despliegue Paso a Paso
- Inicialización de la Sesión Agéntica en Antigravity: Abre el repositorio local en Antigravity y solicita al agente el objetivo mediante un prompt declarativo (ej. "Quiero migrar mi script app.py a Google Cloud Run usando Terraform y Docker").
-
Aprobación del Implementation Plan: Revisa la arquitectura propuesta: refactorización a endpoint HTTP, creación del
Dockerfileoptimizado, declaración de Terraform y script de compilación. -
Vinculación de Facturación y Cuenta de GCP: Si el agente crea un nuevo proyecto, proporciona el
billing_account_idcuando lo solicite para permitir el aprovisionamiento de APIs administradas. -
Ejecución del Pipeline de Construcción: El agente ejecuta
deploy.sh, que compila la imagen con Cloud Build, la publica en Artifact Registry y aplicaterraform apply -auto-approve. -
Verificación del Endpoint: Obtén la URL de salida y realiza un health check mediante
curl -s https://[SERVICE-URL]/health.
Preguntas Frecuentes de Arquitectura
Cloud Run es un entorno orientado a peticiones. Si el contenedor no abre un socket TCP en el puerto asignado por $PORT para responder a las comprobaciones de estado de Google, la plataforma considerará el contenedor insalubre y lo reiniciará. Las tareas sin servidor de procesamiento continuo deben estructurarse como Cloud Run Jobs o encapsularse en un servidor web.
Terraform utiliza el recurso google_project_service con dependencias explícitas (depends_on). Esto garantiza que run.googleapis.com y artifactregistry.googleapis.com estén totalmente propagadas antes de que el script intente crear repositorios o servicios.
Para evitar bloqueos por geolocalización o listas negras de proveedores cloud en APIs de terceros, se debe conectar el servicio Cloud Run a una red VPC Serverless con Cloud NAT asignando una IP estática pública, o bien orquestar las peticiones mediante un túnel o proxy intermedio.
