1. Objetivos
El objetivo de este taller es brindar a los usuarios y profesionales una capacitación práctica sobre Duet AI.
En este codelab, aprenderás lo siguiente:
- Activa Duet AI en tu proyecto de GCP y configúralo para usarlo en un IDE y en Cloud Console.
- Usa Duet AI para generar, completar y explicar código.
- Usar Duet AI para explicar y solucionar un problema de la aplicación
- Funciones de Duet AI, como el chat del IDE y el chat de varios turnos, la generación de código intercalado y por chat, acciones inteligentes como la explicación de código y el reconocimiento de la recitación, y mucho más
Narración
Para mostrar cómo se usa Duet AI for Developers de forma auténtica 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 es agregar un servicio nuevo a la aplicación de comercio electrónico existente (que se compone de varios servicios). El nuevo servicio proporciona información adicional (dimensiones, peso, etc.) sobre los productos del catálogo de productos. Este servicio permitirá ofrecer costos de envío mejores o más económicos según las dimensiones y el peso de los productos.
Como el desarrollador es nuevo en la empresa, usará Duet AI para la generación, la explicación y la documentación de código.
Una vez que se codifica 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, infraestructura de procesamiento, es decir, GKE o Cloud Run, etcétera).
Una vez que la aplicación se implemente en GCP, un operador de aplicaciones o SRE usará Duet AI (y Cloud Ops) para ayudar a solucionar un error en el nuevo servicio.
Personificación
En el taller, se aborda el siguiente arquetipo de usuario:
- Desarrollador de aplicaciones: Se requieren algunos conocimientos de programación y desarrollo de software.
Esta variación del taller de Duet AI es solo para desarrolladores. No se requieren conocimientos sobre los recursos de la nube de GCP. Los instructivos para compilar los recursos de GCP necesarios para ejecutar esta aplicación se encuentran aquí. Puedes seguir las instrucciones de esta guía para implementar los recursos de GCP necesarios.
2. Prepara el entorno
Cómo activar Duet AI
Puedes activar Duet AI en un proyecto de GCP a través de la API (gcloud o herramientas de IaC como Terraform) o de la IU de Cloud Console.
Para activar Duet AI en un proyecto de Google Cloud, debes habilitar la API de Cloud AI Companion y otorgarles a los usuarios los roles de Usuario de Cloud AI Companion y Visualizador de Service Usage de Identity and Access Management (IAM).
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 similar al 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 la consola que usaremos. El permiso de Service Usage Viewer 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 los 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 similar al 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 actualiza y muestra el estado Habilitado. Duet AI ahora está disponible en el proyecto de Google Cloud seleccionado para todos los usuarios que tienen los roles de IAM necesarios.
Para otorgar los roles de IAM necesarios para usar Duet AI, ve a la página IAM.
En la columna Principal, busca tu USUARIO para el que deseas habilitar el acceso a Duet AI y, luego, haz clic en el ícono de lápiz ✏️ Editar principal en esa fila.
En el panel Editar acceso, haz clic en Agregar otra función.
En Selecciona un rol, selecciona 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 IDE que se adapten mejor a sus necesidades. La asistencia de código de Duet AI está disponible en varios IDE, como Visual Studio Code, IDE de JetBrains (IntelliJ, PyCharm, GoLand, WebStorm y muchos más), Cloud Workstations y el 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 la configuración de las estaciones de trabajo de Cloud puede tardar entre 20 y 30 minutos.
Para usarlo de inmediato, usa el editor de Cloud Shell.
Haz clic en el ícono de lápiz ✏️ en la barra de menú superior de Cloud Shell para abrir el editor de Cloud Shell.
El editor de Cloud Shell tiene una IU y una UX muy similares a las de VS Code.

Presiona CTRL (en Windows)/CMD (en Mac) + , (coma) para ingresar al panel de configuración.
En la barra de búsqueda, escribe "Duet AI".
Asegúrate de habilitar Cloudcode › Duet AI: Enable y Cloudcode › Duet AI › Inline Suggestions: Enable Auto.

En la barra de estado de la parte inferior, haz clic en Cloud Code - Acceder y sigue el flujo de trabajo de acceso.
Si ya accediste, la barra de estado mostrará Cloud Code - No project.
Haz clic en Cloud Code - No project y 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 y este debería aparecer en la lista.

Selecciona tu PROJECT_ID en la lista de proyectos.
La barra de estado inferior se actualiza para mostrar el ID de tu proyecto. Si no es así, es posible que debas 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 Select GCP Project. Haz clic en el proyecto y vuelve a seleccionarlo.
Ahora verás la ventana de chat de Duet AI

3. Configurar la infraestructura

Para ejecutar el nuevo servicio de envío en GCP, necesitas los siguientes recursos de GCP:
- Una instancia de Cloud SQL, con una base de datos.
- Un clúster de GKE para ejecutar el servicio en contenedor
- Un registro de Artifact Registry para almacenar la imagen de Docker
- Un repositorio de Cloud Source para el código
En la terminal de Cloud Shell, clona el siguiente repo y ejecuta los siguientes comandos para configurar la infraestructura en 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. Cómo desarrollar un servicio de Flask en Python

El servicio que crearemos constará, en última instancia, de los siguientes archivos. No es necesario que crees estos archivos ahora. Los crearás de a uno siguiendo las instrucciones que se indican a continuación:
package-service.yaml: Es una especificación de API abierta para el servicio de paquetes que tiene datos como la altura, el ancho, el peso y las instrucciones especiales de manipulación.data_model.py: Es el modelo de datos para la especificación de la API de package-service. También crea la tablapackagesen la base de datos de product_details.connect_connector.py: Conexión de CloudSQL (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 extremoGETpara recuperar detalles del paquete de los datos depackagessegún el product_id.test.py: Prueba de unidadesrequirement.txt: Requisitos de PythonDockerfile: Para organizar esta aplicación en contenedores
Si tienes algún problema durante los ejercicios, todos los archivos finales se encuentran en el APÉNDICE de este codelab para que los consultes.
En el paso anterior, creaste un repositorio de Cloud Source Repositories. 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 se ve así:
. 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 OpenAPI para el servicio de envío.
Instrucción 1: Genera una especificación de OpenAPI en formato YAML para un servicio que proporcione información de envío y paquetes a partir de 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 instrucciones especiales de manipulación.

Hay tres opciones en la parte superior derecha de la ventana de código generado.
Puedes COPY
el código y PEGARLO en un archivo.
Puedes ADD
el código al archivo que está abierto en el editor.
También puedes OPEN
el código en un archivo nuevo.
Haz clic en OPEN
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 de archivo package-service.yaml. Haz clic en Aceptar.

El archivo final se encuentra en la sección APÉNDICE de este codelab. Si no es así, realiza los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver las respuestas de Duet AI.
Para restablecer el historial del chat de Duet AI, haz 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 basado en la especificación de OpenAPI.
Con el archivo package-service.yaml abierto, ingresa la siguiente instrucción.
Instrucción 1: Con el ORM de SQLAlchemy de Python, genera un modelo de datos para este servicio de API. También incluye una función separada y un punto de entrada principal que crea las tablas de la base de datos.

Veamos cada parte que se generó. Duet AI sigue siendo un asistente y, si bien puede ayudarte a crear código rápidamente, debes revisar el contenido generado y comprenderlo a medida que avanzas.
Primero, hay una clase llamada Package de tipoBase 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 crea un motor con una base de datos sqlite local. Para usar CloudSQL, deberás cambiarlo. Lo harás un poco más adelante.
Usa el flujo de trabajo OPEN
el código en un 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 un guion).
Para restablecer el historial del chat de Duet AI, haz 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 las siguientes instrucciones.
Instrucción 1: Con la biblioteca cloud-sql-python-connector, genera 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 agregar detalles a la misma conversación para definir mejor las instrucciones y ayudar a Duet.
Usemos otra instrucción.
Instrucción 2: Debe usar la biblioteca cloud-sql-python-connector.

Asegúrate de que use la biblioteca cloud-sql-python-connector.
Usa el flujo de trabajo OPEN
el código en un 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 a continuación.
Borra el historial de chat de Duet AI y, con el archivo connect_connector.py abierto, genera los ORM DB engine, sessionmaker y base para usarlos en la aplicación.
Instrucción 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. Si no es así, realiza los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver la posible variación de las respuestas de Duet AI.
Para restablecer el historial del chat de Duet AI, haz clic en el ícono de papelera
en la parte superior de la barra lateral de Duet AI.
Actualización de 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 CloudSQL.
Borra el historial del chat de Duet AI. Abre el archivo data_model.py. Prueba la siguiente instrucción.
Instrucción 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. Si no es así, realiza los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver las diferentes respuestas de Duet AI.
Para restablecer el historial del chat de Duet AI, haz 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, y, luego, ingresa la siguiente instrucción.
Instrucción 1: Genera un archivo de requisitos de pip para este modelo de datos y servicio
Instrucción 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 que se vea de la siguiente manera:
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
Para restablecer el historial del chat de Duet AI, haz 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 la base 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 (consulta el código para ver qué se espera realmente):
Tables created successfully.
Conéctate a la instancia de Cloud SQL y verifica que se haya creado la base de datos.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Después de ingresar la contraseña (también 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 consultar los detalles del modelo de datos y 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 del chat de Duet AI. Con el archivo data_model.py abierto, prueba las siguientes instrucciones.
Instrucción 1: Genera una función que cree 10 filas de paquetes de muestra y las confirme en la tabla de paquetes
Instrucción 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 el flujo de trabajo OPEN
el código en un 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. Si no es así, realiza los cambios correspondientes de forma manual.
También puedes probar varias instrucciones para ver las diferentes respuestas de Duet AI.
Para restablecer el historial del chat de Duet AI, haz 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 se haya creado la base de datos.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Después de ingresar la contraseña (también 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.
Instrucción 1: Con la biblioteca de Flask de Python, crea una implementación que use extremos de REST HTTP para este servicio
Instrucción 2: Con la biblioteca Flask de Python, crea una implementación que use extremos REST HTTP para este servicio. Importa y usa SessionMaker desde connect_conector.py para los datos de paquetes.
Instrucción 3: Con la biblioteca Flask de Python, crea una implementación que use extremos REST HTTP para este servicio. Importa y usa Package de data_model.py y SessionMaker de connect_conector.py para los datos de paquetes.
Instrucción 4: Con la biblioteca Flask de Python, crea una implementación que use extremos de REST HTTP para este servicio. Importa y usa Package desde data_model.py y SessionMaker desde connect_conector.py para los datos de paquetes. Usa la IP del host 0.0.0.0 para app.run

Actualiza los requisitos de main.py.
Instrucción: 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 el flujo de trabajo OPEN
el código en un 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. Si no es así, realiza los cambios correspondientes de forma manual.
Para restablecer el historial del chat de Duet AI, haz 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 de producto en tus datos de muestra.
Ingresa CTRL_C para salir del contenedor de Docker en ejecución en la terminal.
Genera pruebas de unidades
Con el archivo main.py abierto, genera pruebas de unidades.
Instrucción 1: Genera pruebas de unidades.

Usa el flujo de trabajo OPEN
el código en un 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. Si no es así, realiza los cambios correspondientes de forma manual.
Para restablecer el historial del chat de Duet AI, haz 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
en la barra de estado superior.
Dockerfile
Crea un objeto Dockerfile para esta aplicación.
Abre main.py y prueba las siguientes instrucciones.
Instrucción 1: Genera un Dockerfile para esta aplicación.
Instrucción 2: Genera un Dockerfile para esta aplicación. Copia todos los archivos en el contenedor.

También debes establecer el 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 el flujo de trabajo OPEN
el código en un 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. Si no es así, realiza los cambios correspondientes de forma manual.
Ejecuta la aplicación de forma local
Con Dockerfile abierto, prueba la siguiente instrucción.
Instrucción 1: ¿Cómo ejecuto un contenedor de forma local 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 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 en ejecución en la terminal.
Compila la imagen de contenedor en Artifact Registry
Compila la imagen del 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
Anota 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 de 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
En el caso de los clústeres de GKE Autopilot, espera unos momentos 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: Solución de problemas de la aplicación
Quita el rol de IAM de cliente de Cloud SQL de la cuenta de servicio cloudsqlsa. Esto provoca un error al conectarse 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 al servicio de shipping nuevamente.
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, navega 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 de Ver en el Explorador de registros
que se encuentra en el lado derecho 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 Explica esta entrada de registro.

Puedes leer la explicación del error.
A continuación, pídele a Duet AI que te ayude a solucionar el error.
Prueba la siguiente instrucción.
Instrucción 1: Ayúdame a solucionar este error

Ingresa el mensaje de error en la instrucción.
Mensaje 2: Prohibido: La principal de IAM autenticada no parece estar autorizada para realizar la solicitud a la API. Verifica que la API de Cloud SQL Admin esté habilitada en tu proyecto de GCP y que se haya otorgado el rol de "Cliente de Cloud SQL" a la principal de IAM.

Y luego.
Instrucción 3: ¿Cómo asigno el rol de cliente de Cloud SQL a una cuenta de servicio de Google con gcloud?

Asigna el rol 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 instantes 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 Explicador de registros para solucionar el problema.
8. Conclusión
¡Felicitaciones! Completaste este codelab correctamente.
En este codelab, aprendiste lo siguiente:
- Activa Duet AI en tu proyecto de GCP y configúralo para usarlo en un IDE y en Cloud Console.
- Usa Duet AI para generar, completar y explicar código.
- Usar Duet AI para explicar y solucionar un problema de la aplicación
- Funciones de Duet AI, como el chat del IDE y el chat de varios turnos, la generación de código intercalado y por chat, acciones inteligentes como la explicación de código y el reconocimiento de la recitación, 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"]