La red de AlpinaShop ya está construida: alpinashop-vpc con sus subredes, el firewall que solo deja pasar lo necesario, Cloud NAT para la salida y la base de datos en IP privada. Pero el catálogo sigue sirviéndose por la dirección de una máquina concreta. Si esa máquina cae, la tienda cae. Si el tráfico crece, no hay nada que reparta. Y no hay HTTPS, ni dominio, ni un punto único donde aplicar seguridad. Esta lección pone delante la pieza que resuelve todo eso a la vez: el balanceador de carga.
Cloud Load Balancing no es un aparato ni una máquina virtual que tú administras. Es un servicio distribuido, implementado en la propia infraestructura de red de Google, sin instancias que dimensionar ni escalar. Su versión global tiene una propiedad que conviene entender bien porque cambia el diseño: una sola dirección IP anycast que se anuncia desde más de cien puntos de presencia repartidos por el mundo, de modo que un cliente de Madrid y otro de Helsinki entran por el punto más cercano a cada uno y viajan el resto del trayecto por la red privada de Google.
Además, el balanceador es el sitio donde se enchufa todo lo demás: el certificado TLS (03-07), la caché de Cloud CDN (03-03) y el cortafuegos de aplicación Cloud Armor (03-05) se configuran sobre él. Construirlo bien es la condición previa de las cuatro lecciones siguientes.
En esta lección aprenderás a orientarte en el catálogo de balanceadores sin perderte en la nomenclatura, montarás pieza a pieza el balanceador HTTP(S) externo global de AlpinaShop con gcloud, enrutarás /imagenes/* directamente al bucket alpinashop-catalogo y el resto al MIG alpinashop-web-mig, y dominarás las comprobaciones de estado, que son la causa del 90 % de los problemas de un balanceador recién creado.
Contenido
- Por qué un balanceador y qué problemas resuelve
- El catálogo de balanceadores de Google Cloud y cómo elegir
- Anatomía de un balanceador HTTP(S) externo global
- Preparativos: comprobación de estado y puerto con nombre
- El servicio de backend sobre el MIG
- El backend de bucket para las imágenes
- El mapa de URL: enrutar por ruta
- Proxy de destino y regla de reenvío
- Comprobaciones de estado en profundidad: por qué fallan
- Políticas de balanceo, capacidad y afinidad de sesión
- Redirección de HTTP a HTTPS
- Escalado global: por qué no hay que "precalentar"
- Balanceadores internos para servicios internos
- NEG sin servidor: Cloud Run detrás del mismo balanceador
- Registro y métricas del balanceador
- Por qué un balanceador y qué problemas resuelve
Un balanceador de carga hace mucho más que repartir peticiones. En el caso de AlpinaShop resuelve simultáneamente:
| Problema actual | Cómo lo resuelve el balanceador |
|---|---|
| Una sola VM: punto único de fallo | Reparte entre las instancias del MIG y saca de rotación las que fallan |
| El tráfico solo entra por una zona | El MIG regional cubre tres zonas; el balanceador reparte entre ellas |
| Clientes lejanos con latencia alta | IP anycast: se entra por el PoP más cercano y se viaja por la red de Google |
| No hay HTTPS ni certificado | Termina TLS con certificados gestionados (03-07) |
| Las imágenes las sirve la aplicación | Un backend de bucket sirve alpinashop-catalogo sin tocar la aplicación |
| No hay dónde poner WAF ni caché | Cloud Armor (03-05) y Cloud CDN (03-03) se aplican aquí |
| Actualizar la app implica corte | Drenaje de conexiones y actualización progresiva del MIG |
La idea clave: el balanceador es el borde de tu arquitectura. Todo lo que quieras hacer una sola vez para todo el tráfico —cifrar, filtrar, cachear, medir— se hace en el borde.
- El catálogo de balanceadores de Google Cloud y cómo elegir
Aquí es donde mucha gente se pierde, porque la nomenclatura ha cambiado con los años y los nombres son largos. Vamos a ordenarlo con tres preguntas.
Pregunta 1: ¿capa 7 o capa 4? Es decir, ¿el balanceador entiende HTTP (rutas, cabeceras, cookies) o solo mueve paquetes TCP/UDP?
Pregunta 2: ¿externo o interno? ¿Lo llaman desde internet o solo desde dentro de tu VPC?
Pregunta 3: ¿global o regional? ¿Una IP única para todo el mundo o una IP por región?
Con esas tres respuestas, el balanceador está determinado:
| Balanceador | Capa | Externo/interno | Alcance | Protocolos | Caso de uso |
|---|---|---|---|---|---|
| Balanceador de aplicaciones externo global | 7 | Externo | Global | HTTP, HTTPS, HTTP/2, HTTP/3 | El de AlpinaShop. Web pública mundial, CDN, WAF |
| Balanceador de aplicaciones externo regional | 7 | Externo | Regional | HTTP, HTTPS | Requisitos de residencia de datos en una región |
| Balanceador de aplicaciones interno | 7 | Interno | Regional (o entre regiones) | HTTP, HTTPS | Microservicios internos con enrutamiento por ruta |
| Balanceador de red de proxy externo | 4 (proxy) | Externo | Global o regional | TCP, SSL | Protocolos no HTTP que necesitan terminación TLS |
| Balanceador de red de paso a través externo | 4 (paso a través) | Externo | Regional | TCP, UDP, ESP, ICMP | Preserva la IP de origen; juegos, protocolos raros |
| Balanceador de red de paso a través interno | 4 | Interno | Regional | TCP, UDP | Backend interno de alto rendimiento; base de datos, gRPC |
Dos distinciones que conviene tener claras:
- Proxy frente a paso a través. Un balanceador proxy termina la conexión del cliente y abre otra hacia el backend; el backend ve la IP del balanceador y recibe la del cliente en la cabecera
X-Forwarded-For. Un balanceador de paso a través no termina nada: el paquete llega al backend con la IP de origen original. - Global frente a regional. El global usa anycast y un único mapa de URL para todas las regiones; el regional vive en una sola región y su IP también. El global es el que permite CDN y Cloud Armor a escala mundial.
Regla práctica para elegir: si es tráfico web público, es el balanceador de aplicaciones externo global. Solo se baja de ahí por un requisito concreto: residencia de datos, un protocolo que no es HTTP o la necesidad de conservar la IP de origen a nivel de paquete.
- Anatomía de un balanceador HTTP(S) externo global
El balanceador no es un objeto: es una cadena de objetos que se crean por separado y se enlazan. Entender la cadena es entender el servicio.
flowchart TB
C([Cliente en Europa])
IP["Dirección IP global anycast<br/>alpinashop-lb-ip"]
FR["Regla de reenvío<br/>puerto 443"]
TP["Proxy HTTPS de destino<br/>+ certificado TLS (03-07)<br/>+ política SSL"]
UM["Mapa de URL<br/>alpinashop-url-map"]
BS["Servicio de backend<br/>bs-catalogo-web"]
BB["Backend de bucket<br/>bb-catalogo-imagenes"]
HC["Comprobación de estado<br/>hc-catalogo /salud"]
MIG["MIG alpinashop-web-mig<br/>2–10 instancias, 3 zonas"]
GCS[("Bucket alpinashop-catalogo")]
C --> IP --> FR --> TP --> UM
UM -->|"/imagenes/*"| BB --> GCS
UM -->|"resto"| BS --> MIG
HC -.comprueba.-> MIG
BS -.usa.-> HC
Pieza a pieza, de fuera hacia dentro:
| Pieza | Qué hace | Recurso gcloud |
|---|---|---|
| Dirección IP global | La IP anycast pública que anuncian los PoP | compute addresses --global |
| Regla de reenvío | Une IP + puerto con un proxy de destino | compute forwarding-rules |
| Proxy de destino | Termina la conexión; en HTTPS, aplica el certificado y la política SSL | compute target-https-proxies |
| Mapa de URL | Decide, según host y ruta, qué servicio de backend atiende | compute url-maps |
| Servicio de backend | Agrupa backends, define política de balanceo, CDN, Cloud Armor, timeouts | compute backend-services |
| Backend | El grupo real: MIG, NEG o bucket | backend-services add-backend |
| Comprobación de estado | Decide qué instancias reciben tráfico | compute health-checks |
Se construyen de dentro hacia fuera: primero la comprobación de estado, luego los servicios de backend, después el mapa de URL, el proxy y por último la regla de reenvío. Si lo intentas al revés, gcloud se queja de que el recurso referenciado no existe.
- Preparativos: comprobación de estado y puerto con nombre
La aplicación Flask de AlpinaShop escucha en el puerto 8080 bajo gunicorn y expone una ruta de salud. Antes de nada, asegúrate de que esa ruta existe y es barata:
# app.py — ruta de salud de AlpinaShop
@app.route("/salud")
def salud():
"""Comprobación de estado para el balanceador.
Debe ser BARATA y RÁPIDA: se invoca cada pocos segundos desde
varios comprobadores. No consultes la base de datos aquí salvo
que quieras que un problema de BD saque de rotación toda la flota.
"""
return {"estado": "ok"}, 200Ese matiz merece una explicación, porque es una decisión de arquitectura y no un detalle:
- Si
/saludno consulta la base de datos, un problema de base de datos deja los backends "sanos" y los clientes reciben errores 500 de la aplicación. Malo, pero acotado. - Si
/saludsí consulta la base de datos, un problema de base de datos marca todos los backends como no sanos a la vez, el balanceador se queda sin destinos y devuelve 502 a todo el mundo. Peor: has convertido un fallo parcial en una caída total.
La práctica habitual es tener dos rutas: /salud superficial (para el balanceador) y /salud/completo profunda (para la monitorización de 06-04, que alerta pero no saca de rotación).
Ahora, la comprobación de estado y el puerto con nombre:
gcloud config set project alpinashop-prod
# Comprobación de estado HTTP contra /salud en el 8080
gcloud compute health-checks create http hc-catalogo \
--port=8080 \
--request-path=/salud \
--check-interval=10s \
--timeout=5s \
--healthy-threshold=2 \
--unhealthy-threshold=3 \
--description="Salud del catalogo de AlpinaShop"
# El grupo de instancias debe declarar un "puerto con nombre":
# el servicio de backend se referirá al nombre, no al número.
gcloud compute instance-groups managed set-named-ports alpinashop-web-mig \
--region=europe-west1 \
--named-ports=http-catalogo:8080El puerto con nombre es una fuente habitual de confusión. El servicio de backend no dice "manda el tráfico al 8080"; dice "manda el tráfico al puerto llamado http-catalogo", y cada grupo de instancias traduce ese nombre a un número. La ventaja es que puedes cambiar el puerto de la aplicación sin tocar el balanceador. El inconveniente es que si olvidas definir el puerto con nombre, el balanceador usa el http por defecto (puerto 80), no encuentra nada y todo aparece como no saludable.
Parámetros de la comprobación, explicados:
| Parámetro | Valor | Significado |
|---|---|---|
--check-interval |
10s | Cada cuánto se comprueba |
--timeout |
5s | Cuánto se espera la respuesta antes de contarla como fallo |
--healthy-threshold |
2 | Comprobaciones correctas seguidas para volver a rotación |
--unhealthy-threshold |
3 | Fallos seguidos para salir de rotación |
Con estos valores, una instancia rota tarda unos 30 segundos en salir de rotación y una recuperada unos 20 en volver. Bajar el intervalo detecta antes pero genera más carga; subir el umbral de fallo evita expulsiones por un pico transitorio.
- El servicio de backend sobre el MIG
El servicio de backend es la pieza central: define cómo se reparte el tráfico, qué comprobación se usa, cuánto se espera una respuesta, si hay CDN y si hay Cloud Armor.
# 1) Crear el servicio de backend (esquema EXTERNAL_MANAGED = balanceador global moderno)
gcloud compute backend-services create bs-catalogo-web \
--global \
--load-balancing-scheme=EXTERNAL_MANAGED \
--protocol=HTTP \
--port-name=http-catalogo \
--health-checks=hc-catalogo \
--timeout=30s \
--connection-draining-timeout=60s \
--description="Backend del catalogo web de AlpinaShop"
# 2) Añadir el MIG regional como backend
gcloud compute backend-services add-backend bs-catalogo-web \
--global \
--instance-group=alpinashop-web-mig \
--instance-group-region=europe-west1 \
--balancing-mode=RATE \
--max-rate-per-instance=80 \
--capacity-scaler=1.0Opciones importantes:
--load-balancing-scheme=EXTERNAL_MANAGED: es el esquema del balanceador de aplicaciones externo global actual, basado en el proxy Envoy de Google. El valor antiguoEXTERNALcorresponde al balanceador clásico. Usa siempreEXTERNAL_MANAGEDpara desarrollos nuevos: soporta enrutamiento avanzado, reintentos, reescritura de cabeceras y espejo de tráfico.--timeout=30s: cuánto espera el balanceador la respuesta completa del backend. Si la aplicación tiene alguna operación lenta (una exportación de catálogo, por ejemplo), súbelo o mueve esa operación a un proceso asíncrono. Un 502 conbackend_timeouten los logs es exactamente esto.--connection-draining-timeout=60s: cuando una instancia sale del grupo (por autoescalado o por una actualización), el balanceador deja de mandarle peticiones nuevas pero le da 60 segundos para terminar las que tiene en curso. Sin drenaje, cada reducción del autoescalado corta conexiones vivas.--balancing-mode=RATEcon--max-rate-per-instance=80: cada instancia se considera "llena" a 80 peticiones por segundo. Lo desarrollamos en el apartado 10.
- El backend de bucket para las imágenes
Las 60 GB de imágenes del catálogo no deben pasar por la aplicación Flask. Un backend de bucket conecta el balanceador directamente con alpinashop-catalogo: Google sirve el objeto sin que ninguna instancia intervenga.
gcloud compute backend-buckets create bb-catalogo-imagenes \
--gcs-bucket-name=alpinashop-catalogo \
--description="Imagenes de producto servidas directamente desde Cloud Storage"Ventajas frente a servirlas desde la aplicación:
| Aspecto | Desde Flask | Desde backend de bucket |
|---|---|---|
| Consumo de CPU de las VM | Alto (cada imagen ocupa un worker) | Cero |
| Escalado | Limitado por el MIG | Ilimitado, es Cloud Storage |
| Caché en CDN | Requiere configurar cabeceras en la app | Se activa con una opción (03-03) |
| Coste | Instancias más grandes | Solo almacenamiento y egress |
| Latencia | Un salto extra | Directo |
Para que el bucket sea servible por el balanceador, sus objetos deben ser legibles públicamente o bien accesibles mediante cookies firmadas (que se ven en 03-03). Las imágenes de producto de AlpinaShop son públicas por naturaleza —están en la tienda—, así que:
# Lectura pública SOLO del prefijo de las imágenes web y miniaturas.
# Los originales de alta resolución NO deben ser públicos.
gcloud storage buckets add-iam-policy-binding gs://alpinashop-catalogo \
--member=allUsers \
--role=roles/storage.objectViewer \
--condition='expression=resource.name.startsWith("projects/_/buckets/alpinashop-catalogo/objects/productos/") && (resource.name.contains("/web/") || resource.name.contains("/thumb/")),title=solo-web-y-thumb,description=Publico solo el contenido optimizado para la tienda'Fíjate en la condición IAM: hace pública solo la parte web/ y thumb/ del convenio de rutas que fijamos en 02-02, dejando original/ privado. Las condiciones de IAM se explican en 03-04; aquí sirven para no exponer los originales de alta resolución por descuido.
- El mapa de URL: enrutar por ruta
El mapa de URL es el cerebro del balanceador: mira el host y la ruta de cada petición y decide qué backend la atiende.
# 1) Crear el mapa con el servicio por defecto (la aplicación)
gcloud compute url-maps create alpinashop-url-map \
--default-service=bs-catalogo-web \
--description="Enrutamiento del sitio de AlpinaShop"
# 2) Añadir el matcher de rutas que desvía /imagenes/* al bucket
gcloud compute url-maps add-path-matcher alpinashop-url-map \
--path-matcher-name=matcher-principal \
--default-service=bs-catalogo-web \
--backend-bucket-path-rules="/imagenes/*=bb-catalogo-imagenes,/estatico/*=bb-catalogo-imagenes" \
--new-hosts="alpinashop.example,www.alpinashop.example"El resultado se puede ver y editar como YAML, que es la forma más clara de razonar sobre él:
name: alpinashop-url-map
defaultService: .../backendServices/bs-catalogo-web
hostRules:
- hosts:
- alpinashop.example
- www.alpinashop.example
pathMatcher: matcher-principal
pathMatchers:
- name: matcher-principal
defaultService: .../backendServices/bs-catalogo-web
pathRules:
- paths:
- /imagenes/*
service: .../backendBuckets/bb-catalogo-imagenes
- paths:
- /estatico/*
service: .../backendBuckets/bb-catalogo-imagenesCómo se evalúa una petición, con ejemplos reales de AlpinaShop:
| Petición | Regla que aplica | Backend |
|---|---|---|
https://alpinashop.example/ |
defaultService del matcher |
bs-catalogo-web |
https://alpinashop.example/producto/moc-40 |
defaultService del matcher |
bs-catalogo-web |
https://alpinashop.example/imagenes/productos/moc-40/web/frontal-800.webp |
/imagenes/* |
bb-catalogo-imagenes |
https://alpinashop.example/estatico/css/tienda.css |
/estatico/* |
bb-catalogo-imagenes |
https://otrodominio.example/ |
Ningún hostRule coincide |
defaultService del mapa |
Tres detalles que ahorran horas de depuración:
- La coincidencia de rutas es por prefijo con
*al final, no una expresión regular./imagenes/*coincide con todo lo que empieza por/imagenes/. - La ruta no se reescribe por defecto. Una petición a
/imagenes/productos/moc-40/web/frontal-800.webpbusca en el bucket el objetoimagenes/productos/moc-40/web/frontal-800.webp, con el prefijoimagenes/incluido. Como nuestro convenio de 02-02 guarda los objetos enproductos/<sku>/web/..., sin ese prefijo, hay que reescribir:
# Exportar, editar y volver a importar el mapa para añadir urlRewrite
gcloud compute url-maps export alpinashop-url-map \
--destination=/tmp/url-map.yaml --global# Fragmento a añadir dentro de la pathRule de /imagenes/*
pathRules:
- paths:
- /imagenes/*
service: .../backendBuckets/bb-catalogo-imagenes
routeAction:
urlRewrite:
pathPrefixRewrite: /Con pathPrefixRewrite: /, la petición /imagenes/productos/moc-40/web/frontal-800.webp se convierte en /productos/moc-40/web/frontal-800.webp antes de llegar al bucket, que es exactamente la ruta del objeto.
gcloud compute url-maps validatecomprueba el mapa antes de aplicarlo, incluyendo pruebas de enrutamiento declaradas en el propio YAML. Es muy recomendable en un pipeline (06-01).
- Proxy de destino y regla de reenvío
Las dos últimas piezas. Aquí montamos primero la versión HTTP para validar que todo funciona; el certificado y el proxy HTTPS son de 03-07, pero dejamos ya escrita la forma final.
# --- Versión HTTP (para validar la cadena antes de tener certificado) ---
gcloud compute target-http-proxies create alpinashop-http-proxy \
--url-map=alpinashop-url-map
gcloud compute forwarding-rules create alpinashop-fr-http \
--global \
--address=alpinashop-lb-ip \
--target-http-proxy=alpinashop-http-proxy \
--ports=80 \
--load-balancing-scheme=EXTERNAL_MANAGED# --- Versión HTTPS (se completa en 03-07, con el certificado gestionado) ---
# gcloud compute target-https-proxies create alpinashop-https-proxy \
# --url-map=alpinashop-url-map \
# --ssl-certificates=alpinashop-cert \
# --ssl-policy=alpinashop-ssl-policy
#
# gcloud compute forwarding-rules create alpinashop-fr-https \
# --global --address=alpinashop-lb-ip \
# --target-https-proxy=alpinashop-https-proxy \
# --ports=443 --load-balancing-scheme=EXTERNAL_MANAGEDComprobación de extremo a extremo:
IP=$(gcloud compute addresses describe alpinashop-lb-ip --global --format="value(address)")
echo "IP del balanceador: $IP"
# La aplicación
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" "http://$IP/"
# Una imagen desde el bucket
curl -s -o /dev/null -w "%{http_code}\n" "http://$IP/imagenes/productos/moc-40/web/frontal-800.webp"
# Estado de los backends
gcloud compute backend-services get-health bs-catalogo-web --globalTen paciencia: un balanceador global recién creado tarda entre 5 y 10 minutos en propagarse por todos los puntos de presencia. Durante ese tiempo es normal recibir 404 o 502. Si a los quince minutos sigue fallando, entonces sí hay un problema real.
- Comprobaciones de estado en profundidad: por qué fallan
Este apartado es el más rentable de la lección. La mayoría de los balanceadores rotos no están mal construidos: tienen los backends en UNHEALTHY.
Primer punto, y el que más veces es la causa: las comprobaciones de estado no se originan en internet ni en tu subred. Google las lanza desde dos rangos fijos:
130.211.0.0/2235.191.0.0/16
Si el firewall de VPC no los permite, la comprobación nunca llega, la instancia se marca no saludable y el balanceador devuelve 502 Server Error sin decir por qué. Ya creamos la regla en 03-01 (fw-allow-lb-health-web), pero conviene saber verificarla:
gcloud compute firewall-rules list \
--filter="network:alpinashop-vpc AND sourceRanges:(130.211.0.0/22 OR 35.191.0.0/16)" \
--format="table(name, allowed[].map().firewall_rule().list(), targetTags.list(), disabled)"Lista de comprobación completa cuando un backend está UNHEALTHY:
| Nº | Causa | Cómo confirmarla | Solución |
|---|---|---|---|
| 1 | Firewall no permite 130.211.0.0/22 y 35.191.0.0/16 |
El comando anterior no devuelve nada | Crear la regla |
| 2 | La etiqueta de red de la regla no está en las instancias | gcloud compute instances list --format="table(name,tags.items.list())" |
Añadir la etiqueta a la plantilla del MIG |
| 3 | Puerto con nombre mal definido | gcloud compute instance-groups managed describe alpinashop-web-mig --region=europe-west1 --format="value(namedPorts)" |
set-named-ports |
| 4 | La ruta /salud no existe o devuelve 301/302 |
curl -i http://IP_INTERNA:8080/salud desde otra VM |
Corregir la aplicación; la comprobación exige 200, no sigue redirecciones |
| 5 | La aplicación escucha en 127.0.0.1 en vez de 0.0.0.0 |
ss -tlnp dentro de la VM |
gunicorn --bind 0.0.0.0:8080 |
| 6 | /salud consulta la base de datos y esta va lenta |
Latencia de /salud mayor que el timeout |
Hacer /salud superficial |
| 7 | La instancia aún está arrancando | Recién creada por el autoescalado | Ajustar --initial-delay del MIG |
| 8 | Protocolo equivocado (HTTPS en la comprobación, HTTP en la app) | describe de la health check |
Usar http |
Diagnóstico desde dentro de una VM, sin IP pública, gracias a IAP:
gcloud compute ssh alpinashop-web-1 --zone=europe-west1-b --tunnel-through-iap
# Dentro de la VM
curl -i http://localhost:8080/salud # ¿responde la app?
ss -tlnp | grep 8080 # ¿en qué interfaz escucha?
sudo journalctl -u gunicorn -n 50 --no-pagerY la vista agregada, que dice qué instancia concreta está mal:
gcloud compute backend-services get-health bs-catalogo-web --global \
--format="table(status.healthStatus[].instance, status.healthStatus[].healthState)"Hay dos tipos de comprobación en la plataforma y conviene no confundirlos:
| Tipo | Para qué sirve | Efecto de un fallo |
|---|---|---|
| Comprobación del balanceador | Decidir si una instancia recibe tráfico | Sale de rotación |
| Comprobación de autorreparación del MIG | Decidir si una instancia se recrea | Se destruye y se crea otra |
Si usas la misma comprobación agresiva para ambas cosas, un fallo transitorio de la aplicación puede provocar que el MIG destruya toda la flota en cadena. La práctica recomendada es que la comprobación de autorreparación sea más laxa (umbral de fallo más alto y ruta más simple) que la del balanceador.
- Políticas de balanceo, capacidad y afinidad de sesión
Modo de balanceo
Cada backend declara cuándo se considera lleno. Hay tres modos:
| Modo | Métrica | Cuándo usarlo |
|---|---|---|
RATE |
Peticiones por segundo | Aplicaciones web con peticiones homogéneas. El de AlpinaShop |
UTILIZATION |
Uso de CPU del grupo | Cargas con coste de CPU muy variable por petición |
CONNECTION |
Conexiones simultáneas | Balanceadores de capa 4 y conexiones largas |
Para AlpinaShop, RATE con --max-rate-per-instance=80 significa: "cada instancia se da por llena a 80 req/s". Ese número no se inventa; se mide. La forma correcta de obtenerlo:
- Lanzar una prueba de carga contra una sola instancia.
- Subir la tasa hasta que la latencia del percentil 95 se degrade o aparezcan errores.
- Tomar entre el 60 % y el 70 % de esa cifra como
max-rate-per-instance, dejando margen para picos.
Si el número es demasiado alto, el balanceador satura las instancias antes de desbordar a otras regiones. Si es demasiado bajo, el autoescalado añade máquinas innecesarias y sube el coste.
capacity-scaler: la palanca de operación más útil
--capacity-scaler es un multiplicador entre 0.0 y 1.0 sobre la capacidad declarada. Sirve para vaciar un backend sin borrarlo:
# Drenar el backend a la mitad (por ejemplo, durante un despliegue)
gcloud compute backend-services update-backend bs-catalogo-web \
--global \
--instance-group=alpinashop-web-mig \
--instance-group-region=europe-west1 \
--capacity-scaler=0.5
# Vaciarlo del todo (deja de recibir tráfico nuevo, respeta el drenaje)
gcloud compute backend-services update-backend bs-catalogo-web \
--global --instance-group=alpinashop-web-mig \
--instance-group-region=europe-west1 \
--capacity-scaler=0.0Es la forma limpia de hacer un despliegue azul/verde o de sacar de servicio una región con problemas.
Afinidad de sesión
Por defecto no hay afinidad: cada petición puede ir a una instancia distinta. Eso es lo correcto para una aplicación sin estado, que es como debe diseñarse.
| Tipo de afinidad | Basada en | Coste |
|---|---|---|
NONE (por defecto) |
Nada | Reparto óptimo |
CLIENT_IP |
IP del cliente | Mal reparto tras NAT corporativo |
GENERATED_COOKIE |
Cookie que genera el balanceador | Reparto aceptable |
HEADER_FIELD |
Una cabecera concreta | Requiere control del cliente |
AlpinaShop no necesita afinidad, y es importante entender por qué: el carrito y la sesión viven en Firestore (decidido en 02-06), no en la memoria de la instancia. La afinidad es un parche para aplicaciones con estado local, y siempre degrada el reparto: una instancia puede quedar sobrecargada mientras otras están ociosas, y el autoescalado no puede aliviarla porque los clientes ya están pegados a ella.
Otras opciones del servicio de backend
# Política de reintentos y detección de valores atípicos (solo EXTERNAL_MANAGED)
gcloud compute backend-services update bs-catalogo-web --global \
--custom-request-header="X-Cliente-Region:{client_region}" \
--custom-response-header="X-Cache-Estado:{cdn_cache_status}"Las cabeceras personalizadas con variables ({client_region}, {client_city}, {cdn_cache_status}) son muy útiles: permiten que la aplicación sepa desde qué país entra el cliente sin geolocalizar nada, y que puedas depurar la caché mirando una cabecera de respuesta (lo usaremos en 03-03).
- Redirección de HTTP a HTTPS
Servir la tienda por HTTP sin cifrar no es aceptable. La redirección se hace en el propio balanceador, no en la aplicación, para que ni un solo byte de contenido viaje en claro.
Se implementa con un mapa de URL específico que no tiene backends, solo una acción de redirección:
# Mapa de URL que solo redirige
gcloud compute url-maps import alpinashop-redir-map --global --quiet --source=- <<'EOF'
name: alpinashop-redir-map
defaultUrlRedirect:
httpsRedirect: true
redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
stripQuery: false
EOF
# El proxy HTTP apunta a ese mapa en vez de al mapa real
gcloud compute target-http-proxies update alpinashop-http-proxy \
--url-map=alpinashop-redir-mapExplicación de las opciones:
httpsRedirect: true: cambia el esquema ahttpsconservando host y ruta.redirectResponseCode: MOVED_PERMANENTLY_DEFAULT: es un 301. Los navegadores lo cachean, así que las visitas siguientes ni siquiera hacen la petición en claro. Si estás probando y no quieres que se quede pegado en el navegador, usaFOUND(302) mientras tanto.stripQuery: false: conserva la cadena de consulta. Ponerlo atruerompería los enlaces de campaña con parámetrosutm_*.
La cabecera HSTS, que hace que el navegador ni siquiera intente HTTP, la emite la aplicación y se explica en 03-07.
- Escalado global: por qué no hay que "precalentar"
Quien viene de otros proveedores está acostumbrado a "precalentar" el balanceador antes de una campaña: avisar al proveedor de que va a llegar tráfico para que amplíe la capacidad del balanceador. En Google Cloud eso no existe y no hace falta.
El motivo es arquitectónico:
- El balanceador global no es un conjunto de instancias tuyas. Es una función de la infraestructura de red de Google, la misma que atiende a Búsqueda, YouTube y Gmail. Su capacidad no está dimensionada para ti.
- La IP anycast se anuncia desde todos los PoP simultáneamente. Un pico de tráfico no llega a un punto, sino que se reparte geográficamente por construcción.
- El balanceador absorbe además los ataques volumétricos de capa 3 y 4 sin que tú configures nada, porque la mitigación está en la propia red.
Lo que sí hay que dimensionar es lo que hay detrás: el MIG alpinashop-web-mig está configurado para 2–10 instancias, y si la campaña de otoño necesita más, el límite se sube en el autoescalado. El cuello de botella nunca será el balanceador; será tu aplicación o tu base de datos.
Consecuencia práctica para el equipo de AlpinaShop: antes de la campaña, la lista de comprobación no incluye "avisar al balanceador", sino subir max-num-replicas del MIG, revisar max-rate-per-instance con datos reales y comprobar que la réplica de lectura de Cloud SQL aguanta.
- Balanceadores internos para servicios internos
No todo el tráfico es público. Cuando AlpinaShop tenga servicios internos —el motor de recomendaciones, la API de stock del almacén, el generador de informes de Lucía— esos servicios no deben tener IP pública. La pieza correcta es un balanceador interno:
# Balanceador de aplicaciones interno (capa 7) para un servicio interno
gcloud compute health-checks create http hc-stock-interno \
--port=8080 --request-path=/salud --region=europe-west1
gcloud compute backend-services create bs-stock-interno \
--region=europe-west1 \
--load-balancing-scheme=INTERNAL_MANAGED \
--protocol=HTTP \
--health-checks=hc-stock-interno \
--health-checks-region=europe-west1
# Subred de solo proxy: obligatoria para los balanceadores internos de capa 7.
# Es un rango reservado del que toman IP los proxies gestionados por Google.
gcloud compute networks subnets create sn-proxy-euw1 \
--network=alpinashop-vpc \
--region=europe-west1 \
--range=10.10.10.0/24 \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVEDos cosas nuevas y una advertencia:
- El esquema es
INTERNAL_MANAGED, noEXTERNAL_MANAGED. - Los balanceadores internos de capa 7 necesitan una subred de solo proxy (
--purpose=REGIONAL_MANAGED_PROXY) por región. Es un rango que no aloja VM tuyas: lo usan los proxies de Google. Sin ella, la creación falla con un mensaje que no siempre es evidente. En el plan de direccionamiento de 03-01 hay que reservarle sitio: aquí hemos usado10.10.10.0/24, dentro del bloque libre previsto. - Reglas de firewall: el tráfico llega desde el rango de la subred de solo proxy, no desde el cliente original. Hay que permitir
10.10.10.0/24hacia los backends.
Cuándo usar cada uno:
| Servicio de AlpinaShop | Balanceador |
|---|---|
| Catálogo público | Aplicaciones externo global (el que hemos construido) |
| API de stock consumida solo por la tienda | Aplicaciones interno |
| Base de datos de sesión con protocolo propio | Red de paso a través interno |
- NEG sin servidor: Cloud Run detrás del mismo balanceador
En 02-07 decidimos (DA-001) que el catálogo acabará en Cloud Run. Cloud Run ya da una URL HTTPS propia, así que ¿para qué ponerle un balanceador delante? Por cuatro motivos que ya conoces:
- Dominio propio y certificado gestionado unificados (03-07).
- Cloud CDN sobre el contenido de la aplicación (03-03).
- Cloud Armor: la URL nativa de Cloud Run no se puede proteger con WAF; la del balanceador sí (03-05).
- Un único mapa de URL que reparte entre Cloud Run, el bucket y lo que venga.
La pieza que lo hace posible es el NEG sin servidor (serverless network endpoint group): un backend que no apunta a máquinas, sino a un servicio gestionado.
# NEG sin servidor que apunta al futuro servicio Cloud Run alpinashop-web
gcloud compute network-endpoint-groups create neg-alpinashop-web \
--region=europe-west1 \
--network-endpoint-type=serverless \
--cloud-run-service=alpinashop-web
# Servicio de backend que lo usa (sin comprobación de estado: la gestiona Cloud Run)
gcloud compute backend-services create bs-alpinashop-run \
--global \
--load-balancing-scheme=EXTERNAL_MANAGED
gcloud compute backend-services add-backend bs-alpinashop-run \
--global \
--network-endpoint-group=neg-alpinashop-web \
--network-endpoint-group-region=europe-west1Y entonces la migración del MIG a Cloud Run es un cambio en el mapa de URL, no una reconstrucción:
# Enviar solo /nuevo/* a Cloud Run para probar en producción con tráfico real
gcloud compute url-maps add-path-matcher alpinashop-url-map \
--path-matcher-name=matcher-migracion \
--default-service=bs-catalogo-web \
--path-rules="/nuevo/*=bs-alpinashop-run" \
--new-hosts="alpinashop.example"Esto es lo que hace que el trabajo de hoy no se tire a la basura mañana: el balanceador sobrevive al cambio de backend. La IP, el dominio, el certificado, las reglas de Cloud Armor y la configuración de CDN permanecen; solo cambia a dónde apunta el mapa. Los detalles de Cloud Run son de 07-02.
Existen NEG de varios tipos, y conviene tenerlos ubicados:
| Tipo de NEG | Apunta a | Uso |
|---|---|---|
Zonal (GCE_VM_IP_PORT) |
IP:puerto de VM o pods | GKE con Ingress/Gateway nativo |
| Sin servidor | Cloud Run, Cloud Functions, App Engine | El caso de arriba |
Internet (INTERNET_FQDN_PORT) |
Un servicio externo por nombre | Poner CDN o Armor delante de un origen ajeno |
| Híbrido | Un servidor local | Migraciones (07-03) |
- Registro y métricas del balanceador
Sin observabilidad, un balanceador es una caja negra. Actívalo desde el principio:
gcloud compute backend-services update bs-catalogo-web \
--global \
--enable-logging \
--logging-sample-rate=1.0--logging-sample-rate=1.0 registra el 100 % de las peticiones. En un sitio con tráfico alto se baja a 0.1 para contener el coste de logs; en AlpinaShop, con picos de 20 req/s, el 100 % es perfectamente asumible y facilita mucho el diagnóstico.
Consultas útiles:
# Peticiones que terminaron en 5xx en la última hora
gcloud logging read '
resource.type="http_load_balancer"
AND httpRequest.status>=500
' --project=alpinashop-prod --limit=20 --freshness=1h \
--format="table(
timestamp,
httpRequest.requestUrl,
httpRequest.status,
jsonPayload.statusDetails
)"El campo jsonPayload.statusDetails es el más valioso del log del balanceador. Traduce el 502 genérico a una causa concreta:
statusDetails |
Significado | Qué mirar |
|---|---|---|
failed_to_pick_backend |
Ningún backend saludable | Comprobaciones de estado (apartado 9) |
backend_timeout |
El backend no respondió a tiempo | --timeout y el rendimiento de la app |
backend_connection_closed_before_data_sent_to_client |
El backend cortó la conexión | Keepalive de gunicorn menor que el del balanceador |
response_sent_by_backend |
Todo normal | El código lo devolvió la aplicación |
denied_by_security_policy |
Bloqueado por Cloud Armor | 03-05 |
client_disconnected_before_any_response |
El cliente se fue | Normal en tráfico móvil |
El caso de backend_connection_closed_before_data_sent_to_client merece un apunte porque es sutil y muy común: el balanceador global mantiene conexiones persistentes con el backend durante 10 minutos. Si gunicorn cierra la conexión antes (su keepalive por defecto son 2 segundos), el balanceador se encuentra la conexión cerrada a mitad y devuelve 502 esporádicos, imposibles de reproducir a mano. La solución es configurar gunicorn con un keepalive superior al del balanceador:
Métricas recomendadas para el panel de Marta (se construye en 06-04):
| Métrica | Para qué |
|---|---|
loadbalancing.googleapis.com/https/request_count |
Volumen, por código de respuesta |
loadbalancing.googleapis.com/https/total_latencies |
Latencia extremo a extremo (p50, p95, p99) |
loadbalancing.googleapis.com/https/backend_latencies |
Latencia solo del backend: separa el problema |
loadbalancing.googleapis.com/https/backend_request_count |
Peticiones que llegaron al backend (frente a las servidas por CDN) |
La diferencia entre total_latencies y backend_latencies es la que dice si el problema es tuyo o de la red: si la total sube y la del backend no, el problema está en el trayecto hasta el cliente.
Errores Comunes y Consejos
- Olvidar el firewall de
130.211.0.0/22y35.191.0.0/16. Es la causa número uno de un balanceador que devuelve 502 recién creado. Antes de depurar nada más, comprueba esa regla. - No definir el puerto con nombre en el MIG. El servicio de backend usa
--port-name, y si el grupo no lo declara, el tráfico va al puerto 80 y nada responde. - Impacientarse. Un balanceador global tarda entre 5 y 10 minutos en propagarse. Los primeros 404 y 502 son normales.
- Que
/saludconsulte la base de datos. Convierte un fallo parcial en una caída total: todos los backends se marcan no saludables a la vez. - Usar la misma comprobación para el balanceador y para la autorreparación del MIG. Un fallo transitorio puede provocar que el grupo destruya y recree toda la flota.
- Confundir
EXTERNALconEXTERNAL_MANAGED. Para desarrollos nuevos usaEXTERNAL_MANAGED; mezclarlos entre el servicio de backend y la regla de reenvío produce errores de validación confusos. - Olvidar el
urlRewritedel backend de bucket. Si el mapa envía/imagenes/*al bucket sin reescribir, se busca un objeto cuyo nombre empieza porimagenes/y se obtiene 404 sistemático. - Activar afinidad de sesión "por si acaso". Degrada el reparto y esconde un problema de diseño. Si la aplicación necesita afinidad, lo que hay que arreglar es el estado, no el balanceador.
max-rate-per-instancepuesto a ojo. Mídelo con una prueba de carga sobre una instancia y aplica un margen del 30-40 %.- No activar el registro del balanceador. Sin
statusDetailsestás depurando a ciegas. keepalivede gunicorn demasiado bajo. Provoca 502 esporádicos irreproducibles. Ponlo por encima de los 600 segundos del balanceador.- No borrar los recursos de una prueba. La cadena tiene siete objetos; se borran en orden inverso al de creación. Las IP estáticas huérfanas se siguen facturando.
Ejercicios
Ejercicio 1 — Elegir el balanceador correcto
Para cada escenario de AlpinaShop, indica qué balanceador corresponde y justifícalo en una línea:
- La tienda pública
alpinashop.example, con clientes en toda Europa, HTTPS, caché de imágenes y WAF. - Una API interna de stock que solo consumen las instancias del catálogo dentro de
alpinashop-vpc. - Un servicio de sincronización con el almacén que habla un protocolo propio sobre TCP en el puerto 9000 y necesita ver la IP real del cliente.
- Un panel interno de informes para Lucía que enruta
/informes/*a un servicio y/exportar/*a otro, accesible solo desde la red interna.
Ejercicio 2 — Depurar un balanceador roto
Marta ha construido el balanceador siguiendo la lección, pero curl http://$IP/ devuelve 502 Server Error y gcloud compute backend-services get-health bs-catalogo-web --global muestra todas las instancias en UNHEALTHY. Se sabe que:
- Desde otra VM de
sn-web-euw1,curl http://10.10.0.7:8080/saluddevuelve200 OK. - La regla
fw-allow-lb-health-webexiste y permitetcp:80,tcp:8080desde los rangos correctos hacia la etiquetaweb-catalogo.
Escribe la secuencia de comandos de diagnóstico y la causa más probable.
Ejercicio 3 — Ampliar el mapa de URL
AlpinaShop quiere tres cosas nuevas:
- Que
blog.alpinashop.examplevaya a un servicio de backend distinto llamadobs-blog. - Que
/api/*tenga un tiempo de espera de 120 segundos porque hay una exportación lenta, sin cambiar el del resto del sitio. - Que
/descargas/manual-mochilas.pdfredirija de forma permanente a/imagenes/documentos/manual-mochilas-2026.pdf.
Indica qué recursos hay que crear o modificar para cada punto y escribe el fragmento de YAML del mapa de URL para el punto 3.
Soluciones
Solución 1
- Balanceador de aplicaciones externo global. Es tráfico HTTP público mundial, y es el único que admite Cloud CDN y Cloud Armor con IP anycast global.
- Balanceador de aplicaciones interno (
INTERNAL_MANAGED), regional eneurope-west1. No debe tener IP pública y el enrutamiento por ruta puede ser útil más adelante. Requiere subred de solo proxy. - Balanceador de red de paso a través externo (capa 4, regional). Es el único que no termina la conexión y por tanto conserva la IP de origen real; además, el protocolo no es HTTP, así que un balanceador de capa 7 no sirve.
- Balanceador de aplicaciones interno. Necesita enrutamiento por ruta (capa 7) y no debe ser accesible desde internet. Si además hiciera falta acceso desde fuera de la oficina, la alternativa correcta sería el balanceador externo global protegido con IAP (03-04), no abrirlo.
Solución 2
# 1) ¿Están las instancias etiquetadas como web-catalogo?
gcloud compute instances list \
--filter="name~alpinashop-web-mig" \
--format="table(name, zone, status, tags.items.list())"
# 2) ¿Tiene el MIG definido el puerto con nombre?
gcloud compute instance-groups managed describe alpinashop-web-mig \
--region=europe-west1 \
--format="value(namedPorts)"
# 3) ¿A qué puerto y ruta apunta la comprobación?
gcloud compute health-checks describe hc-catalogo \
--format="yaml(type, httpHealthCheck)"
# 4) ¿Qué port-name usa el servicio de backend?
gcloud compute backend-services describe bs-catalogo-web --global \
--format="value(portName, protocol, timeoutSec)"Causa más probable: falta el puerto con nombre. El firewall está bien y la aplicación responde en el 8080 desde dentro de la subred, así que el paquete de comprobación sí puede llegar. Lo que ocurre es que el servicio de backend pide el puerto llamado http-catalogo y el grupo de instancias no lo tiene definido, con lo que el balanceador dirige la comprobación y el tráfico al puerto por defecto (80), donde no hay nada escuchando.
gcloud compute instance-groups managed set-named-ports alpinashop-web-mig \
--region=europe-west1 \
--named-ports=http-catalogo:8080La segunda causa candidata sería que la plantilla de instancia del MIG no aplique la etiqueta web-catalogo a las máquinas nuevas: la regla existiría pero no se aplicaría a nadie. Lo confirma el comando 1.
Solución 3
Punto 1 — blog.alpinashop.example. Se crea el servicio de backend bs-blog y se añade al mapa una hostRule nueva con su propio pathMatcher. Además hay que incluir el nombre en el certificado gestionado (03-07) y crear el registro DNS correspondiente.
gcloud compute url-maps add-path-matcher alpinashop-url-map \
--path-matcher-name=matcher-blog \
--default-service=bs-blog \
--new-hosts=blog.alpinashop.examplePunto 2 — tiempo de espera de /api/*. El timeout es una propiedad del servicio de backend, no de la regla de ruta. Por tanto hay que crear un segundo servicio de backend (por ejemplo bs-catalogo-api) apuntando al mismo MIG pero con --timeout=120s, y enrutar /api/* hacia él.
gcloud compute backend-services create bs-catalogo-api \
--global --load-balancing-scheme=EXTERNAL_MANAGED \
--protocol=HTTP --port-name=http-catalogo \
--health-checks=hc-catalogo --timeout=120s
gcloud compute backend-services add-backend bs-catalogo-api \
--global --instance-group=alpinashop-web-mig \
--instance-group-region=europe-west1 \
--balancing-mode=RATE --max-rate-per-instance=80Punto 3 — redirección permanente. Se hace en el propio mapa de URL, sin tocar la aplicación:
pathMatchers:
- name: matcher-principal
defaultService: .../backendServices/bs-catalogo-web
pathRules:
- paths:
- /descargas/manual-mochilas.pdf
urlRedirect:
pathRedirect: /imagenes/documentos/manual-mochilas-2026.pdf
redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
stripQuery: trueNota: una pathRule con urlRedirect no lleva service. Y ojo con el orden: las rutas más específicas deben poder ganar a las genéricas; el balanceador aplica la coincidencia más larga, así que /descargas/manual-mochilas.pdf gana a /descargas/*.
Conclusión
AlpinaShop ya no depende de una máquina. Has entendido el catálogo de balanceadores de Google Cloud reduciéndolo a tres preguntas —capa 7 o capa 4, externo o interno, global o regional— y sabes que para tráfico web público la respuesta casi siempre es el balanceador de aplicaciones externo global, con la distinción clara entre proxy y paso a través.
Has construido la cadena completa de dentro hacia fuera: la comprobación hc-catalogo contra /salud en el 8080, el puerto con nombre http-catalogo en el MIG, el servicio de backend bs-catalogo-web con drenaje de conexiones y modo RATE a 80 req/s por instancia, el backend de bucket bb-catalogo-imagenes que sirve las imágenes de alpinashop-catalogo sin tocar la aplicación, el mapa alpinashop-url-map que envía /imagenes/* y /estatico/* al bucket con pathPrefixRewrite y el resto al MIG, y la regla de reenvío sobre la IP global alpinashop-lb-ip que reservamos en 03-01.
Has aprendido a diagnosticar lo único que se rompe de verdad: las comprobaciones de estado, con su lista de ocho causas encabezada por los rangos 130.211.0.0/22 y 35.191.0.0/16, y la distinción entre la comprobación del balanceador y la de autorreparación del MIG. Sabes ajustar capacidad con max-rate-per-instance medido, vaciar un backend con capacity-scaler, y por qué AlpinaShop no necesita afinidad de sesión: el estado vive en Firestore, no en las instancias. Has redirigido HTTP a HTTPS en el borde, has visto por qué no hace falta precalentar nada de cara a la campaña de otoño, dónde encajan los balanceadores internos y su subred de solo proxy, y cómo un NEG sin servidor permitirá mover el catálogo a Cloud Run (DA-001) cambiando solo el mapa de URL, conservando IP, dominio, certificado, caché y WAF. Y has activado el registro, que convierte un 502 opaco en un statusDetails accionable.
Queda una ineficiencia evidente. Cada vez que un cliente de Lisboa abre una ficha de producto, las imágenes viajan desde europe-west1 hasta Portugal, aunque sean los mismos bytes que se enviaron hace un minuto a otro cliente. Con 60 GB de catálogo y clientes repartidos por toda Europa, eso es latencia innecesaria y una factura de salida de datos que crece con cada visita. En la siguiente lección, 03-03, Cloud CDN, activamos la caché sobre el mismo servicio de backend que acabamos de construir: las imágenes pasarán a servirse desde el punto de presencia más cercano al cliente, aprenderás a controlar qué se cachea y durante cuánto tiempo, a evitar que los parámetros utm_* de las campañas arruinen el ratio de aciertos, y a medir el ahorro real en latencia y en euros.
Curso de Google Cloud Platform (GCP)
Módulo 1: Introducción a Google Cloud Platform
- ¿Qué es Google Cloud Platform?
- Configuración de tu cuenta de GCP
- Descripción general de la consola de GCP
- Proyectos, jerarquía de recursos y facturación
- Regiones, zonas y modelo de responsabilidad compartida
- Cloud Shell y la CLI de gcloud
Módulo 2: Servicios principales de GCP
- Compute Engine: máquinas virtuales en Google Cloud
- Cloud Storage: almacenamiento de objetos
- Cloud SQL: bases de datos relacionales gestionadas
- App Engine: plataforma como servicio
- Google Kubernetes Engine (GKE)
- Bases de datos NoSQL: Firestore, Bigtable y Spanner
- Cómo elegir el servicio de cómputo adecuado
Módulo 3: Redes y seguridad
- Redes VPC
- Balanceo de carga en la nube
- Cloud CDN
- Gestión de identidad y acceso (IAM)
- Cloud Armor
- Secretos y cifrado: Secret Manager y Cloud KMS
- Cloud DNS, certificados TLS y publicación segura de servicios
Módulo 4: Datos y análisis
- BigQuery: el almacén de datos analítico
- Cloud Dataflow: procesamiento de datos por lotes y en streaming
- Cloud Dataproc: Spark y Hadoop gestionados
- Cloud Pub/Sub: mensajería asíncrona
- Cloud Data Fusion: integración de datos sin código
- Orquestación de pipelines con Cloud Composer y Workflows
- Gobierno del dato y cuadros de mando con Dataplex y Looker Studio
Módulo 5: Aprendizaje automático e IA
- Vertex AI: la plataforma de machine learning de GCP
- AutoML: modelos a medida sin escribir código
- TensorFlow en GCP: entrenamiento y servicio de modelos
- API de lenguaje natural
- API de visión
- IA generativa en Vertex AI: modelos Gemini y embeddings
- MLOps: del modelo al producto con Vertex AI Pipelines
Módulo 6: DevOps y monitoreo
- Cloud Build: integración continua en GCP
- Cloud Source Repositories y gestión del código fuente
- Cloud Functions: funciones sin servidor
- Cloud Monitoring (antes Stackdriver): métricas, paneles y alertas
- Cloud Deployment Manager e infraestructura como código nativa
- Cloud Logging y Cloud Trace: logs, trazas y diagnóstico
- Terraform en GCP: infraestructura como código en la práctica
Módulo 7: Temas avanzados de GCP
- Híbrido y multinube con Anthos
- Computación sin servidor con Cloud Run
- Redes avanzadas: VPC compartida, peering y conectividad híbrida
- Mejores prácticas de seguridad
- Gestión y optimización de costos
- Fiabilidad: SLO, alta disponibilidad y recuperación ante desastres
- Gobierno a escala: organización, políticas y auditoría
