← Volver al blog

Una app interna en Cloud Run: lo que configuramos para que salga barata y no se caiga

  • Google Cloud
Una app interna en Cloud Run: lo que configuramos para que salga barata y no se caiga

Imagina una empresa de logística de 14 personas con una sola app interna: los repartidores marcan las entregas desde el celular y la oficina ve la lista llenarse. Se construyó en una semana, corre en un contenedor y alguien la desplegó en Cloud Run porque era el camino más corto entre "funciona en mi máquina" y "funciona en un estacionamiento". Ocho meses después pasaron dos cosas. La factura no es la que nadie esperaba, y nadie tiene claro quién puede abrir la URL.

Ninguna de las dos es mala suerte. Cloud Run es un buen lugar para una app así, y sus valores por defecto tienen sentido para un sitio público con tráfico real. Una app interna que usan catorce personas tiene otra forma, y son unos cinco ajustes los que deciden si cuesta unos dólares al mes o unos cientos. Este es el orden en que los revisamos en el servicio de un cliente. Cada cifra de abajo sale de la documentación de Google, consultada el 5 de octubre de 2026.

Qué te cobra realmente un servicio de Cloud Run

Cloud Run tiene dos modos de facturación, y la diferencia entre ellos es el número más grande de la factura.

El modo por defecto es la facturación basada en solicitudes. Se te cobra por las instancias mientras procesan una solicitud, más el tiempo que tardan en arrancar y en apagarse. Una instancia que está inactiva y no es una instancia mínima no genera cobro, y la documentación de Google indica que una instancia nunca se queda inactiva más de 15 minutos después de procesar una solicitud, salvo que las instancias mínimas la mantengan viva. Para una app que trabaja de 7am a 6pm y está callada el resto del día, eso es casi ideal.

El otro modo es la facturación basada en instancias, antes llamada "CPU siempre asignada". Cobra todo el ciclo de vida de cada instancia, desde que arranca hasta que termina, con un mínimo de un minuto, llegue o no una solicitud. Ese costo se justifica cuando tu contenedor trabaja entre solicitudes: una cola en segundo plano, un programador que corre dentro del proceso, un caché que se calienta solo. Un formulario que guarda un registro no lo necesita.

Las tarifas publicadas para la facturación basada en solicitudes son USD 0.000024 por vCPU-segundo y USD 0.0000025 por GiB-segundo de tiempo activo, más USD 0.40 por millón de solicitudes, precio de lista consultado el 5 de octubre de 2026. Las tarifas cambian según la región, así que lee la fila de la región donde de verdad vas a desplegar. También hay una capa gratuita mensual: los primeros 180,000 vCPU-segundos, 360,000 GiB-segundos y 2 millones de solicitudes. Una app interna de catorce personas que baja a cero de noche muchas veces cabe dentro de esa capa gratuita, y su línea en la factura es un redondeo.

Los dos ajustes que crean una factura sin avisar

Cuando la factura de Cloud Run de una pyme sorprende, casi siempre es por uno de estos dos.

El primero son las instancias mínimas. Ponerlas en más de cero mantiene instancias tibias para que la primera solicitud de la mañana no sea lenta. Es un problema real que vale la pena resolver, y no es gratis: con facturación basada en solicitudes, las instancias mínimas se cobran a una tarifa de inactividad reducida de CPU y memoria mientras esperan, y esa tarifa corre las 24 horas del día, incluidas las dieciséis en que nadie usa la app. Una instancia tibia es una decisión defendible. Una instancia tibia con la facturación basada en instancias también encendida es un pequeño servidor que estás rentando todo el día sin querer.

El segundo es la facturación basada en instancias que quedó encendida por costumbre, normalmente porque alguien tuvo una tarea en segundo plano y nadie la volvió a apagar. Revisa en qué modo está tu servicio antes de ajustar cualquier otra cosa, porque todos los demás números de esta página se leen distinto en cada uno.

Si de verdad quieres instancias tibias, la versión honesta es una, en la región donde está tu gente, con facturación basada en solicitudes, y solo después de medir qué tan lento es realmente un arranque en frío de tu contenedor. Un contenedor que arranca en 400ms no necesita que lo mantengan despierto.

Los tres ajustes de solicitud que nadie vuelve a ver

La concurrencia es cuántas solicitudes atiende una instancia al mismo tiempo. Un servicio desplegado desde la consola de Google Cloud tiene 80 por defecto. Desplegado con la CLI de gcloud o con Terraform, el valor por defecto es 80 por la cantidad de vCPU, y baja a 1 si pediste menos de una vCPU. El techo es 1,000. Para una app interna el valor por defecto casi siempre está bien, y la trampa es la CPU fraccionada: pide media vCPU para ahorrar y te queda un servicio que atiende una solicitud por instancia, así que catorce personas haciendo clic al mismo tiempo levantan catorce instancias.

El máximo de instancias viene en 100 por revisión. Ese valor por defecto existe para un sitio web que podría recibir un enlace desde algún lugar popular. Para una app con catorce usuarios conocidos, 100 no es un límite de seguridad, es un cheque en blanco contra tus propios errores: un bucle de reintentos en el cliente del celular, o un rastreador que encontró un endpoint que olvidaste cerrar, pueden escalarte a cien instancias, y lo único que se da cuenta es la factura. Nosotros ponemos un tope que refleja la cantidad real de usuarios, casi siempre de un dígito, y tratamos el llegar a ese tope como una alerta y no como algo que hay que subir.

El timeout de solicitud viene en 300 segundos y se puede subir hasta 3,600. Cinco minutos es mucho tiempo para mantener una conexión abierta en una app cuya página más lenta es un reporte. Bajarlo significa que una solicitud atorada falla rápido en vez de cobrar CPU mientras cuelga. La documentación de Google advierte que por encima de 15 minutos conviene implementar reintentos y esperar que los clientes se reconecten, buena señal de que los timeouts largos pertenecen a otro tipo de carga.

Quién puede llamar a la URL, y dónde vive la contraseña

Un servicio de Cloud Run es alcanzable por HTTPS para cualquier identidad que tenga sobre él el rol de Cloud Run Invoker (roles/run.invoker). Darle ese rol al principal especial allUsers es lo que vuelve público un servicio. En una app interna, ese permiso no debería existir. Dale el rol a la gente que lo necesita:

gcloud run services add-iam-policy-binding internal-app \
  --region=REGION \
  --member=group:operaciones@tuempresa.com \
  --role=roles/run.invoker

Despliega con --no-allow-unauthenticated y el servicio rechaza las solicitudes sin autenticar con un HTTP 403, así una URL filtrada deja de ser un incidente. Algo que conviene saber antes de ordenar esto: volver a activar la verificación de IAM del rol Invoker desde la consola elimina por ti cualquier permiso existente de allUsers, lo cual es cómodo y también significa que todo lo que estaba llamando al servicio de forma anónima sin que lo supieras va a dejar de funcionar en ese minuto. Primero encuentra a esos llamadores.

Los secretos son la otra mitad del mismo trabajo. Cloud Run lee los secretos de Secret Manager como variable de entorno o como archivo montado dentro del contenedor, en ambos casos con --set-secrets, donde una clave que empieza con diagonal es una ruta de montaje y cualquier otra cosa es una variable de entorno:

gcloud run deploy internal-app \
  --region=REGION \
  --set-secrets=/secrets/db/password=db-password:latest \
  --no-allow-unauthenticated

Las dos formas fallan distinto, y vale la pena elegir esa diferencia a propósito. Un secreto como variable de entorno se obtiene antes de que arranque la instancia, así que si el secreto no está accesible la instancia no arranca y te enteras al momento de desplegar. Un secreto montado no se verifica al arrancar; la lectura falla después, en tiempo de ejecución, dentro de cualquier parte del código que lo necesite. Nosotros montamos los secretos que rotan y usamos variables de entorno para los que la app no puede dejar de tener.

Logs: los 30 días por defecto y qué pasa después

Todo lo que el contenedor escribe en la salida estándar llega a Cloud Logging, al bucket _Default, que guarda los logs 30 días. Puedes dejarlo en cualquier valor entre 1 día y 3,650 días. Dos datos simplifican la decisión. La retención más allá de los 30 días por defecto se cobra a USD 0.01 por GiB al mes, precio de lista consultado el 5 de octubre de 2026. Y acortar la retención a menos de 30 días no ahorra nada, porque los primeros 30 días van incluidos con la ingesta.

Entonces el único cambio de retención que mueve dinero es uno largo, y una app interna parlanchina con el log de depuración encendido es justo el servicio que más caro lo vuelve. Baja el nivel de log antes de subir la retención.

Cloud Run o una VM pequeña

La comparación que la gente espera que sea sobre precio es casi toda sobre quién parcha el sistema operativo. Una VM pequeña corriendo el mismo contenedor tiene un costo mensual predecible y una lista interminable de obligaciones chicas: el sistema operativo llega al fin de su vida útil, el disco se llena de logs, un certificado vence, alguien tiene que ser la persona que entra a arreglarlo. Cloud Run te quita esa lista y a cambio te pide que te ocupes de los cinco ajustes de arriba.

Para una app interna con tráfico a ratos y en horario de oficina, que puede bajar a cero de noche, Cloud Run suele ganar tanto en costo como en atención. Para algo que tiene que guardar estado en disco local, correr un proceso largo que no tiene forma de solicitud, o quedar detrás de una IP fija para la lista de permitidos de un proveedor, una VM o un servicio administrado es la respuesta más limpia, y lo decimos.

Qué vigilamos el primer mes

  1. Un presupuesto de facturación con alertas en el proyecto, puesto antes del primer despliegue y no después del primer susto.
  2. La cantidad de instancias en el tiempo. Un servicio que nunca vuelve a cero de noche te está diciendo que algo lo está consultando.
  3. Solicitudes que nadie pidió: accesos anónimos, chequeos de salud de origen desconocido, un cliente reintentando en bucle.
  4. El tiempo de arranque en frío, medido y no supuesto, para que la decisión sobre instancias mínimas descanse en un número.
  5. La tasa de errores contra el nuevo timeout más bajo, todos los días de la primera semana después de cambiarlo.

Cómo ayuda Guanacos Tech

Esto lo hacemos como un trabajo de alcance fijo: leer el servicio tal como está hoy, dejar el modo de facturación, la concurrencia, el tope de instancias y el timeout acordes a la cantidad real de usuarios, mover los secretos a Secret Manager, cerrar el permiso de invoker, poner presupuesto y alertas en el proyecto, y dejar una nota de una página que explique qué es cada ajuste y por qué quedó donde quedó. Somos una consultoría independiente y nuestros ingenieros tienen certificaciones de Google, así que recibes el razonamiento junto con los ajustes y no un servicio cambiado y un encogimiento de hombros.

Si tienes una app interna en Cloud Run que nadie ha abierto desde el día que salió, ese es el punto de partida normal y no uno vergonzoso. Mira qué hacemos en consultoría de Google Cloud. Una llamada de 30 minutos alcanza para decirte cuál de estos ajustes te está costando dinero.

Fuentes

Siguiente paso

¿Prefieres que lo hagamos nosotros?

Treinta minutos por Google Meet, sin costo. Miramos tu dominio o tu proyecto contigo, te decimos qué está mal y qué haríamos primero. Si lo puedes resolver solo, te lo decimos.

Reservar una llamada de 30 minutos o lee sobre nuestro consultoría de Google Cloud

Preguntas frecuentes

¿Cloud Run cuesta algo mientras nadie usa la app?

Con la facturación basada en solicitudes, que es la de por defecto, las instancias inactivas que no son instancias mínimas no generan cobro, y una instancia no se queda inactiva más de 15 minutos después de una solicitud salvo que las instancias mínimas la mantengan viva. Si pones instancias mínimas en más de cero, esas instancias se cobran a una tarifa de inactividad reducida las 24 horas, incluida la noche.

¿Cómo dejo de tener público un servicio de Cloud Run?

El acceso público viene de darle el rol de Cloud Run Invoker al principal allUsers. Quita ese permiso, dale roles/run.invoker a los usuarios o grupos que de verdad lo necesitan y despliega con la bandera no-allow-unauthenticated para que las solicitudes sin autenticar se rechacen con un HTTP 403. Antes de cerrarlo averigua qué está llamando al servicio de forma anónima, porque esos llamadores van a dejar de funcionar de inmediato.

¿En cuánto debería quedar el máximo de instancias de una app interna chica?

El valor por defecto es 100 instancias por revisión, mucho más de lo que necesita un equipo de diez o veinte personas. Un tope de un dígito acorde a la cantidad real de usuarios convierte un bucle de reintentos descontrolado en un error visible en vez de una factura grande, y siempre puedes subirlo a propósito si el tráfico real lo pide.