1. Descripción general
En este lab, se demuestran las funciones y capacidades diseñadas para optimizar el flujo de trabajo de desarrollo de los ingenieros de software encargados de desarrollar aplicaciones de Python en un entorno alojado en contenedores. El desarrollo de contenedores típico requiere que el usuario comprenda los detalles de los contenedores y el proceso de compilación de contenedores. Además, los desarrolladores suelen tener que interrumpir su flujo de trabajo y salir del IDE para probar y depurar sus aplicaciones en entornos remotos. Con las herramientas y tecnologías que se mencionan en este instructivo, los desarrolladores pueden trabajar de manera eficaz con aplicaciones en contenedores sin salir de su IDE.
Qué aprenderás
En este lab, aprenderás métodos para desarrollar con contenedores en GCP, incluidos los siguientes:
- Cómo crear una nueva aplicación inicial de Python
- Explicación del proceso de desarrollo
- Desarrolla un servicio REST de CRUD simple
- Implementar en GKE
- Cómo depurar un estado de error
- Utilización de registros y puntos de interrupción
- Implementación en caliente de los cambios en GKE

2. Configuración y requisitos
Cómo configurar el entorno a tu propio ritmo
- Accede a Google Cloud Console 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.



- El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla en cualquier momento.
- El ID del proyecto es único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID del proyecto (suele identificarse como
PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se usará el mismo durante todo el proyecto. - Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
- A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no debería costar mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar todo el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de USD 300.
Inicia el editor de Cloud Shell
Este lab se diseñó y probó para usarse con el Editor de Google Cloud Shell. Para acceder al editor, haz lo siguiente:
- Accede a tu proyecto de Google en https://console.cloud.google.com.
- En la esquina superior derecha, haz clic en el ícono del editor de Cloud Shell.

- Se abrirá un panel nuevo en la parte inferior de la ventana.
- Haz clic en el botón Abrir editor.

- El editor se abrirá con un explorador a la derecha y un editor en el área central.
- También debería haber un panel de terminal disponible en la parte inferior de la pantalla.
- Si la terminal NO está abierta, usa la combinación de teclas "Ctrl + `" para abrir una ventana de terminal nueva.
Configuración del entorno
En Cloud Shell, configura el ID y el número de tu proyecto. Guárdalos como variables PROJECT_ID y PROJECT_ID.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')
Aprovisiona la infraestructura que se usa en este lab
En este lab, implementarás código en GKE y accederás a los datos almacenados en una base de datos de Spanner. También usarás Cloud Workstations como IDE. La siguiente secuencia de comandos de configuración prepara esta infraestructura por ti.
- Descarga la secuencia de comandos de configuración y haz que sea ejecutable.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/python/setup_with_cw.sh
chmod +x setup_with_cw.sh
- Abre el archivo
setup_with_cw.shy edita los valores de las contraseñas que actualmente están configuradas como CHANGEME. - Ejecuta la secuencia de comandos de configuración para crear un clúster de GKE y una base de datos de Spanner que usarás en este lab.
./setup_with_cw.sh &
Clúster de Cloud Workstations
- Abre Cloud Workstations en Cloud Console. Espera a que el clúster tenga el estado
READY.
Crea la configuración de las estaciones de trabajo
- Si se desconectó tu sesión de Cloud Shell, haz clic en "Reconnect" y, luego, ejecuta el comando de la CLI de gcloud para establecer el ID del proyecto. Antes de ejecutar el comando, reemplaza el ID del proyecto de ejemplo que se muestra a continuación por el ID de tu proyecto de Qwiklabs.
gcloud config set project qwiklabs-gcp-project-id
- Descarga y ejecuta la siguiente secuencia de comandos en la terminal para crear la configuración de Cloud Workstations.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/python/workstation_config_setup.sh
chmod +x workstation_config_setup.sh
./workstation_config_setup.sh
- Verifica los resultados en la sección Configurations. La transición al estado READY tardará 2 minutos.

- Abre Cloud Workstations en la consola y crea una instancia nueva.

- Cambia el nombre a
my-workstationy selecciona la configuración existente:codeoss-python.

- Verifica los resultados en la sección Workstations.
Iniciar estación de trabajo
- Inicia la estación de trabajo. La estación de trabajo tardará unos minutos en iniciarse.

- Para permitir las cookies de terceros, haz clic en el ícono de la barra de direcciones.


- Haz clic en “¿No funciona el sitio?”.

- Haz clic en "Permitir cookies".

- Una vez que se inicie la estación de trabajo, aparecerá el IDE de Code OSS. Haz clic en "Marcar como completado" en la página de introducción del IDE de la estación de trabajo.

3. Crea una nueva aplicación inicial de Python
En esta sección, crearás una nueva aplicación de Python.
- Abre una terminal nueva.

- Crea un directorio nuevo y ábrelo como espacio de trabajo
mkdir music-service && cd music-service
code-oss-cloud-workstations -r --folder-uri="$PWD"
Haz clic en el botón Permitir si ves este mensaje para que puedas copiar y pegar en la estación de trabajo.

- Crea un archivo llamado
requirements.txty copia el siguiente contenido en él.

Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- Crea un archivo llamado
app.pyy pega el siguiente código en él:
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
@app.route("/")
def hello_world():
message="Hello, World!"
return message
if __name__ == '__main__':
server_port = os.environ.get('PORT', '8080')
app.run(debug=False, port=server_port, host='0.0.0.0')
- Crea un archivo llamado
Dockerfiley pega el siguiente código en él:
FROM python:3.8
ARG FLASK_DEBUG=0
ENV FLASK_DEBUG=$FLASK_DEBUG
ENV FLASK_APP=app.py
WORKDIR /app
COPY requirements.txt .
RUN pip install --trusted-host pypi.python.org -r requirements.txt
COPY . .
ENTRYPOINT ["python3", "-m", "flask", "run", "--port=8080", "--host=0.0.0.0"]
Nota: FLASK_DEBUG=1 te permite volver a cargar automáticamente los cambios de código en una app de Flask en Python. Este Dockerfile te permite pasar este valor como un argumento de compilación.
Generar manifiestos
En tu terminal, ejecuta el siguiente comando para generar un archivo skaffold.yaml y un archivo deployment.yaml predeterminados.
- Inicializa Skaffold con el siguiente comando:
skaffold init --generate-manifests
Cuando se te solicite, usa las flechas para mover el cursor y la barra espaciadora para seleccionar las opciones.
Elige:
8080para el puertoypara guardar la configuración
Actualiza la configuración de Skaffold
- Cambia el nombre de la aplicación predeterminada
- Abrir
skaffold.yaml - Selecciona el nombre de la imagen que está configurado actualmente como
dockerfile-image. - Haz clic con el botón derecho y elige Cambiar todas las ocurrencias.
- Escribe el nombre nuevo como
python-app - Edita aún más la sección de compilación para que quede de la siguiente manera:
- Agrega
docker.buildArgsal paseFLASK_DEBUG=1. - Sincroniza la configuración para cargar los cambios en los archivos
*.pydel IDE al contenedor en ejecución
Después de las ediciones, la sección de compilación del archivo skaffold.yaml se vería de la siguiente manera:
build:
artifacts:
- image: python-app
docker:
buildArgs:
FLASK_DEBUG: "1"
dockerfile: Dockerfile
sync:
infer:
- '**/*.py'
Modifica el archivo de configuración de Kubernetes
- Cómo cambiar el nombre predeterminado
- Abre el archivo
deployment.yaml. - Selecciona el nombre de la imagen que está configurado actualmente como
dockerfile-image. - Haz clic con el botón derecho y elige Cambiar todas las ocurrencias.
- Escribe el nombre nuevo como
python-app
4. Explicación del proceso de desarrollo
Con la lógica empresarial agregada, ahora puedes implementar y probar tu aplicación. En la siguiente sección, se mostrará el uso del complemento de Cloud Code. Entre otras cosas, este complemento se integra con Skaffold para optimizar tu proceso de desarrollo. Cuando realices la implementación en GKE en los siguientes pasos, Cloud Code y Skaffold compilarán automáticamente tu imagen de contenedor, la enviarán a Container Registry y, luego, implementarán la aplicación your en GKE. Esto sucede en segundo plano, abstrayendo los detalles del flujo del desarrollador.
Accede a Google Cloud
- Haz clic en el ícono de Cloud Code y selecciona "Acceder a Google Cloud":

- Haz clic en "Continuar al acceso".

- Verifica el resultado en la terminal y abre el vínculo:

- Accede con las credenciales de estudiante de Qwiklabs.

- Selecciona "Permitir":

- Copia el código de verificación y regresa a la pestaña Workstation.

- Pega el código de verificación y presiona Intro.

Agrega un clúster de Kubernetes
- Agrega un clúster

- Selecciona Google Kubernetes Engine:

- Selecciona el proyecto.

- Selecciona "python-cluster", que se creó en la configuración inicial.

- El clúster ahora aparece en la lista de clústeres de Kubernetes en Cloud Code. Desde aquí, puedes navegar y explorar el clúster.

Configura el ID del proyecto actual con la CLI de gcloud
- Copia el ID del proyecto para este lab desde la página de Qwiklabs.

- En la terminal, ejecuta el comando de la CLI de gcloud para establecer el ID del proyecto. Reemplaza el ID del proyecto de muestra antes de ejecutar el comando. SUSTITUYE el ID del proyecto antes de ejecutar el siguiente comando.
gcloud config set project qwiklabs-gcp-project-id
Implementar en Kubernetes
- En el panel que se encuentra en la parte inferior del editor de Cloud Shell, selecciona Cloud Code. 

- En el panel que aparece en la parte superior, selecciona Run on Kubernetes. Si se te solicita, selecciona Sí para usar el contexto actual de Kubernetes.

Este comando inicia una compilación del código fuente y, luego, ejecuta las pruebas. La compilación y las pruebas tardarán unos minutos en ejecutarse. Estas pruebas incluyen pruebas de unidades y un paso de validación que verifica las reglas establecidas para el entorno de implementación. Este paso de validación ya está configurado y garantiza que recibas advertencias sobre problemas de implementación, incluso mientras sigues trabajando en tu entorno de desarrollo.
- La primera vez que ejecutes el comando, aparecerá un mensaje en la parte superior de la pantalla que te preguntará si deseas el contexto actual de Kubernetes. Selecciona "Sí" para aceptar y usar el contexto actual.
- A continuación, se mostrará un mensaje en el que se preguntará qué registro de contenedores usar. Presiona Intro para aceptar el valor predeterminado proporcionado.
- Selecciona la pestaña "Salida" en el panel inferior para ver el progreso y las notificaciones. En el menú desplegable, selecciona “Kubernetes: Run/Debug”.

- Selecciona "Kubernetes: Run/Debug - Detailed" en el menú desplegable del canal a la derecha para ver detalles adicionales y registros que se transmiten en vivo desde los contenedores.

Cuando finalicen la compilación y las pruebas, los registros de la pestaña Resultado incluirán la URL http://localhost:8080 en la vista "Kubernetes: Run/Debug".
- En la terminal de Cloud Code, coloca el cursor sobre la primera URL en el resultado (http://localhost:8080) y, luego, en la información sobre herramientas que aparece, selecciona Abrir en la vista previa web.
- Se abrirá una nueva pestaña del navegador y se mostrará el mensaje
Hello, World!.
Recarga en caliente
- Abre el archivo
app.py. - Cambia el mensaje de saludo a
Hello from Python.
Observa de inmediato que, en la ventana Output, vista Kubernetes: Run/Debug, el observador sincroniza los archivos actualizados con el contenedor en Kubernetes.
Update initiated Build started for artifact python-app Build completed for artifact python-app Deploy started Deploy completed Status check started Resource pod/python-app-6f646ffcbb-tn7qd status updated to In Progress Resource deployment/python-app status updated to In Progress Resource deployment/python-app status completed successfully Status check succeeded ...
- Si cambias a la vista
Kubernetes: Run/Debug - Detailed, notarás que reconoce los cambios en el archivo, luego compila y vuelve a implementar la app.
files modified: [app.py]
Syncing 1 files for gcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Copying files:map[app.py:[/app/app.py]]togcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Watching for changes...
[python-app] * Detected change in '/app/app.py', reloading
[python-app] * Restarting with stat
[python-app] * Debugger is active!
[python-app] * Debugger PIN: 744-729-662
- Actualiza la pestaña del navegador en la que viste los resultados anteriores para ver los resultados actualizados.
Depuración
- Ve a la vista de depuración y detén el subproceso actual
. Si te lo pregunta, puedes elegir limpiar después de cada ejecución. 
- Haz clic en
Cloud Codeen el menú inferior y seleccionaDebug on Kubernetespara ejecutar la aplicación en mododebug.
- En la vista
Kubernetes Run/Debug - Detailedde la ventanaOutput, observa que Skaffold implementará esta aplicación en modo de depuración.
- Cuando se completa el proceso Verás un depurador adjunto y la pestaña Output dirá:
Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully., y se mostrará la URL http://localhost:8080.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- La barra de estado inferior cambia su color de azul a naranja, lo que indica que está en modo de depuración.
- En la vista
Kubernetes Run/Debug, observa que se inició un contenedor depurable.
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
Utiliza puntos de interrupción
- Abre el archivo
app.py. - Ubica la instrucción que dice
return message. - Para agregar un punto de interrupción a esa línea, haz clic en el espacio en blanco a la izquierda del número de línea. Aparecerá un indicador rojo para señalar que se estableció el punto de interrupción.
- La primera vez que se ejecute, aparecerá un mensaje que preguntará dónde se encuentra la fuente dentro del contenedor. Este valor se relaciona con los directorios del Dockerfile.
Presiona Intro para aceptar el valor predeterminado.

La compilación y la implementación de la aplicación tardarán un par de minutos.
- Vuelve a cargar el navegador y observa que el depurador detiene el proceso en el punto de interrupción y te permite investigar las variables y el estado de la aplicación que se ejecuta de forma remota en GKE.
- Haz clic en la sección VARIABLES.
- Haz clic en Locales y allí encontrarás la variable
"message". - Haz doble clic en el nombre de la variable "message" y, en la ventana emergente, cambia el valor por algo diferente, como
"Greetings from Python". - Haz clic en el botón Continuar en el panel de control de depuración.

- Revisa la respuesta en tu navegador, que ahora muestra el valor actualizado que acabas de ingresar.
- Para detener el modo "Depuración", presiona el botón de detener
y quita el punto de interrupción haciendo clic en él de nuevo.
5. Cómo desarrollar un servicio REST de CRUD simple
En este punto, tu aplicación está completamente configurada para el desarrollo en contenedores y ya completaste el flujo de trabajo de desarrollo básico con Cloud Code. En las siguientes secciones, practicarás lo que aprendiste agregando extremos de servicio de REST que se conectan a una base de datos administrada en Google Cloud.
Codifica el servicio de REST
El siguiente código crea un servicio REST simple que usa Spanner como la base de datos que respalda la aplicación. Para crear la aplicación, copia el siguiente código en ella.
- Reemplaza
app.pypor el siguiente contenido para crear la aplicación principal:
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
instance_id = "music-catalog"
database_id = "musicians"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/singer', methods=['POST'])
def create():
try:
request_json = request.get_json()
singer_id = request_json['singer_id']
first_name = request_json['first_name']
last_name = request_json['last_name']
def insert_singers(transaction):
row_ct = transaction.execute_update(
f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
f"({singer_id}, '{first_name}', '{last_name}')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['GET'])
def get_singer():
try:
singer_id = request.args.get('singer_id')
def get_singer():
first_name = ''
last_name = ''
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
f"SELECT SingerId, FirstName, LastName FROM Singers " \
f"where SingerId = {singer_id}",
)
for row in results:
first_name = row[1]
last_name = row[2]
return (first_name,last_name )
first_name, last_name = get_singer()
return {"first_name": first_name, "last_name": last_name }, 200
except Exception as e:
return e
@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
try:
singer_id = request.args.get('singer_id')
request_json = request.get_json()
first_name = request_json['first_name']
def update_singer(transaction):
row_ct = transaction.execute_update(
f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_singer)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['DELETE'])
def delete_singer():
try:
singer_id = request.args.get('singer')
def delete_singer(transaction):
row_ct = transaction.execute_update(
f"DELETE FROM Singers WHERE SingerId = {singer_id}"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singer)
return {"Success": True}, 200
except Exception as e:
return e
port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=port)
Agrega configuraciones de bases de datos
Para conectarte a Spanner de forma segura, configura la aplicación para que use identidades de cargas de trabajo. Esto permite que tu aplicación actúe como su propia cuenta de servicio y tenga permisos individuales cuando acceda a la base de datos.
- Actualiza
deployment.yaml. Agrega el siguiente código al final del archivo (asegúrate de conservar las sangrías de tabulación del siguiente ejemplo):
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Después de los cambios, la sección spec debería verse así:
spec:
containers:
- name: python-app
image: python-app
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Implementa y valida la aplicación
- En el panel que se encuentra en la parte inferior del Editor de Cloud Shell, selecciona
Cloud Codey, luego,Debug on Kubernetesen la parte superior de la pantalla. - Cuando finalicen la compilación y las pruebas, la pestaña Output dirá:
Resource deployment/python-app status completed successfullyy se mostrará una URL: "Forwarded URL from service python-app: http://localhost:8080". - Agrega algunas entradas.
En la terminal de Cloud Shell, ejecuta el siguiente comando:
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- Para probar el método GET, ejecuta el siguiente comando en la terminal:
curl -X GET http://localhost:8080/singer?singer_id=6
- Prueba de eliminación: Ahora intenta borrar una entrada ejecutando el siguiente comando. Cambia el valor de item-id si es necesario.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
Identifica y corrige el problema
- Modo de depuración para encontrar el problema A continuación, se incluyen algunas sugerencias:
- Sabemos que hay un problema con la instrucción DELETE, ya que no devuelve el resultado deseado. Por lo tanto, establecerías el punto de interrupción en
app.pyen el métododelete_singer. - Ejecuta paso a paso y observa las variables en cada paso para ver los valores de las variables locales en la ventana de la izquierda.
- Para observar valores específicos, como
singer_idyrequest.args, agrega estas variables a la ventana Watch.
- Ten en cuenta que el valor asignado a
singer_idesNone. Cambia el código para solucionar el problema.
El fragmento de código corregido se vería de la siguiente manera:
@app.route('/delete-singer', methods=['DELETE', 'GET'])
def delete_singer():
try:
singer_id = request.args.get('singer_id')
- Una vez que se reinicie la aplicación, vuelve a probar si se puede borrar.
- Para detener la sesión de depuración, haz clic en el cuadrado rojo de la barra de herramientas de depuración.

6. Limpieza
¡Felicitaciones! En este lab, creaste una nueva aplicación de Python desde cero y la configuraste para que funcione de manera eficaz con contenedores. Luego, implementaste y depuraste tu aplicación en un clúster de GKE remoto siguiendo el mismo flujo de desarrollador que se encuentra en las pilas de aplicaciones tradicionales.
Para limpiar después de completar el lab, haz lo siguiente:
- Borra los archivos que se usaron en el lab
cd ~ && rm -rf ~/music-service
- Borra el proyecto para quitar toda la infraestructura y los recursos relacionados
