De desarrollo a producción en tres pasos sencillos con Cloud Run

1. Introducción

¿Por qué es tan difícil administrar las aplicaciones?

Una de las principales razones es que, a menudo, los desarrolladores deben ser administradores de sistemas a tiempo parcial. Ten en cuenta esta lista (parcial) de inquietudes para desarrollar, implementar y administrar una aplicación web moderna apta para la producción :

4d018476b4a73b47.png

No sé tú, pero yo no quiero preocuparme por estas cosas. En realidad, lo que quiero pensar es en la lógica de mi aplicación:

6dfd143d20e5548b.png

En pocas palabras, de eso se trata Cloud Run: te brinda la capacidad de enfocarte en tu app y dejar toda la administración y el mantenimiento a otra persona, es decir, Google, que invirtió millones de horas en perfeccionar sus habilidades en este dominio.

Además de los desafíos administrativos mencionados anteriormente, también debes lidiar con lo siguiente:

  • Dependencias: El entorno en el que se ejecuta tu app debe, en la medida de lo posible, coincidir con precisión con el entorno en el que se probó. Esto puede abarcar varias dimensiones, como el sistema operativo, las bibliotecas de compatibilidad, el intérprete o compilador de lenguaje, la configuración de hardware y muchos otros factores.
  • Distribución: Pasar de una versión local de una app a una que se comparte ampliamente en Internet suele requerir un cambio en el entorno de ejecución, un salto cuántico en la complejidad y una curva de aprendizaje pronunciada.

Cloud Run se encarga de estos y muchos otros problemas por ti. Pero, en lugar de que me creas, creemos una app juntos y veamos lo fácil que es pasar de un entorno de desarrollo local a una app en la nube de nivel de producción en solo unos simples pasos.

Actividades

  • Compilarás una app web simple y verificarás que se ejecute según lo previsto en tu entorno de desarrollo.
  • Luego, pasarás a una versión en contenedores de la misma app. En el camino, explorarás qué significa la contenerización y por qué es tan útil.
  • Por último, implementarás tu app en la nube y verás lo fácil que es administrar tu servicio de Cloud Run con la línea de comandos y la consola de Google Cloud.

Qué aprenderás

  • Cómo crear una app de servidor web simple en Python
  • Cómo empaquetar tu app en un contenedor de Docker que se ejecuta en cualquier lugar
  • Cómo implementar tu app en la nube para que cualquier persona pueda probar tu nueva creación
  • Cómo simplificar aún más los pasos anteriores con paquetes de compilación
  • Cómo usar la herramienta de línea de comandos de Google Cloud y la IU web de Cloud Console

Qué necesitarás

  • Un navegador web
  • Una Cuenta de Google

Este lab está dirigido a desarrolladores de todos los niveles, incluidos principiantes. Aunque usarás Python, no es necesario que sepas programar en ese lenguaje para entender lo que se hace, ya que explicaremos todo el código que uses.

2. Prepárate

5110b5081a1e1c49.png

En esta sección, se explica todo lo que debes hacer para comenzar este lab.

Configuración del entorno de autoaprendizaje

  1. Accede a la consola de Cloud y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

Recuerde el ID de proyecto, un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se mencionará más adelante en este codelab como PROJECT_ID.

  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar los recursos de Google Cloud recursos.

Ejecutar este codelab no debería costar mucho, tal vez nada. Asegúrate de seguir las instrucciones de la sección “Realiza una limpieza”, en la que se aconseja cómo cerrar recursos para que no se te facture más allá de este instructivo. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de USD 300.

Inicia Cloud Shell

En este lab, trabajarás en una sesión de Cloud Shell, que es un intérprete de comandos alojado en una máquina virtual que se ejecuta en la nube de Google. Podrías ejecutar fácilmente esta sección de forma local, en tu computadora, pero Cloud Shell brinda una experiencia reproducible en un entorno coherente para todo el mundo. Después de este lab, puedes volver a probar esta sección en tu computadora.

704a7b7491bd157.png

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shell4292cbf4971c9786.png.

bce75f34b2c53987.png

Si nunca has iniciado Cloud Shell, aparecerá una pantalla intermedia (mitad inferior de la página) en la que se describirá qué es. Si ese es el caso, haz clic en Continuar (y no volverás a verla). Así es como se ve la pantalla única:

70f315d7b402b476.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

fbe3a0674c982259.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo que necesitas. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer simplemente con un navegador o tu Chromebook.

Una vez conectado a Cloud Shell, debería ver que ya se autenticó y que el proyecto ya se configuró con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que está autenticado:
gcloud auth list

Resultado del comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

Configura algunas variables de entorno en tu terminal que te facilitarán los pasos posteriores:

export PROJ=$GOOGLE_CLOUD_PROJECT 
export APP=hello 
export PORT=8080
export REGION="us-central1"
export TAG="gcr.io/$PROJ/$APP"

Habilita las APIs

En pasos posteriores, verás dónde y por qué se necesitan estos servicios. Por ahora, ejecuta este comando para que tu proyecto pueda acceder a los servicios de Cloud Build, Container Registry y Cloud Run:

gcloud services enable cloudbuild.googleapis.com         \
                       containerregistry.googleapis.com  \
                       run.googleapis.com          

Si se realizó correctamente, se mostrará un mensaje similar a este:

Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.

3. Compila una app web sencilla

eef530b56b8e93a3.png

Para comenzar, haz clic en el botón Open Editor en la parte superior del panel de Cloud Shell. El aspecto resultante será el siguiente:

9b81c8a37a6bcdd8.png

Luego, te encontrarás en un entorno de IDE similar a Visual Studio Code, en el que podrás crear proyectos, editar código fuente, ejecutar tus programas, etcétera. Si la pantalla está demasiado abarrotada, puedes expandir o reducir la línea divisoria entre la consola y la ventana de edición o de terminal arrastrando la barra horizontal entre esas dos regiones, que se destaca aquí:

8dea35450851af53.png

Para alternar entre el editor y la terminal, haz clic en los botones Open Editor y Open Terminal, respectivamente. Ahora intenta alternar entre estos dos entornos.

A continuación, selecciona Archivo->Carpeta nueva, ingresa hello y haz clic en OK para crear una carpeta en la que almacenar tu trabajo para este lab. Todos los archivos que crees en este lab y todo el trabajo que realices en Cloud Shell se llevarán a cabo en esta carpeta.

Ahora, crea un archivo requirements.txt. Esto le indica a Python de qué bibliotecas depende tu app. Para esta app web simple, usarás un módulo de Python popular para compilar servidores web llamado Flask y un framework de servidores web llamado gunicorn. En la ventana del editor de Cloud, haz clic en el menú Archivo > Archivo nuevo para crear un archivo nuevo. Cuando se te solicite el nombre del archivo nuevo, ingresa requirements.txt y presiona el botón OK. Asegúrate de que el archivo nuevo termine en la carpeta del proyecto hello.

Ingresa las siguientes líneas en el archivo nuevo para especificar que tu app depende del paquete Flask de Python y del servidor web gunicorn.

Flask
gunicorn

No es necesario que guardes este archivo de forma explícita, ya que el Editor de Cloud guardará los cambios automáticamente.

Versión 1: Hello world!

Con la misma técnica, crea otro archivo nuevo llamado main.py. Este será el archivo fuente principal (y único) de Python de tu app. Nuevamente, asegúrate de que el archivo nuevo termine en la carpeta del proyecto hello.

Inserta el siguiente código en este archivo:

from flask import Flask
import os
import random

app = Flask(__name__)  # Create a Flask object.
PORT = os.environ.get("PORT")  # Get PORT setting from the environment.

# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
@app.route("/", methods=["GET"])
def say_hello():
    html = "<h1>Hello world!</h1>"
    return html


# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=PORT)

Regresa a la terminal y cambia a la carpeta del proyecto con este comando:

cd hello

Ejecuta el siguiente comando para instalar las dependencias del proyecto:

pip3 install -r requirements.txt

Ahora, ejecuta tu app con este comando en la terminal:

python3 main.py

En este punto, tu app se ejecuta en la máquina virtual dedicada a tu sesión de Cloud Shell. Cloud Shell incluye un mecanismo de proxy que te permite acceder a servidores web (como el que acabas de iniciar) que se ejecutan en tu máquina virtual desde cualquier lugar de Internet.

Haz clic en el botón web preview y, luego, en el elemento de menú Preview on Port 8080 de la siguiente manera:

fe45e0192080efd6.png

Se abrirá una pestaña del navegador web en la app en ejecución, que debería verse de la siguiente manera:

b1f06501509aefb9.png

Versión 2: Cómo mostrar la ruta de URL

Vuelve a Cloud Editor (con el botón Open Editor) y agrega compatibilidad para hacer eco de un sufijo de URL opcional. Para ello, actualiza tu archivo main.py de la siguiente manera:

from flask import Flask
import os
import random

app = Flask(__name__)  # Create a Flask object.
PORT = os.environ.get("PORT")  # Get PORT setting from environment.

# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
# If something is specified as the URL path (after the '/'), say_hello()
# responds with "Hello X", where X is the string at the end of the URL.
@app.route("/", methods=["GET"])
@app.route("/<name>", methods=["GET"])     # ← NEW
def say_hello(name="world"):               # ← MODIFIED
    html = f"<h1>Hello {name}!</h1>"       # ← MODIFIED
    return html


# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=PORT)

Vuelve a la terminal (con el botón Open Terminal) y presiona control-C (mantén presionada la tecla Ctrl mientras presionas "C") para detener la app en ejecución y, luego, reiníciala con el siguiente comando:

python3 main.py

Nuevamente, haz clic en el botón web preview y, luego, en el elemento de menú Preview on Port 8080 para abrir una pestaña del navegador web en tu app en ejecución. Deberías ver nuevamente el mensaje "Hello world!", pero ahora reemplaza el texto de la URL que sigue al carácter de barra con cualquier cadena que elijas (p.ej., /your-name) y verifica que veas algo como lo siguiente:

93b87996f88fa370.png

Versión 3: Colores aleatorios

Ahora, agrega compatibilidad con colores de fondo aleatorios. Para ello, vuelve a Cloud Editor (con el botón Open Editor) y actualiza tu archivo main.py de la siguiente manera:

from flask import Flask
import os
import random

app = Flask(__name__)  # Create a Flask object.
PORT = os.environ.get("PORT")  # Get PORT setting from the environment.

# This function decides whether foreground text should be
# displayed in black or white, to maximize fg/bg contrast.
def set_text_color(rgb):                      # ← NEW
    sum = round(                              # ← NEW
        (int(rgb[0]) * 0.299)                 # ← NEW
        + (int(rgb[1]) * 0.587)               # ← NEW
        + (int(rgb[2]) * 0.114)               # ← NEW
    )                                         # ← NEW
    return "black" if sum > 186 else "white"  # ← NEW


# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
# If something is specified as the URL path (after the '/'), say_hello()
# responds with "Hello X", where X is the string at the end of the URL.
# To verify each new invocation of these requests, the HTML document
# includes CSS styling to produce a randomly colored background.
@app.route("/", methods=["GET"])
@app.route("/<name>", methods=["GET"])
def say_hello(name="world"):
    bg = random.sample(range(1, 255), 3)                       # ← NEW
    hex = (int(bg[0]) * 256) + (int(bg[1]) * 16) + int(bg[2])  # ← NEW
    fg_color = set_text_color(bg)                              # ← NEW
    bg_color = f"#{hex:06x}"                                   # ← NEW
    style = f"color:{fg_color}; background-color:{bg_color}"   # ← NEW
    html = f'<h1 style="{style}">Hello {name}!</h1>'           # ← MODIFIED
    return html


# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=PORT)

Vuelve a la terminal (con el botón Open Terminal) y presiona control-C (mantén presionada la tecla Ctrl mientras presionas "C") para detener la app en ejecución y, luego, reiníciala con el siguiente comando:

python3 main.py

Nuevamente, haz clic en el botón web preview y, luego, en el elemento de menú Preview on Port 8080 para abrir una pestaña del navegador web en tu app en ejecución. Deberías ver el texto generado, con cualquier sufijo especificado o la cadena predeterminada "Hello world!", que se muestra delante de un fondo de color aleatorio, como se muestra a continuación:

baf8d028f15ea7f4.png

Vuelve a cargar la página varias veces para ver que el color de fondo aleatorio cambia cada vez que visitas la app.

¡Y con eso, tu app está lista! ¡Felicitaciones! En el siguiente paso, aprenderás a empaquetar tu app en un contenedor y por qué es útil hacerlo.

4. Organiza tu app en contenedores

17cc234ec3325a8a.png

¿Qué es un contenedor?

Los contenedores en general, y Docker en particular, nos brindan la capacidad de crear una caja modular en la que se puede ejecutar una aplicación con todas sus dependencias agrupadas. El resultado se denomina imagen de contenedor. En esta sección, crearás una imagen de contenedor que usarás para encapsular tu aplicación y todas sus dependencias.

Hablando de dependencias, en un paso anterior, cuando ejecutabas tu app en un entorno de desarrollo, debías ejecutar pip3 install -r requirements.txt y asegurarte de que el archivo requirements.txt contuviera todas tus bibliotecas dependientes y las versiones correspondientes. Con los contenedores, instalas esos requisitos cuando generas la imagen del contenedor, por lo que el consumidor del contenedor no necesita preocuparse por instalar nada.

Esta imagen de contenedor formará el bloque de compilación básico para implementar tu aplicación en Cloud Run. Dado que los contenedores se pueden usar en casi cualquier servidor virtual o real, esto nos permite implementar tu aplicación en cualquier lugar que desees y trasladarla de un proveedor de servicios a otro, o bien de un entorno local a la nube.

Los contenedores ayudan a que tus aplicaciones sean las siguientes:

  • Reproducibles: Los contenedores son independientes y completos.
  • Portátiles: Los contenedores son componentes básicos de la industria, lo que permite la portabilidad de las aplicaciones en diferentes proveedores y entornos de la nube.

En resumen, los contenedores ofrecen la capacidad de, finalmente, "escribir una vez y ejecutar en cualquier lugar". Una excepción a esa regla es que el contenedor generado está restringido para ejecutarse en el tipo de procesador en el que lo creaste, pero también hay formas de generar versiones de contenedores para otras configuraciones de hardware.

Basta de charla, ¡creemos un contenedor! Usarás una tecnología específica para crear un contenedor llamado Docker.

En Cloud Editor, crea un archivo nuevo llamado Dockerfile. Este archivo es un plano para construir tu imagen. Le indica a Docker sobre tu entorno operativo y tu código fuente, cómo instalar tus dependencias, compilar tu app y ejecutar tu código.

# Use an official lightweight Python image.
FROM python:3.9-slim

# Copy local code to the container image.
WORKDIR /app
COPY main.py .
COPY requirements.txt .

# Install dependencies into this container so there's no need to 
# install anything at container run time.
RUN pip install -r requirements.txt

# Service must listen to $PORT environment variable.
# This default value facilitates local development.
ENV PORT 8080

# Run the web service on container startup. Here you use the gunicorn
# server, with one worker process and 8 threads. For environments 
# with multiple CPU cores, increase the number of workers to match 
# the number of cores available.
CMD exec gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 main:app

En la terminal de Cloud, ejecuta el siguiente comando para compilar la imagen de contenedor con Cloud Build:

gcloud builds submit --tag $TAG

Una vez que se envíe al registro, verás un mensaje de SUCCESS que contiene el nombre de la imagen, que debería verse así: gcr.io/<project-id>/hello. Ahora la imagen se almacena en Google Container Registry y se puede volver a usar cuando y donde quieras.

Puedes enumerar todas las imágenes de contenedores asociadas a tu proyecto actual con el siguiente comando:

gcloud container images list

Ahora, ejecuta y prueba la aplicación de manera local desde Cloud Shell con los siguientes comandos de docker:

docker run -p $PORT:$PORT -e PORT=$PORT $TAG

La opción -p $PORT:$PORT le indica a Docker que asigne el puerto externo $PORT (establecido en 8080 más arriba) en el entorno del host al mismo número de puerto dentro del contenedor en ejecución. Esto facilita las cosas, ya que el código del servidor que escribes y el número de puerto externo al que te conectas cuando pruebas tu app serán los mismos (8080), pero podrías usar la opción -p para asignar cualquier puerto externo arbitrario en el host a cualquier puerto interno deseado dentro del contenedor.

La opción -e PORT=$PORT le indica a Docker que ponga la variable de entorno $PORT (establecida en 8080 más arriba) a disposición de tu app que se ejecuta dentro del contenedor.

Ahora puedes probar tu app. Para ello, dirige un navegador web al código de Python que se ejecuta dentro del contenedor. En la ventana de Cloud Shell, haz clic en el ícono de "Vista previa en la Web" y selecciona "Vista previa en el puerto 8080", como hiciste en el paso anterior.

El resultado debería ser familiar: deberías ver el texto generado frente a un fondo de color aleatorio, tal como lo hiciste cuando ejecutaste la app directamente en la terminal de Cloud Shell. Vuelve a cargar la página varias veces para ver que el color de fondo aleatorio cambia cada vez que visitas la app.

¡Felicitaciones! Ahora ejecutaste una versión en contenedor de tu app. En la siguiente sección, sin tocar una sola línea de código, convertirás tu imagen de contenedor en una app web de calidad para producción.

5. A la nube…

1b0665d94750ded6.gif

Ahora que ya creaste un contenedor para tu app, querrás compartir esta maravilla con el resto del mundo, por lo que es momento de implementarla en la nube. Pero te gustaría hacer algo más que compartirlo. Te gustaría asegurarte de que cumpla con los siguientes requisitos:

  • Se ejecuta de forma confiable: Obtienes tolerancia a fallas automática en caso de que falle una computadora que ejecuta tu app.
  • Se ajusta automáticamente: Tu app se mantendrá al día con grandes niveles de tráfico y reducirá automáticamente su huella cuando no se use.
  • Minimiza tus costos, ya que no se te cobra por los recursos que no usas. Solo se te cobra por los recursos consumidos mientras respondes al tráfico.
  • Se puede acceder a él a través de un nombre de dominio personalizado: Tienes acceso a una solución con un solo clic para asignar un nombre de dominio personalizado a tu servicio.
  • Ofrece un excelente tiempo de respuesta: los inicios en frío son razonablemente rápidos, pero puedes ajustar eso especificando una configuración de instancia mínima.
  • Admite la encriptación de extremo a extremo con la seguridad web estándar de SSL/TLS: Cuando implementas un servicio, obtienes la encriptación web estándar y los certificados requeridos correspondientes de forma gratuita y automática.

Si implementas tu app en Google Cloud Run, obtendrás todo lo anterior y mucho más.

Implementa tu app en Cloud Run

Primero, modifiquemos tu app para que puedas distinguir la revisión nueva de la anterior. Para ello, modifica el archivo main.py de modo que el mensaje predeterminado cambie de "Hello world!" a "Hello from Cloud Run!". En otras palabras, cambia esta línea en main.py de la siguiente manera:

def say_hello(name="world"):

a esto:

def say_hello(name="from Cloud Run"):

Cloud Run es regional, lo que significa que la infraestructura que ejecuta tus servicios se ubica en una región específica y Google la administra para que esté disponible de manera redundante en todas las zonas de esa región. En la sección "Preparación" anterior, definiste una región predeterminada a través de la variable de entorno REGION.

Vuelve a compilar tu imagen de contenedor y, luego, implementa tu aplicación alojada en contenedores en Cloud Run con el siguiente comando:

gcloud builds submit --tag $TAG
gcloud run deploy "$APP"   \
  --image "$TAG"           \
  --platform "managed"     \
  --region "$REGION"       \
  --allow-unauthenticated
  • También puedes definir una región predeterminada con gcloud config set run/region $REGION.
  • La opción --allow-unauthenticated hace que el servicio esté disponible de forma pública. Para evitar solicitudes no autenticadas, usa --no-allow-unauthenticated en su lugar.

La imagen especificada aquí es la imagen de Docker que compilaste en el último paso. Gracias al servicio de Cloud Build, que almacenó la imagen resultante en Google Container Registry, el servicio de Cloud Run puede encontrarla y, luego, implementarla por ti.

Espera un momento a que finalice la implementación. Si la operación es exitosa, la línea de comandos mostrará la URL de servicio:

Deploying container to Cloud Run service [hello] in project [PROJECT_ID...
✓ Deploying new service... Done.                                   
  ✓ Creating Revision... Revision deployment finished. Waiting for health check...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [hello] revision [hello-...] has been deployed and is serving 100 percent of traffic.
Service URL: https://hello-....a.run.app

También puedes recuperar la URL de tu servicio con este comando:

gcloud run services describe hello  \
  --platform managed                \
  --region $REGION                  \
  --format "value(status.url)"

Debería aparecer algo similar a lo siguiente:

https://hello-....a.run.app

Esta URL es exclusiva y cuenta con seguridad de TLS para tu servicio de Cloud Run. Este vínculo es permanente (siempre y cuando no inhabilite su servicio) y se puede usar en cualquier lugar de Internet. No usa el mecanismo de proxy de Cloud Shell que se mencionó antes, el cual dependía de una máquina virtual transitoria.

Haz clic en el Service URL destacado para abrir una pestaña del navegador web en tu app en ejecución. El resultado debería mostrar el mensaje "Hello from Cloud Run!" frente a un fondo de color aleatorio.

¡Felicitaciones! Tu app ahora se ejecuta en la nube de Google. Sin tener que pensarlo, tu app está disponible públicamente, con encriptación TLS (HTTPS) y escalamiento automático a niveles de tráfico asombrosos.

Pero creo que este proceso podría ser aún más fácil…

6. Crea el contenedor automáticamente

Todo esto es genial, pero ¿qué sucede si no quiero pensar en Dockerfiles ni contenedores? ¿Qué sucede si, como la mayoría de los desarrolladores, solo quiero enfocarme en escribir el código de mi aplicación y dejar que alguien más se preocupe por contenerizarla? Bueno, estás de suerte porque Cloud Run admite un estándar de código abierto llamado Buildpacks, que existe por este mismo motivo: automatizar el proceso de fabricación de un contenedor a partir de una colección de archivos fuente.

Ten en cuenta que, en algunos casos, es posible que un desarrollador prefiera usar un Dockerfile explícito, por ejemplo, si desea un alto grado de personalización en la forma en que se compila su contenedor. Sin embargo, para casos comunes como este ejercicio, los buildpacks funcionan bien y evitan la necesidad de crear un Dockerfile de forma manual. Modifiquemos tu código para usar paquetes de compilación.

Primero, modifiquemos tu app para que puedas distinguir la revisión nueva de la anterior. Para ello, modifica el archivo main.py de modo que el mensaje predeterminado cambie de "Hello from Cloud Run!" a "Hello from Cloud Run with Buildpacks!". En otras palabras, cambia esta línea en main.py de la siguiente manera:

def say_hello(name="from Cloud Run"):

a esto:

def say_hello(name="from Cloud Run with Buildpacks"):

Ahora aprovechemos los buildpacks creando un archivo nuevo llamado Procfile. Crea ese archivo en Cloud Editor y, luego, inserta esta línea de texto:

web: python3 main.py

Esto le indica al sistema de compilación cómo ejecutar tu app en el contenedor generado automáticamente. Con esa pequeña instrucción, ya no necesitas un Dockerfile. Para verificarlo, borra tu Dockerfile y ejecuta el siguiente comando en la terminal de Cloud Shell:

gcloud beta run deploy "$APP"  \
    --source .                 \
    --platform "managed"       \
    --region "$REGION"         \
    --allow-unauthenticated

Este comando es similar al que ejecutaste para implementar tu app en el último paso, pero, esta vez, reemplazaste la opción --image por la opción --source .. Esto le indica al comando gcloud que deseas que use paquetes de compilación para crear tu imagen de contenedor, según los archivos fuente que encuentre en el directorio actual (dot en --source . es una abreviatura del directorio actual). Dado que el servicio se encarga de la imagen del contenedor de forma implícita, no es necesario que especifiques una imagen en este comando gcloud.

Una vez más, verifica que esta implementación haya funcionado. Para ello, haz clic en el Service URL destacado para abrir una pestaña del navegador web en tu app en ejecución y asegúrate de que tu servicio muestre el mensaje "Hello from Cloud Run with Buildpacks!" frente a un fondo de color aleatorio.

Ten en cuenta que, al usar buildpacks para fabricar tu Dockerfile, básicamente redujiste los tres sencillos pasos a dos:

  1. Crea una app en tu entorno de desarrollo.
  2. Implementa el mismo código en la nube con un solo comando.

7. ¿Debo usar la línea de comandos?

¡No! Al igual que con casi todos los servicios de Google Cloud, existen tres formas de interactuar con Cloud Run:

  • La herramienta de línea de comandos de gcloud, que acabas de ver.
  • Una interfaz de usuario web enriquecida, a través de la consola de Cloud, que admite un estilo de interacción intuitivo de apuntar y hacer clic.
  • De forma programática, con las bibliotecas cliente de Google disponibles para muchos lenguajes populares, incluidos Java, C#, Python, Go, JavaScript, Ruby, C/C++ y otros

Implementemos una instancia adicional de tu app de Cloud Run con la IU de la consola. Navega a la página de destino del servicio de Cloud Run a través del menú de la esquina superior izquierda:

e2b4983b38c81796.png

Luego, deberías ver un resumen de tus servicios de Cloud Run, como el siguiente:

b335e7bf0a3af845.png

Haz clic en el vínculo "Crear servicio" para iniciar el proceso de implementación:

51f61a8ddc7a4c0b.png

Ingresa "hello-again" como el nombre del servicio, acepta la plataforma de implementación y la región predeterminadas, y haz clic en "Siguiente".

8a17baa45336c4c9.png

Ingresa esta URL para la imagen del contenedor: gcr.io/cloudrun/hello, que es un contenedor creado por Google para fines de prueba, y haz clic en el menú desplegable "Configuración avanzada" para ver algunos de los muchos parámetros de configuración disponibles. Estos son solo algunos de los elementos que puedes personalizar:

  • Número de puerto y punto de entrada del contenedor (que anulará el punto de entrada especificado cuando se compile el contenedor)
  • Hardware: memoria y cantidad de CPU
  • scaling: min and max instances
  • variables de entorno
  • Otros: Configuración de tiempo de espera de la solicitud, cantidad máxima de solicitudes por contenedor, HTTP/2

Haz clic en el botón “Siguiente” para avanzar en el diálogo. En el siguiente diálogo, puedes especificar cómo se activa tu servicio. En "Ingress", selecciona "Permitir todo el tráfico" y, en "Autenticación", selecciona "Permitir tráfico no autenticado".

e78281d1cff3418.png

Estos son los parámetros de configuración más flexibles, ya que permiten que cualquier persona acceda a tu app de Cloud Run desde cualquier lugar de Internet público sin especificar credenciales de autenticación. Es posible que desees usar parámetros de configuración más restrictivos para tu app, pero, para este ejercicio de aprendizaje, mantendremos la configuración simple.

Ahora haz clic en el botón Create para crear tu servicio de Cloud Run. Después de unos segundos, deberías ver tu nuevo servicio en la lista de resumen de los servicios de Cloud Run. La línea de resumen proporciona la implementación más reciente (fecha y hora, y quién la realizó) junto con algunos parámetros de configuración clave. Haz clic en el vínculo del nombre del servicio para obtener más detalles sobre tu servicio nuevo.

Para verificar tu servicio, haz clic en la URL que se muestra cerca de la parte superior de la página de resumen, como se destaca en el siguiente ejemplo:

6c35cf0636dddc51.png

Deberías ver algo como esto:

3ba6ab4fe0da1f84.png

Ahora que implementaste un nuevo servicio de Cloud Run, selecciona la pestaña REVISIONS para ver algunas formas de administrar varias implementaciones.

2351ee7ec4a356f0.png

Para implementar revisiones nuevas directamente desde la consola, puedes hacer clic en el botón EDIT & DEPLOY NEW REVISION, como se destaca en la siguiente captura de pantalla de ejemplo:

a599fa88d00d6776.png

Haz clic en ese botón ahora para crear una revisión nueva. Cerca de la URL del contenedor, haz clic en el botón SELECT, como se muestra a continuación:

5fd1b1f8e1f11d40.png

En el cuadro de diálogo que aparece, busca la app web simple que implementaste desde Cloud Build con Buildpacks anteriormente y, luego, haz clic en Seleccionar. Asegúrate de elegir la imagen de contenedor en

gcr.io/<project>/cloud-run-source-deploy

folder , de la siguiente manera:

8a756c6157face3a.png

Una vez que lo hayas seleccionado, desplázate hasta la parte inferior y haz clic en el botón DEPLOY. Ahora implementaste una nueva revisión de tu app. Para verificarlo, vuelve a visitar la URL de tu servicio y comprueba que ahora ves tu app web colorida "Hello from Cloud Run with Buildpacks!".

Como puedes ver, la pestaña de revisiones proporciona un resumen de cada revisión que implementaste, y ahora deberías ver dos revisiones para este servicio. Para seleccionar una revisión determinada, haz clic en el botón de selección que se encuentra a la izquierda del nombre de la revisión. De esta manera, se mostrará un resumen de los detalles de la revisión en el lado derecho de la pantalla. Si seleccionas esos botones, verás que tus dos revisiones se derivan de dos imágenes de contenedor diferentes.

El botón MANAGE TRAFFIC te permite modificar la distribución de las solicitudes entrantes que se envían a una revisión determinada. Esta capacidad de ajustar la cantidad de tráfico que se envía a una revisión determinada habilita varios casos de uso valiosos:

  • Pruebas de versión canary de una nueva versión de tu app con una pequeña parte del tráfico entrante
  • Revertir el tráfico de una versión problemática a una revisión anterior
  • Pruebas A/B

Aquí puedes encontrar el botón MANAGE TRAFFIC:

519d3c22ae028287.png

Configura una división del tráfico 50/50 entre tus dos revisiones especificando una división del tráfico 50/50 de la siguiente manera:

8c37d4f115d9ded4.png

Ahora haz clic en el botón SAVE y verifica la división 50/50. Para ello, visita la URL de tu servicio varias veces y comprueba que, en promedio, la mitad de tus solicitudes se publiquen con la revisión actual ("Hello from Cloud Run with Buildpacks!") y la otra mitad, con la revisión anterior ("It's running!").

Otras pestañas de la página Detalles del servicio ofrecen la posibilidad de supervisar el rendimiento, el tráfico y los registros, lo que proporciona estadísticas valiosas sobre qué tan bien y qué tan arduamente funciona tu servicio. También puedes ajustar el acceso a tu servicio en la pestaña "Permisos". Dedica unos minutos a explorar las pestañas de esta página para conocer las capacidades disponibles.

Interfaz programática

Como se mencionó anteriormente, también tienes la opción de crear, implementar y administrar tus servicios de Cloud Run de forma programática. Para las tareas manuales, esta opción es más avanzada que la línea de comandos o la consola web, pero es la mejor opción para automatizar los servicios de Cloud Run. Tienes la opción de usar las bibliotecas cliente de Google en varios lenguajes de programación populares.

8. Cómo probar tu app

198ada162d1f0bf1.png

En este último paso, ejecutarás una prueba de carga artificial para someter a tu app a una prueba de esfuerzo y observar cómo se escala con la demanda entrante. Usarás una herramienta llamada hey, que está preinstalada en Cloud Shell y nos permite ejecutar pruebas de carga y presentar los resultados

Ejecuta la prueba

En la terminal de Cloud Shell, ejecuta este comando para realizar una prueba de carga:

hey -q 1000 -c 200 -z 30s https://hello-...run.app

Los argumentos del comando se interpretan de la siguiente manera:

  • -q 1000: Intenta generar la carga a aproximadamente 1,000 solicitudes por segundo.
  • -c 200: Asigna 200 trabajadores paralelos.
  • -z 30s: Ejecuta la prueba de carga durante 30 segundos.
  • asegúrate de usar la URL de tu servicio como el último argumento en esta línea de comandos

Los resultados de la prueba deberían verse de la siguiente manera:

 Summary:
 Total:        30.2767 secs
 Slowest:      3.3633 secs
 Fastest:      0.1071 secs
 Average:      0.1828 secs
 Requests/sec: 1087.2387
 Total data:   3028456 bytes
 Size/request: 92 bytes

Response time histogram:
 0.107 [1]     |
 0.433 [31346] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
 0.758 [1472]  |■■
 1.084 [82]    |
 1.410 [4]     |
...

Latency distribution:
...
 50% in 0.1528 secs
 75% in 0.1949 secs
 90% in 0.2442 secs
 95% in 0.4052 secs
 99% in 0.7062 secs

Details (average, fastest, slowest):
...
 req write:    0.0000 secs, 0.0000 secs, 0.0232 secs
 resp wait:    0.1824 secs, 0.1070 secs, 3.2953 secs
 resp read:    0.0000 secs, 0.0000 secs, 0.0010 secs
Status code distribution:
 [200] 32918 responses

En este resumen, se indican varios elementos de interés:

  • Se enviaron 32,918 solicitudes a aproximadamente 1,000 por segundo durante 30 s.
  • No hubo errores (solo respuestas HTTP 200).
  • La latencia promedio fue de 180 ms.
  • La latencia mínima fue de 107 ms y la máxima, de 3.3 s.
  • La latencia del percentil 90 fue de 244 ms.

Si consultas la pestaña METRICS en la consola de Cloud Run, puedes ver el lado del servidor de la historia del rendimiento:

e635c6831c468dd3.png

9. Limpieza

Si bien Cloud Run no cobra cuando el servicio no se usa, es posible que se te cobre por el almacenamiento de la imagen del contenedor compilada.

Para evitar esto, puedes borrar el proyecto de GCP, lo que detendrá la facturación de todos los recursos usados en ese proyecto, o puedes borrar la imagen del contenedor con el siguiente comando:

gcloud container images delete $TAG

Para borrar tus servicios de Cloud Run, usa los siguientes comandos:

gcloud run services delete hello --platform managed --region $REGION --quiet
gcloud run services delete hello-again --platform managed --region $REGION --quiet

10. ¡Lo lograste!

9a31f4fdbbf1ddcb.png

Felicitaciones. Creaste e implementaste correctamente una app de Cloud Run de producción. Durante el proceso, aprendiste sobre los contenedores y cómo crear tu propio contenedor. Viste lo fácil que es implementar tu app con Cloud Run, tanto con la herramienta de línea de comandos de gcloud como con Cloud Console. Ahora sabes cómo compartir tus brillantes creaciones con todo el mundo.

Quiero dejarte una pregunta importante:

Una vez que tu app funcionó en tu entorno de desarrollo, ¿cuántas líneas de código tuviste que modificar para implementarla en la nube, con todos los atributos de nivel de producción que ofrece Cloud Run?

La respuesta, por supuesto, es cero. :)

Codelabs que puedes consultar…

Otras funciones interesantes que puedes explorar…

Documentos de referencia

11. Llamado a la acción

Logotipo de Google Cloud

Si disfrutaste este codelab y es probable que dediques más tiempo a la práctica con Google Cloud, te recomendamos que te unas a Google Cloud Innovators hoy mismo.

Logotipo de la insignia de miembro general de Innovators

Google Cloud Innovators es gratuito y ofrece lo siguiente:

  • Debates, sesiones de preguntas y sesiones de planificación en vivo para conocer las novedades más recientes directamente con los Googlers
  • Las últimas noticias de Google Cloud directamente en tu bandeja de entrada
  • Insignia digital y fondo de videoconferencia
  • 500 créditos de labs y aprendizaje en Skills Boost

Haz clic aquí para registrarte.