Desarrollo de InnerLoop mediante Cloud Workstations con Python

1. Descripción general

En este lab, se muestran 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 típico de contenedores requiere que el usuario comprenda sus detalles y el proceso de compilación de estos. Además, por lo general, los desarrolladores tienen que interrumpir el flujo y salir del IDE para probar y depurar sus aplicaciones en entornos remotos. Con las herramientas y tecnologías mencionadas en este instructivo, los desarrolladores pueden trabajar de manera eficaz con aplicaciones alojadas 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:

  • Crea una nueva aplicación de inicio de Python
  • Recorre el proceso de desarrollo
  • Desarrolla un servicio de descanso CRUD simple
  • Implementar en GKE
  • Depura un estado de error
  • Usa puntos de interrupción o registros
  • Implementando cambios en caliente de vuelta en GKE

58a4cdd3ed7a123a.png

2. Configuración y requisitos

Cómo configurar el entorno a tu propio ritmo

  1. 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.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 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 te importa qué es. En la mayoría de los codelabs, deberás hacer referencia al ID del proyecto (por lo general, se identifica como PROJECT_ID). Si no te gusta el ID generado, puedes generar otro aleatorio. También puedes probar el tuyo propio y ver si está disponible. No se puede cambiar después de este paso y se mantendrá mientras dure el proyecto.
  • Para tu información, 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.
  1. 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 te facture 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,

  1. accede a tu proyecto de Google en https://console.cloud.google.com.
  2. En la esquina superior derecha, haz clic en el ícono del editor de Cloud Shell.

8560cc8d45e8c112.png

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

9e504cb98a6a8005.png

  1. El editor se abrirá con un explorador a la derecha y un editor en el área central.
  2. También debería haber un panel de terminal disponible en la parte inferior de la pantalla.
  3. Si la terminal NO está abierta, usa la combinación de teclas “ctrl+” para abrir una nueva ventana de terminal.

Configuración del entorno

Configura tu ID y número de proyecto en Cloud Shell. Guárdalas 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 las estaciones de trabajo de Cloud como IDE. La siguiente secuencia de comandos de configuración prepara esta infraestructura por ti.

  1. 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
  1. Abre el archivo setup_with_cw.sh y edita los valores de las contraseñas que actualmente están configuradas como CHANGEME
  2. Ejecuta la secuencia de comandos de configuración para preparar 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

  1. Abre Cloud Workstations en la consola de Cloud. Espera a que el clúster tenga el estado READY.

305e1a3d63ac7ff6.png

Crear configuración de estaciones de trabajo

  1. Si se desconectó tu sesión de Cloud Shell, haz clic en “Volver a conectar” y, luego, ejecuta el comando gcloud cli para configurar el ID del proyecto. Reemplaza el ID del proyecto de muestra que aparece a continuación por el ID de tu proyecto de Qwiklabs antes de ejecutar el comando.
gcloud config set project qwiklabs-gcp-project-id
  1. 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
  1. Verifica los resultados en la sección Configuración. La transición al estado READY tardará 2 minutos.

2e23c2e9983d1ccf.png

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

a53adeeac81a78c8.png

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

f052cd47701ec774.png

  1. Verifica los resultados en la sección Estaciones de trabajo.

Iniciar estación de trabajo

  1. Inicia y, luego, inicia la estación de trabajo. La estación de trabajo tardará unos minutos en iniciarse.

682f8a307032cba3.png

  1. Permite las cookies de terceros haciendo clic en el ícono de la barra de direcciones. 1b8923e2943f9bc4.png

fcf9405b6957b7d7.png

  1. Haz clic en "¿El sitio no funciona?".

36a84c0e2e3b85b.png

  1. Haz clic en "Permitir cookies".

2259694328628fba.png

  1. Una vez que se inicie la estación de trabajo, verás que aparece Code OSS IDE. Haz clic en "Marcar como hecho". En la página Primeros pasos, el IDE de la estación de trabajo

94874fba9b74cc22.png

3. Crea una aplicación de inicio de Python nueva

En esta sección, crearás una nueva aplicación de Python.

  1. Abre una terminal nueva.

c31d48f2e4938c38.png

  1. Crea un directorio nuevo y ábrelo como lugar de trabajo.
mkdir music-service && cd music-service

code-oss-cloud-workstations -r --folder-uri="$PWD"

Si ves este mensaje, haz clic en el botón Permitir para copiar y pegar en la estación de trabajo.

58149777e5cc350a.png

  1. Crea un archivo llamado requirements.txt y copia el siguiente contenido en él

827e8389170bd900.png

Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
  1. Crea un archivo llamado app.py y pega en él el siguiente código.
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')

  1. Crea un archivo llamado Dockerfile y pega lo siguiente 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 a una app de flask de Python. Este Dockerfile te permite pasar este valor como un argumento de compilación.

Generar manifiestos

En la terminal, ejecuta el siguiente comando para generar un archivo predeterminado skaffold.yaml y deployment.yaml

  1. 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:

  • 8080 para el puerto
  • y para guardar la configuración

Actualiza los parámetros de configuración de Skaffold

  • Cambia el nombre predeterminado de la aplicación
  • Abrir skaffold.yaml
  • Selecciona el nombre de la imagen establecido actualmente como dockerfile-image
  • Haz clic con el botón derecho y elige Cambiar todos los casos.
  • Escribe el nombre nuevo como python-app.
  • Edita la sección de compilación para
  • agrega docker.buildArgs para pasar FLASK_DEBUG=1
  • La configuración de sincronización para cargar los cambios en los archivos *.py del IDE al contenedor en ejecución

Después de las modificaciones, la sección de compilación del archivo skaffold.yaml se verá de la siguiente manera:

build:
 artifacts:
 - image: python-app
   docker:
     buildArgs:
       FLASK_DEBUG: "1"
     dockerfile: Dockerfile
   sync:
     infer:
     - '**/*.py'

Modificar el archivo de configuración de Kubernetes

  1. Cómo cambiar el nombre predeterminado
  • Abrir archivo deployment.yaml
  • Selecciona el nombre de la imagen establecido actualmente como dockerfile-image
  • Haz clic con el botón derecho y elige Cambiar todos los casos.
  • 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 sigas estos pasos para implementar en GKE, 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 detrás de escena, abstrae los detalles del flujo del desarrollador.

Accede a Google Cloud

  1. Haz clic en el ícono de Cloud Code y selecciona “Acceder a Google Cloud”:

1769afd39be372ff.png

  1. Haz clic en "Continuar para acceder".

923bb1c8f63160f9.png

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

517fdd579c34aa21.png

  1. Accede con tus credenciales de estudiantes de Qwiklabs.

db99b345f7a8e72c.png

  1. Selecciona "Permitir":

a5376553c430ac84.png

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

6719421277b92eac.png

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

e9847cfe3fa8a2ce.png

Agregar clúster de Kubernetes

  1. Agrega un clúster

62a3b97bdbb427e5.png

  1. Selecciona Google Kubernetes Engine:

9577de423568bbaa.png

  1. Selecciona un proyecto.

c5202fcbeebcd41c.png

  1. Selecciona “python-cluster” que se creó en la configuración inicial.

80c8c2556655.png

  1. El clúster ahora aparece en la lista de clústeres de Kubernetes en Cloud Code. Navega y explora el clúster desde aquí.

7e5f50662d4eea3c.png

Establece el ID del proyecto actual con gcloud cli

  1. Copia el ID del proyecto de este lab desde la página de Qwiklabs.

fcff2d10007ec5bc.png

  1. En la terminal, ejecuta el comando gcloud cli para configurar 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

  1. En el panel ubicado en la parte inferior del editor de Cloud Shell, selecciona Cloud Code pago.

d99a88992e15fea9.png

  1. 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.

bfd65e9df6d4a6cb.png

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 comprueba las reglas establecidas para el entorno de implementación. Este paso de validación ya está configurado y garantiza que recibas advertencias de problemas de implementación, incluso mientras sigues trabajando en tu entorno de desarrollo.

  1. La primera vez que ejecutes el comando, aparecerá un mensaje en la parte superior de la pantalla en el que se te preguntará si quieres conocer el contexto de Kubernetes actual. Selecciona “Yes” aceptar y usar el contexto actual.
  2. A continuación, se mostrará un mensaje en el que se te preguntará qué registro de contenedores usar. Presiona Intro para aceptar el valor predeterminado proporcionado
  3. Selecciona la "Salida". en el panel inferior para ver el progreso y las notificaciones. En el menú desplegable, selecciona “Kubernetes: Run/Debug”

9c87ccbf5d06f50a.png

  1. Selecciona “Kubernetes: Run/Debug - Detail”. En el menú desplegable de canales que se encuentra a la derecha para ver detalles adicionales y registros que se transmiten en vivo desde los contenedores

804abc8833ffd571.png

Cuando finalice la compilación y las pruebas, los registros de la pestaña Salida mostrarán la URL http://localhost:8080 en el campo “Kubernetes: Run/Debug” vista.

  1. En la terminal de Cloud Code, coloca el cursor sobre la primera URL del resultado (http://localhost:8080) y, luego, en la sugerencia de herramientas que aparece, selecciona Open Web Preview.
  2. Se abrirá una nueva pestaña del navegador y se mostrará el mensaje Hello, World!

Recarga en caliente

  1. Abre el archivo app.py.
  2. Cambiar el mensaje de saludo a Hello from Python

Observa inmediatamente que en la ventana Output, en la 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
...
  1. Si cambias a la vista Kubernetes: Run/Debug - Detailed, notarás que reconoce los cambios en el archivo y, 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
  1. Actualiza la pestaña del navegador donde viste los resultados anteriores para verlos actualizados.

Depuración

  1. Ve a la vista de depuración y detén el subproceso actual 647213126d7a4c7b.png. Si te lo solicita, puedes optar por realizar una limpieza después de cada ejecución.
  2. 70d6bd947d04d1e6.png
  3. Haz clic en Cloud Code en el menú inferior y selecciona Debug on Kubernetes para ejecutar la aplicación en modo debug.
  • En la vista Kubernetes Run/Debug - Detailed de la ventana Output, observa que Skaffold implementará esta aplicación en modo de depuración.
  1. Cuando se complete el proceso. Verás que adjuntas un depurador y la pestaña Salida dice: Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully. y aparece la URL http://localhost:8080.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
  1. La barra de estado inferior cambia de color de azul a naranja, lo que indica que está en modo de depuración.
  2. En la vista Kubernetes Run/Debug, observa que se inicia un contenedor Debuggable.
**************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

  1. Abre el archivo app.py.
  2. Busca la sentencia que dice return message.
  3. 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. Se mostrará un indicador rojo para indicar que se estableció el punto de interrupción
  4. La primera vez que se ejecute, un mensaje te preguntará dónde está la fuente dentro del contenedor. Este valor está relacionado con los directorios en el Dockerfile.

Presiona Intro para aceptar

fccc866f32b5ed86.png

La aplicación tardará algunos minutos en compilarse e implementarse.

  1. 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.
  2. Haz clic en la sección VARIABLES.
  3. Haz clic en Locales y encontrarás la variable "message".
  4. Haz doble clic en el nombre de variable "message" En la ventana emergente, cambia el valor a uno diferente, como "Greetings from Python".
  5. Haz clic en el botón Continuar en el panel de control de depuración 607c33934f8d6b39.png
  6. Revisa la respuesta en tu navegador, que ahora muestra el valor actualizado que acabas de ingresar.
  7. Cómo detener la "depuración" si presionas el botón de detención 647213126d7a4c7b.png y, para quitar el punto de interrupción, vuelves a hacer clic en él.

5. Desarrollar un servicio simple de REST de CRUD

En este punto, tu aplicación está completamente configurada para el desarrollo en contenedores, y ya recorriste el flujo de trabajo básico de desarrollo con Cloud Code. En las siguientes secciones, pondrás en práctica lo que aprendiste agregando extremos del servicio de REST conectados a una base de datos administrada en Google Cloud.

Codificar el servicio de resto

El siguiente código crea un servicio de 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 tu aplicación.

  1. Para crear la aplicación principal, reemplaza app.py por el siguiente contenido
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)

Agregar parámetros de configuración de la base de datos

Si quieres conectarte a Spanner de forma segura, configura la aplicación para que use identidades de carga 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.

  1. Actualiza deployment.yaml. Agrega el siguiente código al final del archivo (asegúrate de mantener las sangrías de tabulación en el siguiente ejemplo).
      serviceAccountName: python-ksa
      nodeSelector:
        iam.gke.io/gke-metadata-server-enabled: "true" 

Después de los cambios, la sección de especificaciones 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

  1. En el panel ubicado en la parte inferior del Editor de Cloud Shell, selecciona Cloud Code y, luego, elige Debug on Kubernetes en la parte superior de la pantalla.
  2. Cuando finalicen la compilación y las pruebas, la pestaña Salida indicará Resource deployment/python-app status completed successfully y aparecerá una URL: “URL reenviada del servicio python-app: http://localhost:8080”
  3. Agrega algunas entradas.

En la terminal de cloudshell, 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}'
  1. Ejecuta el siguiente comando en la terminal para probar GET
curl -X GET http://localhost:8080/singer?singer_id=6
  1. Prueba la eliminación: Ahora intenta borrar una entrada con el siguiente comando. Si es necesario, cambia el valor de item-id.
curl -X DELETE http://localhost:8080/singer?singer_id=6
    This throws an error message
500 Internal Server Error

Identifica y soluciona el problema

  1. Modo de depuración y busca el problema. A continuación, se incluyen algunas sugerencias:
  • Sabemos que hay un problema con DELETE, ya que no muestra el resultado deseado. Por lo tanto, debes establecer el punto de interrupción en app.py, en el método delete_singer.
  • Realiza la ejecución paso a paso y observa las variables en cada paso para observar los valores de las variables locales en la ventana de la izquierda.
  • Para observar valores específicos, como singer_id y request.args, en la ventana de visualización, agrega estas variables.
  1. Ten en cuenta que el valor asignado a singer_id es None. Cámbialo para solucionar el problema.

El fragmento de código fijo se vería así.

@app.route('/delete-singer', methods=['DELETE', 'GET'])
def delete_singer():
    try:
        singer_id = request.args.get('singer_id')
  1. Una vez que se reinicie la aplicación, intenta borrarla nuevamente.
  2. Para detener la sesión de depuración, haz clic en el cuadrado rojo de la barra de herramientas de depuración 647213126d7a4c7b.png

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 con el mismo flujo de desarrollador que se encuentra en las pilas de aplicaciones tradicionales.

Sigue estos pasos para realizar una limpieza después de completar el lab:

  1. Borra los archivos utilizados en el lab
cd ~ && rm -rf ~/music-service
  1. Borra el proyecto para quitar toda la infraestructura y los recursos relacionados.