09 — Cloud Storage
← Anterior: 08 — Gestión de Secretos
Cloud Storage (GCS) almacena archivos estáticos y medios subidos por usuarios. Crearemos dos buckets con Terraform: uno para archivos estáticos (CSS, JS) y uno para medios (subidas de usuarios).
¿Por qué dos buckets?
| Bucket | Contenido | Quién escribe | Quién lee |
|---|---|---|---|
static |
CSS, JS, íconos — de collectstatic |
Django (en tiempo de despliegue) | Navegadores directamente |
media |
Imágenes subidas por usuarios, avatares | Django (en tiempo de ejecución) | Navegadores directamente |
Ambos son públicamente legibles para que los navegadores puedan obtener archivos directamente sin pasar por Django.
Crear los buckets con Terraform
Agrega a infrastructure/main.tf:
# Cloud Storage buckets
resource "google_storage_bucket" "static" {
name = "${var.project_id}-static"
location = var.region
force_destroy = true
# Uniform bucket-level access (simpler, recommended)
uniform_bucket_level_access = true
# Public access prevention (keep off so we can make public)
public_access_prevention = "inherited"
}
resource "google_storage_bucket" "media" {
name = "${var.project_id}-media"
location = var.region
force_destroy = true
uniform_bucket_level_access = true
public_access_prevention = "inherited"
}
# Make static bucket publicly readable
resource "google_storage_bucket_iam_member" "static_public" {
bucket = google_storage_bucket.static.name
role = "roles/storage.objectViewer"
member = "allUsers"
}
# Make media bucket publicly readable
resource "google_storage_bucket_iam_member" "media_public" {
bucket = google_storage_bucket.media.name
role = "roles/storage.objectViewer"
member = "allUsers"
}
# Allow Cloud Run service account to write to both buckets
resource "google_storage_bucket_iam_member" "run_static_admin" {
bucket = google_storage_bucket.static.name
role = "roles/storage.objectAdmin"
member = "serviceAccount:${google_service_account.run.email}"
}
resource "google_storage_bucket_iam_member" "run_media_admin" {
bucket = google_storage_bucket.media.name
role = "roles/storage.objectAdmin"
member = "serviceAccount:${google_service_account.run.email}"
}
output "static_bucket" {
value = google_storage_bucket.static.name
}
output "media_bucket" {
value = google_storage_bucket.media.name
}
Ejecuta terraform apply para crear ambos buckets.
Qué se crea
| Bucket nombre | URL | Propósito |
|---|---|---|
mycoolproject-prod-static |
https://storage.googleapis.com/mycoolproject-prod-static/ |
CSS, JS, fuentes |
mycoolproject-prod-media |
https://storage.googleapis.com/mycoolproject-prod-media/ |
Subidas de usuarios |
Configuración de Django
En web/core/settings/prod.py:
STORAGES = {
# Default storage: user uploads go here
"default": {
"BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
"OPTIONS": {
"bucket_name": "${var.project_id}-media",
},
},
# Static files: collectstatic uploads here
"staticfiles": {
"BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
"OPTIONS": {
"bucket_name": "${var.project_id}-static",
"default_acl": None, # Removes public ACL, relies on bucket policy
"object_parameters": {
"cache_control": "public, max-age=31536000",
},
},
},
}
GS_PROJECT_ID = var.project_id
STATIC_URL = f"https://storage.googleapis.com/${var.project_id}-static/"
MEDIA_URL = f"https://storage.googleapis.com/${var.project_id}-media/"
Collectstatic: subir archivos estáticos
Antes de desplegar, ejecuta collectstatic para subir CSS, JS y fuentes a GCS:
Esto sube todos los archivos estáticos al bucket estático. El backend de GCS de Django maneja esto automáticamente vía la librería storages.
No hay archivos media para colectar
Los archivos media (subidas de usuarios) se suben en tiempo de ejecución cuando los usuarios envían formularios. No hay equivalente de collectstatic — Django escribe directamente a GCS vía el backend de storages.
Verificar que los buckets existen
Deberías ver:
Navegación
- 01 — Introducción: Qué vamos a construir
- 02 — Visión general de Terraform
- 03 — Servicios en la nube explicados
- 04 — Base de datos PlanetScale explicada
- 05 — Configuración del proyecto y estado de Terraform
- 06 — Proyecto GCP y APIs
- 07 — Artifact Registry
- 08 — Gestión de Secretos
- 09 — Cloud Storage (Capítulo actual)
- 10 — Service Accounts e IAM
- 11 — Cloud Run
- 12 — Trabajos en segundo plano y Scheduler
- 13 — Dockerfile
- 14 — Primer Despliegue
- 15 — Dominio personalizado y SSL
- 16 — Workload Identity Federation
- 17 — GitHub Actions CI/CD
- 18 — Referencia Rápida