Saltar al contenido
Gontzal Bilbao
← cheatsheets

gcp · cloud-run

GCP Cloud Run & Ops

Comandos para operar Cloud Run: logs, build y push a Artifact Registry, despliegues, Cloud SQL y Secret Manager.

14 secciones · 62 comandos · revisado 6 oct 2026

Tus valores

Cámbialos aquí y se aplican a todos los comandos. Se guardan en tu navegador.

Ábrela cuando tengas que desplegar o diagnosticar un servicio de Cloud Run desde la terminal. Si algo falla y no sabes por dónde empezar, ve a los escenarios del final: cada uno da el orden en que mirar.

1. Configurar gcloud

Inicia sesión en Google Cloud desde la terminal.

gcloud auth login

Fija el proyecto por defecto.

gcloud config set project PROJECT_ID

Fija la región por defecto de Cloud Run.

gcloud config set run/region REGION

Autoriza a Docker a subir imágenes a Artifact Registry (una sola vez).

gcloud auth configure-docker REGION-docker.pkg.dev

Crea credenciales para herramientas locales, como el proxy de Cloud SQL.

gcloud auth application-default login

2. Logs y estado del servicio

Lee las últimas 50 líneas de log del servicio.

gcloud run services logs read mi-api --region REGION --limit 50

Sigue los logs del servicio en tiempo real.

gcloud beta run services logs tail mi-api --region REGION

Lista los servicios con su URL y su última revisión.

gcloud run services list --region REGION

Muestra la configuración del servicio: variables, secretos, escalado y revisión.

gcloud run services describe mi-api --region REGION

3. Filtros de Logs Explorer

Filtro de Logs Explorer que deja solo avisos y errores del servicio.

resource.type="cloud_run_revision" AND resource.labels.service_name="mi-api" AND severity>=WARNING

Filtro que busca un texto concreto entre los errores del servicio.

resource.type="cloud_run_revision" AND resource.labels.service_name="mi-api" AND textPayload:"[HTTP]" AND severity>=ERROR

Lanza la misma consulta desde la terminal y devuelve JSON.

gcloud logging read \
  'resource.type="cloud_run_revision" AND resource.labels.service_name="mi-api" AND severity>=ERROR' \
  --limit 30 --format json

4. Build y push a Artifact Registry

Guarda el commit actual como versión de la imagen, para poder trazarla.

VERSION=$(git rev-parse --short HEAD)

Construye la imagen desde la raíz del repositorio.

docker build -f apps/api/Dockerfile -t mi-api:$VERSION .

Etiqueta la imagen para el registro con la versión y con latest.

docker tag mi-api:$VERSION REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:$VERSION
docker tag mi-api:$VERSION REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:latest

Sube las dos etiquetas al registro.

docker push REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:$VERSION
docker push REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:latest

Lista las imágenes del repositorio con sus etiquetas.

gcloud artifacts docker images list REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api --include-tags

En un frontend, las variables públicas (NEXT_PUBLIC_*, VITE_*) se fijan en el build con --build-arg, no en el despliegue.

5. Desplegar en Cloud Run

Despliega el servicio con Cloud SQL por socket, secretos y variables de entorno.

gcloud run deploy mi-api \
  --image=REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:latest \
  --region=REGION \
  --allow-unauthenticated \
  --port=4000 \
  --min-instances=0 \
  --max-instances=10 \
  --memory=512Mi \
  --cpu=1 \
  --add-cloudsql-instances=PROJECT_ID:REGION:mi-db \
  --set-secrets="DATABASE_URL=DATABASE_URL:latest,REDIS_URL=REDIS_URL:latest" \
  --set-env-vars="NODE_ENV=production,PORT=4000"

Despliega con salida a la VPC para llegar a recursos privados, como un Redis gestionado.

gcloud run deploy mi-api \
  --image=REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:latest \
  --region=REGION \
  --network=default --subnet=default \
  --vpc-egress=private-ranges-only

Cambia el escalado sin volver a desplegar la imagen.

gcloud run services update mi-api --min-instances=1 --region REGION

Devuelve todo el tráfico a una revisión anterior.

gcloud run services update-traffic mi-api --to-revisions=mi-api-00012-abc=100 --region REGION

6. Conectar a Cloud SQL

Abre un túnel autenticado a la instancia; deja esta terminal abierta mientras consultas.

cloud-sql-proxy PROJECT_ID:REGION:mi-db --port=5432

Conecta con psql a través del túnel local.

psql "host=127.0.0.1 port=5432 dbname=mi_db user=admin"

Conecta directamente y deja que gcloud gestione el túnel.

gcloud sql connect mi-db --user=admin --database=mi_db

Muestra la configuración de la instancia.

gcloud sql instances describe mi-db

Lista las copias de seguridad de la instancia.

gcloud sql backups list --instance=mi-db

7. Consultas para inspeccionar la base

Muestra el tamaño de la base de datos.

SELECT pg_size_pretty(pg_database_size(current_database()));

Lista las 10 tablas que más ocupan.

SELECT relname AS tabla, pg_size_pretty(pg_total_relation_size(relid)) AS tamano
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

Lista las conexiones que están haciendo algo.

SELECT pid, usename, state, query
FROM pg_stat_activity
WHERE state <> 'idle';

8. Secret Manager

Crea un secreto vacío.

gcloud secrets create DATABASE_URL --replication-policy=automatic

Añade un valor al secreto como versión nueva; así también se rota.

echo -n "postgresql://..." | gcloud secrets versions add DATABASE_URL --data-file=-

Lee el valor de la última versión.

gcloud secrets versions access latest --secret=DATABASE_URL

Lista los secretos del proyecto.

gcloud secrets list

Lista las versiones de un secreto.

gcloud secrets versions list DATABASE_URL

Da a la cuenta de servicio de Cloud Run permiso para leer secretos.

PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)")
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

Como el servicio lee :latest, tras rotar un secreto basta con redesplegar o actualizar el servicio.

9. Comprobar tras el despliegue

Comprueba que la API responde.

curl https://api.mi-dominio.com/health

Muestra los registros DNS pendientes de un dominio mapeado al servicio.

gcloud run domain-mappings describe --domain=api.mi-dominio.com --region REGION

10. Escenario: la revisión nueva no arranca

situaciónEl despliegue falla con «container failed to start and listen on the port» y la revisión nueva no queda lista.

qué hay que entender

Cloud Run le pasa al contenedor la variable PORT (8080 si no se indica otro con --port) y espera que el proceso escuche en ese puerto y en 0.0.0.0. Si escucha en localhost, en otro puerto o muere antes, la comprobación de arranque falla y la revisión no queda lista.

Mientras la revisión nueva no está lista, el tráfico se queda en la anterior: el servicio sigue en pie y lo roto es solo el despliegue. El motivo está en los logs de esa revisión, no en los del servicio en general.

pasos, en orden

  1. Lista las revisiones para ver cuál falló y cuál sigue sirviendo tráfico.

    gcloud run revisions list --service mi-api --region REGION
  2. Lee los logs solo de la revisión que falló: ahí sale el error de arranque de la aplicación.

    gcloud logging read \
      'resource.labels.revision_name="mi-api-00013-xyz"' \
      --limit 50
  3. Comprueba qué puerto espera Cloud Run, para compararlo con el que abre la aplicación.

    gcloud run services describe mi-api --region REGION \
      --format="value(spec.template.spec.containers[0].ports[0].containerPort)"
  4. Reproduce el arranque en local con la misma imagen y la misma variable PORT.

    docker run --rm -p 8080:8080 -e PORT=8080 \
      REGION-docker.pkg.dev/PROJECT_ID/mi-repo/api:latest
  5. Si la aplicación usa un puerto fijo, alinea Cloud Run con él; si no, corrige el código para que lea PORT y escuche en 0.0.0.0.

    gcloud run services update mi-api --port=4000 --region REGION

cómo sé que está resuelto

gcloud run revisions list muestra la revisión nueva como lista y con el 100 % del tráfico, y curl https://api.mi-dominio.com/health responde.

si no funciona

Si los logs están vacíos, el proceso ni siquiera arrancó. Una imagen construida en un Mac con chip ARM da «exec format error»: reconstruye con docker build --platform linux/amd64. Si la aplicación arranca pero tarda, la comprobación puede agotarse antes: revisa qué hace al iniciar, como migraciones o conexiones que esperan. Una variable o un secreto que falta también la tumba en el arranque: compáralos con la revisión anterior en gcloud run revisions describe.

en una entrevista«Despliegas en Cloud Run y la revisión nueva no arranca. ¿Qué miras?»
  1. Primero, el impacto: el tráfico sigue en la revisión anterior, así que el servicio no está caído; lo que ha fallado es el despliegue.
  2. Logs de la revisión concreta, filtrando por revision_name, porque el error de arranque está ahí.
  3. Las causas típicas: no leer PORT, escuchar en localhost en vez de 0.0.0.0, una variable que falta o una imagen de otra arquitectura.
  4. Reproducir en local con docker run -e PORT=8080, que da el mismo error en segundos.
  5. Corregir y volver a desplegar, sin tocar el tráfico, que ya está donde debe.

La trampa: buscar el error en los logs del servicio entero, donde la revisión sana tapa a la rota.

11. Escenario: volver a la revisión anterior

situaciónLa revisión nueva arranca, pero tras el despliegue la API devuelve errores o datos mal.

qué hay que entender

Cada despliegue crea una revisión inmutable, y las anteriores se conservan. Volver atrás no es construir ni desplegar nada: es mover el tráfico a una revisión que ya existe, y tarda segundos.

Al fijar el tráfico en una revisión concreta, el servicio deja de mandarlo a la última de forma automática. Los siguientes despliegues no reciben tráfico hasta que lo devuelvas con --to-latest.

pasos, en orden

  1. Lista las revisiones y localiza la última que funcionaba.

    gcloud run revisions list --service mi-api --region REGION
  2. Mira cómo está repartido el tráfico ahora mismo.

    gcloud run services describe mi-api --region REGION --format="yaml(status.traffic)"
  3. Manda todo el tráfico a la revisión buena.

    gcloud run services update-traffic mi-api --region REGION \
      --to-revisions=mi-api-00012-abc=100
  4. Ponle una etiqueta a la revisión rota: tendrá su propia URL para investigarla sin tráfico real.

    gcloud run services update-traffic mi-api --region REGION \
      --set-tags=prueba=mi-api-00013-xyz
  5. Cuando despliegues la corrección, devuelve el tráfico a la última revisión.

    gcloud run services update-traffic mi-api --to-latest --region REGION

cómo sé que está resuelto

status.traffic muestra el 100 % en la revisión buena y los errores desaparecen de los logs del servicio en unos minutos.

si no funciona

Si con la revisión anterior sigue fallando, el problema no es el código. Una migración de base de datos no se deshace al mover el tráfico. Y una revisión que lee un secreto con :latest toma el valor actual, no el que tenía cuando se desplegó. Si la revisión anterior tenía min-instances a 0, las primeras peticiones pueden ir lentas mientras arrancan instancias.

en una entrevista«Has desplegado una versión con un fallo. ¿Cómo vuelves atrás sin redesplegar?»
  1. Restaurar antes que entender: muevo el tráfico a la última revisión buena; tarda segundos y no necesita build.
  2. Conservo la rota con una etiqueta, para reproducir el fallo en su propia URL sin usuarios.
  3. Compruebo qué no vuelve atrás con el tráfico: el esquema de la base de datos y los secretos que se leen con :latest.
  4. Al corregir, devuelvo el tráfico con --to-latest, porque si no, los despliegues siguientes no lo reciben.
  5. Para la próxima vez: desplegar con --no-traffic y abrir el tráfico poco a poco con --to-revisions.

Lo que no haría: hacer un revert y esperar a un build nuevo con el servicio fallando.

12. Escenario: rotar un secreto sin cortar el servicio

situaciónHay que cambiar una contraseña o una clave de API que el servicio lee de Secret Manager.

qué hay que entender

Un secreto expuesto como variable de entorno se resuelve al arrancar cada instancia. Con :latest, las instancias que ya están en marcha siguen con el valor viejo y solo las que arrancan después leen el nuevo. Para que todas lo lean hace falta una revisión nueva.

Rotar sin corte exige que, durante el cambio, el sistema de destino acepte las dos credenciales. Por eso la versión vieja se deshabilita al final, cuando ya nadie la usa, y no se destruye hasta estar seguro.

pasos, en orden

  1. Mira las versiones del secreto y cuál es la actual.

    gcloud secrets versions list DATABASE_URL
  2. Añade el valor nuevo como versión nueva; pasa a ser latest.

    echo -n "postgresql://..." | gcloud secrets versions add DATABASE_URL --data-file=-
  3. Comprueba cómo lo lee el servicio: si la referencia es latest o una versión fija.

    gcloud run services describe mi-api --region REGION \
      --format="yaml(spec.template.spec.containers[0].env)"
  4. Fuerza una revisión nueva sin cambiar la imagen, para que todas las instancias lean el valor nuevo.

    gcloud run services update mi-api --region REGION \
      --update-env-vars=ROTADO_EN=$(date +%F)
  5. Comprueba que la revisión nueva está lista y tiene el tráfico.

    gcloud run revisions list --service mi-api --region REGION --limit 3
  6. Deshabilita la versión vieja (aquí, la 2) cuando ya nada la use.

    gcloud secrets versions disable 2 --secret=DATABASE_URL

cómo sé que está resuelto

La revisión nueva sirve el 100 % del tráfico, los logs no muestran errores de autenticación y gcloud secrets versions list DATABASE_URL enseña la versión vieja como disabled.

si no funciona

Si algo falla tras deshabilitarla, vuelve a habilitarla con gcloud secrets versions enable 2 --secret=DATABASE_URL: deshabilitar es reversible, destruir no. Si la revisión nueva no arranca, revisa que la cuenta de servicio tenga roles/secretmanager.secretAccessor sobre ese secreto. Ojo con las revisiones antiguas que fijan una versión concreta: con esa versión deshabilitada no pueden arrancar instancias, y ya no sirven para volver atrás.

en una entrevista«¿Cómo rotas un secreto en Cloud Run sin que el servicio se caiga?»
  1. Versión nueva, no sobrescribir: Secret Manager guarda versiones, así que la vieja sigue ahí para volver atrás.
  2. Sé cuándo se lee: como variable de entorno, al arrancar la instancia; por eso fuerzo una revisión nueva.
  3. Solapamiento: durante el cambio, el destino acepta la credencial vieja y la nueva.
  4. Retiro la vieja al final, deshabilitándola primero y destruyéndola solo cuando estoy seguro.
  5. Alternativa más trazable: fijar el número de versión con --update-secrets; así cada rotación es una revisión y volver atrás recupera también el secreto.

La trampa: añadir la versión nueva y dar la rotación por hecha mientras las instancias vivas siguen con la vieja.

13. Escenario: la app no llega a Cloud SQL

situaciónEl servicio arranca, pero las peticiones fallan con errores de conexión a la base de datos o con timeouts.

qué hay que entender

Hay dos caminos. Por socket, --add-cloudsql-instances monta un socket Unix en /cloudsql/PROJECT_ID:REGION:mi-db, y Cloud Run abre la conexión con la identidad de la cuenta de servicio, que necesita roles/cloudsql.client. Por IP privada, la app se conecta a la IP interna de la instancia, y para llegar a ella el servicio necesita salida a la VPC.

El error orienta: un socket que no existe es que falta la instancia en el servicio; un «not authorized», IAM; y un timeout suele ser red.

pasos, en orden

  1. Lee los errores del servicio para saber en qué capa falla.

    gcloud logging read \
      'resource.labels.service_name="mi-api" AND severity>=ERROR' \
      --limit 30
  2. Comprueba que el servicio tiene la instancia conectada; si no sale nada, falta --add-cloudsql-instances.

    gcloud run services describe mi-api --region REGION --format=yaml | grep cloudsql
  3. Mira el nombre de conexión de la instancia y qué IP tiene: pública, privada o las dos.

    gcloud sql instances describe mi-db --format="yaml(connectionName,ipAddresses)"
  4. Averigua con qué cuenta de servicio corre; si sale vacío, es la de Compute por defecto (PROJECT_NUMBER-compute@developer.gserviceaccount.com).

    SA=$(gcloud run services describe mi-api --region REGION \
      --format="value(spec.template.spec.serviceAccountName)")
  5. Da a esa cuenta permiso para conectarse a Cloud SQL.

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:$SA" --role="roles/cloudsql.client"
  6. Si la instancia solo tiene IP privada, dale al servicio salida a la VPC donde está.

    gcloud run services update mi-api --region REGION \
      --network=default --subnet=default --vpc-egress=private-ranges-only

cómo sé que está resuelto

Los logs dejan de mostrar errores de conexión y curl https://api.mi-dominio.com/health responde, si ese endpoint consulta la base de datos.

si no funciona

Revisa la cadena de conexión: por socket, el host es la ruta del socket (en PostgreSQL, ?host=/cloudsql/PROJECT_ID:REGION:mi-db), no 127.0.0.1. Comprueba que la API de Cloud SQL Admin está activa con gcloud services enable sqladmin.googleapis.com. Si va por IP privada, la VPC del servicio tiene que ser la misma en la que la instancia tiene la IP. Si conecta a veces y otras no, puede que las instancias agoten las conexiones máximas de la base.

en una entrevista«Tu servicio de Cloud Run no consigue conectarse a Cloud SQL. ¿Qué compruebas?»
  1. Leo el error y lo clasifico: socket que no existe, permiso denegado o timeout.
  2. Configuración del servicio: la instancia en --add-cloudsql-instances y la cadena de conexión apuntando al socket.
  3. Identidad: qué cuenta de servicio usa y si tiene roles/cloudsql.client.
  4. Red, si es IP privada: salida a la VPC con Direct VPC egress o un conector, en la misma red que la instancia.
  5. Capacidad: las conexiones máximas de la base frente a instancias por tamaño del pool.

Lo que no haría: abrir la IP pública de la instancia a cualquier origen para que conecte.

14. Relacionado