1. Objetivos
El propósito de este taller es brindar educación práctica sobre Duet AI a usuarios y profesionales.
En este codelab, aprenderás lo siguiente:
- Activa Duet AI en tu proyecto de GCP y configúralo para usarlo en un IDE y la consola de Cloud.
- Usa Duet AI para generar, completar y explicar código.
- Usa Duet AI para explicar y solucionar un problema de una aplicación.
- Funciones de Duet AI como chat con IDE y chat de varios turnos, generación de código intercalado en comparación con el chat, acciones inteligentes como la explicación del código y el reconocimiento de solicitudes, y mucho más.
Narración
Con el objetivo de mostrar cómo se usa Duet AI para desarrolladores con autenticidad en el desarrollo diario, las actividades de este taller se llevan a cabo en un contexto narrativo.
Un nuevo desarrollador se une a una empresa de comercio electrónico. Su tarea consiste en agregar un servicio nuevo a la aplicación de comercio electrónico existente (compuesta por varios servicios). El nuevo servicio proporciona información adicional (dimensiones, peso, etc.) sobre los productos del catálogo. Este servicio permitirá costos de envío mejores y más económicos en función de las dimensiones y el peso de los productos.
Como el desarrollador es nuevo en la empresa, usará Duet AI para generar, explicar y documentar código.
Después de codificar el servicio, un administrador de la plataforma usará Duet AI (chat) para ayudar a crear el artefacto (contenedor de Docker) y los recursos necesarios para implementarlo en GCP (por ejemplo, Artifact Registry, permisos de IAM, un repositorio de código, la infraestructura de procesamiento, es decir, GKE o CloudRun, etcétera).
Una vez que la aplicación se implementa en GCP, un operador de aplicaciones/SRE usará Duet AI (y Cloud Ops) para ayudar a solucionar un error en el nuevo servicio.
Persona
El taller abarca la siguiente persona:
- Desarrollador de aplicaciones: Se requiere cierto nivel de conocimientos en programación y desarrollo de software.
Esta variación del taller de Duet AI es solo para desarrolladores. No es necesario tener conocimientos sobre los recursos en la nube de GCP. Aquí encontrarás las secuencias de comandos que explican cómo compilar los recursos de GCP necesarios para ejecutar esta aplicación. Puedes seguir las instrucciones de esta guía para implementar los recursos de GCP necesarios.
2. Prepara el entorno
Activando Duet AI
Puedes activar Duet AI en un proyecto de GCP mediante la API (gcloud o herramientas de IaC como Terraform) o la IU de la consola de Cloud.
Para activar Duet AI en un proyecto de Google Cloud, habilita la API de Cloud AI Companion y otorga los roles de Identity and Access Management (IAM) de Usuario de Cloud AI Companion y Visualizador de Service Usage a los usuarios.
A través de gcloud
Activa Cloud Shell:
Configura tu PROJECT_ID
y USER
, y habilita la API de Cloud AI Companion.
export PROJECT_ID=<YOUR PROJECT ID> export USER=<YOUR USERNAME> # Use your full LDAP, e.g. name@example.com gcloud config set project ${PROJECT_ID} gcloud services enable cloudaicompanion.googleapis.com --project ${PROJECT_ID}
El resultado es como el siguiente:
Updated property [core/project]. Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.
Otorga los roles de Identity and Access Management (IAM) de Usuario de Cloud AI Companion y Visualizador de Service Usage a la cuenta de USER. La API de Cloud Companion se encuentra detrás de las funciones del IDE y de la consola que usaremos. El permiso de visualizador de Service Usage se usa como una verificación rápida antes de habilitar la IU en la consola (para que la IU de Duet solo aparezca en proyectos en los que la API esté habilitada).
gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member=user:${USER} --role=roles/cloudaicompanion.user gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member=user:${USER} --role=roles/serviceusage.serviceUsageViewer
El resultado es como el siguiente:
... - members: - user:<YOUR USER ACCOUNT> role: roles/cloudaicompanion.user ... - members: - user:<YOUR USER ACCOUNT> role: roles/serviceusage.serviceUsageViewer
A través de la consola de Cloud
Para habilitar la API, ve a la página de la API de Cloud AI Companion en la consola de Google Cloud.
En el selector de proyectos, elige un proyecto.
Haz clic en Habilitar.
La página se actualizará y mostrará el estado Habilitada. Duet AI ahora está disponible en el proyecto de Google Cloud seleccionado para todos los usuarios que tengan los roles de IAM necesarios.
Si quieres otorgar los roles de IAM necesarios para usar Duet AI, ve a la página IAM.
En la columna Principal, busca el USUARIO para el que quieres habilitar el acceso a Duet AI y, luego, haz clic en el ícono de lápiz ✏️ Editar principal en esa fila.
En el panel de acceso Editar, haz clic en Agregar otro rol.
En Selecciona un rol, elige Usuario de Cloud AI Companion.
Haz clic en Agregar otro rol y selecciona Visualizador de Service Usage.
Haz clic en Guardar.
Configura el IDE
Los desarrolladores pueden elegir entre una variedad de IDEs que se adapten mejor a sus necesidades. La asistencia para código de Duet AI está disponible en varios IDE, como Visual Studio Code, los IDE de JetBrains (IntelliJ, PyCharm, GoLand, WebStorm, entre otros), Cloud Workstations y Editor de Cloud Shell.
En este lab, puedes usar Cloud Workstations o el Editor de Cloud Shell.
En este taller, se usa el editor de Cloud Shell.
Ten en cuenta que Cloud Workstations puede tardar entre 20 y 30 minutos en configurarse.
Para usarlo de inmediato, utiliza el Editor de Cloud Shell.
Para abrir el editor de Cloud Shell, haz clic en el ícono de lápiz ✏️ en la barra de menú superior de Cloud Shell.
El editor de Cloud Shell tiene una IU y una UX muy similares a VSCode.
Haz clic en CTRL (en Windows)/CMD (en Mac) + , (coma) para acceder al panel de configuración.
En la barra de búsqueda, escribe "duet ai".
Asegúrate o habilita Cloudcode › Duet AI: Habilitar y Cloudcode › Duet AI › Sugerencias intercaladas: Habilitar automático
En la barra de estado de la parte inferior, haz clic en Cloud Code - Acceder y sigue el flujo de trabajo para acceder.
Si ya accediste, en la barra de estado aparecerá el mensaje Cloud Code - No project.
Haz clic en Cloud Code - No proyecto. Aparecerá un panel desplegable de acciones en la parte superior. Haz clic en Seleccionar un proyecto de Google Cloud.
Comienza a escribir el ID de tu proyecto. Tu proyecto debería aparecer en la lista.
Selecciona tu PROJECT_ID de la lista de proyectos.
La barra de estado inferior se actualiza para mostrar el ID del proyecto. Si no es así, deberás actualizar la pestaña del editor de Cloud Shell.
Haz clic en el ícono de Duet AI en la barra de menú de la izquierda y aparecerá la ventana de chat de Duet AI. Si recibes un mensaje que dice Seleccionar proyecto de GCP. Haz clic y vuelve a seleccionar el proyecto.
Ahora puedes ver la ventana de chat de Duet AI
3. Configurar la infraestructura
Para ejecutar el servicio de envío nuevo en GCP, necesitarás los siguientes recursos de GCP:
- Una instancia de Cloud SQL, con una base de datos.
- Un clúster de GKE para ejecutar el servicio alojado en contenedores
- Un Artifact Registry para almacenar la imagen de Docker
- Un Cloud Source Repository para el código.
En la terminal de Cloud Shell, clona el siguiente repositorio y ejecuta los siguientes comandos para configurar la infraestructura de tu proyecto de GCP.
# Set your project export PROJECT_ID=<INSERT_YOUR_PROJECT_ID> gcloud config set core/project ${PROJECT_ID} # Enable Cloudbuild and grant Cloudbuild SA owner role export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)') gcloud services enable cloudbuild.googleapis.com gcloud projects add-iam-policy-binding ${PROJECT_ID} --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com --role roles/owner # Clone the repo git clone https://github.com/duetailabs/dev.git ~/duetaidev cd ~/duetaidev # Run Cloudbuild to create the necessary resources gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} # To destroy all GCP resources, run the following # gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} --config=cloudbuild_destroy.yaml
4. Desarrolla un servicio Flask en Python
El servicio que crearemos constará, en última instancia, de los siguientes archivos. No es necesario que crees estos archivos ahora. Para crearlos de a uno, sigue las instrucciones que se indican a continuación:
package-service.yaml
: Es una especificación de Open API para el servicio de paquetes que tiene datos como la altura, el ancho, el peso y las instrucciones especiales de manejo.data_model.py
: Es el modelo de datos para las especificaciones de la API de package-service. También crea la tablapackages
en la base de datos product_details.connect_connector.py
: Conexión de Cloud SQL (define el motor, la sesión y el ORM base)db_init.py
: Genera datos de muestra en la tablapackages
.main.py
: Es un servicio de Flask en Python con un extremoGET
para recuperar detalles del paquete a partir de los datos depackages
basados en product_id.test.py
: Prueba de unidadrequirement.txt
: Requisitos de PythonDockerfile
: Para alojar esta aplicación en contenedores
Si tienes algún problema persistente durante los ejercicios, encontrarás los archivos finales en el APÉNDICE de este codelab a modo de referencia.
En el paso anterior, creaste un Cloud Source Repository. Clona el repositorio. Compilarás los archivos de la aplicación en la carpeta del repositorio clonado.
En la terminal de Cloud Shell, ejecuta el siguiente comando para clonar el repositorio.
cd ~ gcloud source repos clone shipping shipping cd ~/shipping
Abre la barra lateral del chat de Duet AI desde el menú de la izquierda del Editor de Cloud Shell. El ícono es similar a . Ahora puedes usar Duet AI para obtener asistencia con el código.
package-service.yaml
Sin ningún archivo abierto, pídele a Duet que genere una especificación de Open API para el servicio de envío.
Consigna 1: Genera una especificación YAML de OpenAPI para un servicio que proporcione información de envío y paquetes con un ID de producto numérico. El servicio debe incluir información sobre la altura, el ancho, la profundidad y el peso de los paquetes, así como cualquier instrucción especial de manipulación.
En la parte superior derecha de la ventana del código generado, aparecerán tres opciones.
Puedes COPY
el código y PEGARlo en un archivo.
Puedes ADD
el código en el archivo abierto actualmente en el editor.
También puedes OPEN
el código en un archivo nuevo.
Haz clic en OPEN
para agregar el código en un archivo nuevo.
Haz clic en CTRL/CMD + s
para guardar el archivo y almacénalo en la carpeta de la aplicación con el nombre package-service.yaml
. Haz clic en Aceptar.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver las respuestas de Duet AI.
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
data_model.py
A continuación, crearás el archivo de Python del modelo de datos para el servicio según la especificación de OpenAPI.
Con el archivo package-service.yaml
abierto, ingresa el siguiente mensaje.
Consigna 1: Usa el ORM de Python sqlalchemy para generar un modelo de datos para este servicio de la API. Además, incluye una función independiente y un punto de entrada principal que cree las tablas de la base de datos.
Observemos cada parte que se generó. Duet AI sigue siendo un asistente y, si bien puede ayudar a escribir código con rapidez, debes revisar el contenido generado y entenderlo a medida que avanzas.
Primero, hay una clase llamada Package
de categoría Base
que define el modelo de datos para la base de datos packages
de la siguiente manera:
class Package(Base):
__tablename__ = 'packages'
id = Column(Integer, primary_key=True)
product_id = Column(String(255))
height = Column(Float)
width = Column(Float)
depth = Column(Float)
weight = Column(Float)
special_handling_instructions = Column(String(255))
A continuación, necesitas una función que cree la tabla en la base de datos como la siguiente:
def create_tables(engine):
Base.metadata.create_all(engine)
Por último, necesitas una función principal que ejecute la función create_tables
para compilar la tabla en la base de datos de Cloud SQL, como se muestra a continuación:
if __name__ == '__main__':
from sqlalchemy import create_engine
engine = create_engine('sqlite:///shipping.db')
create_tables(engine)
print('Tables created successfully.')
Ten en cuenta que la función main
está creando un motor con una base de datos local sqlite
. Para usar Cloud SQL, deberás cambiarlo. Lo harás un poco más tarde.
Usa OPEN
para el código en un flujo de trabajo de archivo nuevo, como antes. Guarda el código en un archivo llamado
data_model.py
(ten en cuenta el guion bajo en el nombre y no el guion).
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
connect-connector.py
Crea el conector de Cloud SQL.
Con el archivo data_model.py
abierto, ingresa los siguientes mensajes.
Consigna 1: Con la biblioteca cloud-sql-python-connector, generar una función que inicialice un grupo de conexiones para una instancia de Cloud SQL de Postgres.
Ten en cuenta que la respuesta no usa la biblioteca cloud-sql-python-connector
. Puedes definir mejor las instrucciones y darle a Duet un pequeño empujón agregando información específica a la misma conversación de chat.
Usemos otra instrucción.
Consigna 2: Debes usar la biblioteca cloud-sql-python-connector.
Asegúrate de que use la biblioteca cloud-sql-python-connector
.
Usa OPEN
para el código en un flujo de trabajo de archivo nuevo, como antes. Guarda el código en un archivo llamado
connect_conector.py
. Es posible que debas importar manualmente la biblioteca pg8000
. Consulta el archivo que aparece a continuación.
Borra el historial de chat de Duet AI y, con el archivo connect_connector.py
abierto, genera el ORM de DB engine
, sessionmaker
y base
para usar en la aplicación.
Consigna 1: Crea un motor, una clase sessionmaker y un ORM base con el método connect_with_connector
La respuesta puede agregar engine
, Session
y Base
al archivo connect_connector.py
.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver la posible variación de las respuestas de Duet AI.
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
Actualiza data_model.py
Debes usar el motor que creaste en el paso anterior (en el archivo connect_connector.py
) para crear una tabla en la base de datos de Cloud SQL.
Borra el historial de chat de Duet AI. Abre el archivo data_model.py
. Prueba la siguiente instrucción.
Consigna 1: En la función principal, importa y usa el motor de connect_connector.py.
Deberías ver la respuesta que importa engine
desde connect_connector
(para Cloud SQL). create_table
usa ese motor (en lugar de la base de datos local sqlite
predeterminada).
Actualiza el archivo data_model.py
.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver las diferentes respuestas de Duet AI.
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
requirements.txt
Crea un archivo requirements.txt
para la aplicación.
Abre connect_connector.py
y el archivo data_model.py
, e ingresa el siguiente mensaje.
Consigna 1: Genera un archivo de requisitos de pip para este modelo de datos y servicio
Consigna 2: Genera un archivo de requisitos de pip para este modelo de datos y servicio con las versiones más recientes
Verifica que los nombres y las versiones sean correctos. Por ejemplo, en la respuesta anterior, el nombre y la versión de google-cloud-sql-connecter
son incorrectos. Corrige las versiones de forma manual y crea un archivo requirements.txt
similar al siguiente:
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
En la terminal de comandos, ejecuta lo siguiente:
pip3 install -r requirements.txt
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
Crea una tabla de paquetes en Cloud SQL
Configura las variables de entorno para el conector de bases de datos de Cloud SQL.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)') export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)") export DB_USER=evolution export DB_PASS=evolution export DB_NAME=product_details
Ahora ejecuta data_model.py.
python data_model.py
El resultado es similar al siguiente (verifica el código para ver qué es lo que realmente se espera):
Tables created successfully.
Conéctate a la instancia de Cloud SQL y verifica que la base de datos se haya creado.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Después de ingresar la contraseña (también llamada evolution), obtén las tablas.
product_details=> \dt
El resultado es similar a este:
List of relations Schema | Name | Type | Owner --------+----------+-------+----------- public | packages | table | evolution (1 row)
También puedes verificar el modelo de datos y los detalles de la tabla.
product_details=> \d+ packages
El resultado es similar a este:
Table "public.packages" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description -------------------------------+-------------------+-----------+----------+--------------------------------------+----------+-------------+--------------+------------- id | integer | | not null | nextval('packages_id_seq'::regclass) | plain | | | product_id | integer | | not null | | plain | | | height | double precision | | not null | | plain | | | width | double precision | | not null | | plain | | | depth | double precision | | not null | | plain | | | weight | double precision | | not null | | plain | | | special_handling_instructions | character varying | | | | extended | | | Indexes: "packages_pkey" PRIMARY KEY, btree (id) Access method: heap
Escribe \q
para salir de Cloud SQL.
db_init.py
A continuación, agreguemos algunos datos de muestra a la tabla packages
.
Borra el historial de chat de Duet AI. Con el archivo data_model.py
abierto, prueba los siguientes mensajes.
Consigna 1: Genera una función que cree 10 filas de paquetes de muestra y las confirme en la tabla de paquetes
Consigna 2: Con la sesión de connect_connector, genera una función que cree 10 filas de paquetes de muestra y las confirme en la tabla de paquetes
Usa OPEN
para el código en un flujo de trabajo de archivo nuevo, como antes. Guarda el código en un archivo llamado
db_init.py
.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver las diferentes respuestas de Duet AI.
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
Crea datos de paquetes de muestra
Ejecuta db_init.py
desde la línea de comandos.
python db_init.py
El resultado es similar a este:
Packages created successfully.
Vuelve a conectarte a la instancia de Cloud SQL y verifica que los datos de muestra se hayan agregado a la tabla de paquetes.
Conéctate a la instancia de Cloud SQL y verifica que la base de datos se haya creado.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Después de ingresar la contraseña (también llamada evolution), obtén todos los datos de la tabla de paquetes.
product_details=> SELECT * FROM packages;
El resultado es similar a este:
id | product_id | height | width | depth | weight | special_handling_instructions ----+------------+--------+-------+-------+--------+----------------------------------- 1 | 0 | 10 | 10 | 10 | 10 | No special handling instructions. 2 | 1 | 10 | 10 | 10 | 10 | No special handling instructions. 3 | 2 | 10 | 10 | 10 | 10 | No special handling instructions. 4 | 3 | 10 | 10 | 10 | 10 | No special handling instructions. 5 | 4 | 10 | 10 | 10 | 10 | No special handling instructions. 6 | 5 | 10 | 10 | 10 | 10 | No special handling instructions. 7 | 6 | 10 | 10 | 10 | 10 | No special handling instructions. 8 | 7 | 10 | 10 | 10 | 10 | No special handling instructions. 9 | 8 | 10 | 10 | 10 | 10 | No special handling instructions. 10 | 9 | 10 | 10 | 10 | 10 | No special handling instructions. (10 rows)
Escribe \q
para salir de Cloud SQL.
main.py
Con los archivos data_model.py
, package-service.yaml
y connect_connector.py
abiertos, crea un main.py
para la aplicación.
Consigna 1: Usa la biblioteca de flask de Python: crea una implementación que use extremos de REST HTTP para este servicio
Consigna 2: Usa la biblioteca de flask de Python: crea una implementación que use extremos de REST HTTP para este servicio. importar y usar SessionMaker de connect_conector.py para los datos de paquetes
Consigna 3: Usa la biblioteca de flask de Python: crea una implementación que use extremos de REST HTTP para este servicio. importar y usar el paquete de data_model.py y SessionMaker de connect_conector.py a los datos de los paquetes
Consigna 4: Usa la biblioteca de flask de Python: crea una implementación que use extremos de REST HTTP para este servicio. importar y usar un paquete de data_model.py y SessionMaker de connect_conector.py a datos de paquetes. Usa la IP del host 0.0.0.0 para app.run
Actualiza los requisitos de main.py
.
Mensaje: Crea un archivo de requisitos para main.py
Agrega esto al archivo requirements.txt
. Asegúrate de usar la versión 3.0.0 de Flask.
Usa OPEN
para el código en un flujo de trabajo de archivo nuevo, como antes. Guarda el código en un archivo llamado
main.py
.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
5. Prueba y ejecuta la aplicación
Instala los requisitos.
pip3 install -r requirements.txt
Ejecuta main.py
.
python main.py
El resultado es similar a este:
* Serving Flask app 'main' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://10.88.0.3:5000 Press CTRL+C to quit
Desde una segunda terminal, prueba el extremo /packages/<product_id>
.
curl localhost:5000/packages/1
El resultado es similar a este:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
También puedes probar cualquier otro ID del producto en tus datos de muestra.
Ingresa CTRL_C
para salir del contenedor de Docker que se está ejecutando en la terminal.
Cómo generar pruebas de unidades
Con el archivo main.py
abierto, genera pruebas de unidades.
Consigna 1: Genera pruebas de unidades.
Usa OPEN
para el código en un flujo de trabajo de archivo nuevo, como antes. Guarda el código en un archivo llamado
test.py
.
En la función test_get_package
, se debe definir un product_id
. Puedes agregarla de forma manual.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
Restablece el historial de chat de Duet AI haciendo clic en el ícono de papelera en la parte superior de la barra lateral de Duet AI.
Ejecutar pruebas de unidades
Ejecuta la prueba de unidades.
python test.py
El resultado es similar a este:
. ---------------------------------------------------------------------- Ran 1 test in 1.061s OK
Cierra todos los archivos en el Editor de Cloud Shell y borra el historial de chat haciendo clic en el ícono de papelera ubicado en la barra de estado superior.
Dockerfile
Crea un Dockerfile
para esta aplicación.
Abre main.py
y prueba los siguientes mensajes.
Consigna 1: Genera un Dockerfile para esta aplicación.
Consigna 2: Genera un Dockerfile para esta aplicación. Copia todos los archivos en el contenedor.
También debes configurar ENVARS
para INSTANCE_CONNECTION_NAME
, DB_USER
, DB_PASS
y DB_NAME
. Puedes hacerlo de forma manual. Tu Dockerfile debería verse de la siguiente manera:
FROM python:3.10-slim
WORKDIR /app
COPY . ./
RUN pip install -r requirements.txt
# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details
CMD ["python", "main.py"]
Usa OPEN
para el código en un flujo de trabajo de archivo nuevo, como antes. Guarda el código en un archivo llamado Dockerfile.
El archivo final se encuentra en la sección APÉNDICE de este codelab. De lo contrario, haz los cambios correspondientes de forma manual.
Ejecución local de la aplicación
Con el Dockerfile
abierto, prueba el siguiente mensaje.
Consigna 1: ¿Cómo ejecuto de forma local un contenedor con este Dockerfile?
Sigue las instrucciones.
# Build docker build -t shipping . # And run docker run -p 5000:5000 -it shipping
El resultado es similar a este:
* Serving Flask app 'main' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://172.17.0.2:5000 Press CTRL+C to quit
Desde una segunda ventana de la terminal, accede al contenedor.
curl localhost:5000/packages/1
El resultado es similar a este:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
La aplicación alojada en contenedores funciona.
Ingresa CTRL_C
para salir del contenedor de Docker que se está ejecutando en la terminal.
Compila una imagen de contenedor en Artifact Registry
Compila la imagen de contenedor y envíala a Artifact Registry.
cd ~/shipping gcloud auth configure-docker us-central1-docker.pkg.dev docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping . docker push us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
El contenedor de la aplicación ahora se encuentra en us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
, que se puede implementar en GKE.
6. Implementa la aplicación en el clúster de GKE
Se creó un clúster de GKE Autopilot cuando compilaste los recursos de GCP para este taller. Conéctate al clúster de GKE.
gcloud container clusters get-credentials gke1 \ --region=us-central1
Anotar la cuenta de servicio predeterminada de Kubernetes con la cuenta de servicio de Google
kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com
El resultado es similar a este:
serviceaccount/default annotated
Prepara y aplica el archivo k8s.yaml.
cp ~/duetaidev/k8s.yaml_tmpl ~/shipping/. export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)') export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)") export IMAGE_REPO=us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping envsubst < ~/shipping/k8s.yaml_tmpl > k8s.yaml kubectl apply -f k8s.yaml
El resultado es similar a este:
deployment.apps/shipping created service/shipping created
Espera hasta que los Pods se estén ejecutando y el Service tenga asignada una dirección IP del balanceador de cargas externo.
kubectl get pods kubectl get service shipping
El resultado es similar a este:
# kubectl get pods NAME READY STATUS RESTARTS AGE shipping-f5d6f8d5-56cvk 1/1 Running 0 4m47s shipping-f5d6f8d5-cj4vv 1/1 Running 0 4m48s shipping-f5d6f8d5-rrdj2 1/1 Running 0 4m47s # kubectl get service shipping NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE shipping LoadBalancer 34.118.225.125 34.16.39.182 80:30076/TCP 5m41s
Para los clústeres de GKE Autopilot, espera unos minutos hasta que los recursos estén listos.
Accede al servicio a través de la dirección EXTERNAL-IP
.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}') curl http://${EXTERNAL_IP}/packages/1
El resultado es similar a este:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
7. Crédito adicional: Solucionar problemas de la solicitud
Quita el rol de IAM del cliente de Cloud SQL de la cuenta de servicio cloudsqlsa
. Esto provoca un error de conexión a la base de datos de Cloud SQL.
gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/cloudsql.client"
Reinicia el Pod de envío.
kubectl rollout restart deployment shipping
Después de que se reinicie el Pod, intenta acceder de nuevo al servicio shipping
.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}') curl http://${EXTERNAL_IP}/packages/1
El resultado es similar a este:
... <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
Para inspeccionar los registros, dirígete a Kubernetes Engine > Cargas de trabajo
Haz clic en la implementación de shipping
y, luego, en la pestaña Registros.
Haz clic en el ícono Ver en el Explorador de registros a la derecha de la barra de estado. Se abrirá una nueva ventana del Explorador de registros.
Haz clic en una de las entradas de error Traceback
y, luego, en Explain this Log Entry.
Puedes leer la explicación del error.
A continuación, hagamos que Duet AI te ayude a solucionar el error.
Prueba la siguiente instrucción.
Consigna 1: Ayúdame a solucionar este error
Ingresa el mensaje de error en el prompt.
Consigna 2: Prohibido: La principal de IAM autenticada no parece tener autorización para realizar solicitudes a la API. Verifica “API de Cloud SQL Admin” esté habilitada en tu proyecto de GCP y el “cliente de Cloud SQL” se le otorgó el rol a la principal de IAM
y, luego,
Consigna 3: ¿Cómo asigno el rol de cliente de Cloud SQL a una cuenta de servicio de Google con gcloud?
Asigna la función de cliente de Cloud SQL a cloudsqlsa
.
gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/cloudsql.client"
Espera unos minutos y vuelve a intentar acceder a la aplicación.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}') curl http://${EXTERNAL_IP}/packages/1
El resultado es similar a este:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Usaste correctamente Duet AI en Cloud Logging, el Explorador de registros y la función Explicación de registros para solucionar el problema.
8. Conclusión
¡Felicitaciones! Completaste correctamente este codelab.
En este codelab, aprendiste lo siguiente:
- Activa Duet AI en tu proyecto de GCP y configúralo para usarlo en un IDE y la consola de Cloud.
- Usa Duet AI para generar, completar y explicar código.
- Usa Duet AI para explicar y solucionar un problema de una aplicación.
- Funciones de Duet AI como chat con IDE y chat de varios turnos, generación de código intercalado en comparación con el chat, acciones inteligentes como la explicación del código y el reconocimiento de solicitudes, y mucho más.
9. Apéndice
package-service.yaml
swagger: "2.0"
info:
title: Shipping and Package Information API
description: This API provides information about shipping and packages.
version: 1.0.0
host: shipping.googleapis.com
schemes:
- https
produces:
- application/json
paths:
/packages/{product_id}:
get:
summary: Get information about a package
description: This method returns information about a package, including its height, width, depth, weight, and any special handling instructions.
parameters:
- name: product_id
in: path
required: true
type: integer
format: int64
responses:
"200":
description: A successful response
schema:
type: object
properties:
height:
type: integer
format: int64
width:
type: integer
format: int64
depth:
type: integer
format: int64
weight:
type: integer
format: int64
special_handling_instructions:
type: string
"404":
description: The product_id was not found
data_model.py
from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from connect_connector import engine
Base = declarative_base()
class Package(Base):
__tablename__ = 'packages'
id = Column(Integer, primary_key=True)
product_id = Column(Integer, nullable=False)
height = Column(Float, nullable=False)
width = Column(Float, nullable=False)
depth = Column(Float, nullable=False)
weight = Column(Float, nullable=False)
special_handling_instructions = Column(String, nullable=True)
def create_tables():
Base.metadata.create_all(engine)
if __name__ == '__main__':
create_tables()
print('Tables created successfully.')
connect_connector.py
import os
from google.cloud.sql.connector import Connector, IPTypes
import sqlalchemy
# You may need to manually import pg8000 and Base as follows
import pg8000
from sqlalchemy.ext.declarative import declarative_base
def connect_with_connector() -> sqlalchemy.engine.base.Engine:
"""Initializes a connection pool for a Cloud SQL instance of Postgres."""
# Note: Saving credentials in environment variables is convenient, but not
# secure - consider a more secure solution such as
# Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
# keep secrets safe.
instance_connection_name = os.environ[
"INSTANCE_CONNECTION_NAME"
] # e.g. 'project:region:instance'
db_user = os.environ["DB_USER"] # e.g. 'my-database-user'
db_pass = os.environ["DB_PASS"] # e.g. 'my-database-password'
db_name = os.environ["DB_NAME"] # e.g. 'my-database'
ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC
connector = Connector()
def getconn() -> sqlalchemy.engine.base.Engine:
conn: sqlalchemy.engine.base.Engine = connector.connect(
instance_connection_name,
"pg8000",
user=db_user,
password=db_pass,
db=db_name,
ip_type=ip_type,
)
return conn
pool = sqlalchemy.create_engine(
"postgresql+pg8000://",
creator=getconn,
# ...
)
return pool
# Create a connection pool
engine = connect_with_connector()
# Create a sessionmaker class to create new sessions
SessionMaker = sqlalchemy.orm.sessionmaker(bind=engine)
# Create a Base class for ORM
# You may need to manually fix the following
Base = declarative_base()
db_init.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from connect_connector import engine
from data_model import Package
def create_packages():
# Create a session
session = sessionmaker(bind=engine)()
# Create 10 sample packages
for i in range(10):
package = Package(
product_id=i,
height=10.0,
width=10.0,
depth=10.0,
weight=10.0,
special_handling_instructions="No special handling instructions."
)
# Add the package to the session
session.add(package)
# Commit the changes
session.commit()
if __name__ == '__main__':
create_packages()
print('Packages created successfully.')
main.py
from flask import Flask, request, jsonify
from data_model import Package
from connect_connector import SessionMaker
app = Flask(__name__)
session_maker = SessionMaker()
@app.route("/packages/<int:product_id>", methods=["GET"])
def get_package(product_id):
"""Get information about a package."""
session = session_maker
package = session.query(Package).filter(Package.product_id == product_id).first()
if package is None:
return jsonify({"message": "Package not found."}), 404
return jsonify(
{
"height": package.height,
"width": package.width,
"depth": package.depth,
"weight": package.weight,
"special_handling_instructions": package.special_handling_instructions,
}
), 200
if __name__ == "__main__":
app.run(host="0.0.0.0")
test.py
import unittest
from data_model import Package
from connect_connector import SessionMaker
from main import app
class TestPackage(unittest.TestCase):
def setUp(self):
self.session_maker = SessionMaker()
def tearDown(self):
self.session_maker.close()
def test_get_package(self):
"""Test the `get_package()` function."""
package = Package(
product_id=11, # Ensure that the product_id different from the sample data
height=10,
width=10,
depth=10,
weight=10,
special_handling_instructions="Fragile",
)
session = self.session_maker
session.add(package)
session.commit()
response = app.test_client().get("/packages/11")
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.json,
{
"height": 10,
"width": 10,
"depth": 10,
"weight": 10,
"special_handling_instructions": "Fragile",
},
)
if __name__ == "__main__":
unittest.main()
requirements.txt
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Flask==3.0.0
gunicorn==20.1.0
psycopg2-binary==2.9.3
Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY . ./
RUN pip install -r requirements.txt
# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details
CMD ["python", "main.py"]