1. Objetivos
O objetivo deste workshop é oferecer educação prática sobre a Duet AI para usuários e profissionais.
Neste codelab, você vai aprender o seguinte:
- Ative a Duet AI no seu projeto do GCP e configure para uso em um ambiente de desenvolvimento integrado e no Cloud Console.
- Use a Duet AI para geração, conclusão e explicação de código.
- Use a Duet AI para explicar e resolver um problema de aplicativo.
- Recursos da Duet AI, como chat do ambiente de desenvolvimento integrado e conversa multiturno, chat x geração de código inline, ações inteligentes, como explicação de código e confirmação de recitação, entre outros.
Narrativa
Para mostrar como a Duet AI para desenvolvedores é usada de forma autêntica no desenvolvimento diário, as atividades deste workshop acontecem em um contexto narrativo.
Um novo desenvolvedor entra em uma empresa de e-commerce. A tarefa é adicionar um novo serviço ao aplicativo de e-commerce atual, que é composto por vários serviços. O novo serviço fornece mais informações (dimensões, peso etc.) sobre os produtos no catálogo de produtos. Esse serviço vai permitir custos de frete melhores/mais baratos com base nas dimensões e pesos dos produtos.
Como o desenvolvedor é novo na empresa, ele vai usar a Duet AI para geração, explicação e documentação de código.
Depois que o serviço é codificado, um administrador da plataforma usa a Duet AI (chat) para ajudar a criar o artefato (contêiner do Docker) e os recursos necessários para implantar o artefato no GCP (por exemplo, Artifact Registry, permissões do IAM, um repositório de código, infraestrutura de computação, ou seja, GKE ou CloudRun etc.).
Depois que o aplicativo for implantado no GCP, um operador de aplicativo/SRE vai usar a Duet AI (e o Cloud Ops) para ajudar a resolver um erro no novo serviço.
Persona
O workshop abrange a seguinte persona:
- Desenvolvedor de aplicativos: é necessário ter algum conhecimento de programação e desenvolvimento de software.
Esta variação do workshop da Duet AI é apenas para desenvolvedores. Não é necessário ter conhecimento dos recursos de nuvem do GCP. Os scripts para criar os recursos necessários do GCP e executar esse aplicativo podem ser encontrados aqui. Siga as instruções neste guia para implantar os recursos necessários do GCP.
2. Como preparar o ambiente
Ativar a Duet AI
É possível ativar a Duet AI em um projeto do GCP usando a API (gcloud ou ferramentas de IaC, como o Terraform) ou a interface do console do Cloud.
Para ativar a Duet AI em um projeto do Google Cloud, ative a API Cloud AI Companion e conceda aos usuários os papéis de usuário do Cloud AI Companion e de leitor do Service Usage Identity and Access Management (IAM).
Pela gcloud
Ative o Cloud Shell:
Configure seu PROJECT_ID, USER e ative a API IA do Google Cloud 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}
A saída é semelhante a esta:
Updated property [core/project]. Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.
Conceda os papéis de usuário do IA do Google Cloud Companion e leitor do Service Usage do Identity and Access Management (IAM) à conta de USUÁRIO. A API Cloud Companion está por trás dos recursos do IDE e do console que vamos usar. A permissão de leitor de uso do serviço é usada como uma verificação rápida antes de ativar a interface no console. Assim, a interface da Duet AI só aparece em projetos em que a API está ativada.
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
A saída é semelhante a esta:
... - members: - user:<YOUR USER ACCOUNT> role: roles/cloudaicompanion.user ... - members: - user:<YOUR USER ACCOUNT> role: roles/serviceusage.serviceUsageViewer
Pelo console do Cloud
Para ativar a API, acesse a página da API IA do Google Cloud Companion no console do Google Cloud.
No seletor de projetos, escolha um projeto.
Clique em Ativar.
A página é atualizada e mostra o status Ativado. A Duet AI agora está disponível no projeto na nuvem selecionado do Google Cloud para todos os usuários que têm as funções de IAM necessárias.
Para conceder os papéis do IAM necessários para usar a Duet AI, acesse a página IAM.
Na coluna Principal, encontre o USUÁRIO para quem você quer ativar o acesso à Duet AI e clique no ícone de lápis ✏️ Editar principal nessa linha.
No painel Editar acesso, clique em adicionar Adicionar outro papel.
Em "Selecionar um papel", escolha Usuário da IA do Google Cloud Companion.
Clique em Adicionar outro papel e selecione Leitor do Service Usage.
Clique em Salvar.
Configurar o ambiente de desenvolvimento integrado
Os desenvolvedores podem escolher entre uma variedade de IDEs que melhor atendam às necessidades deles. A assistência de código da Duet AI está disponível em vários ambientes de desenvolvimento integrado, como Visual Studio Code, JetBrains (IntelliJ, PyCharm, GoLand, WebStorm e outros), Cloud Workstations e Editor do Cloud Shell.
Neste laboratório, você pode usar as Cloud Workstations ou o editor do Cloud Shell.
Este workshop usa o editor do Cloud Shell.
A configuração do Cloud Workstations pode levar de 20 a 30 minutos.
Para usar imediatamente, use o editor do Cloud Shell.
Clique no ícone de lápis ✏️ na barra de menus superior do Cloud Shell para abrir o editor.
O editor do Cloud Shell tem uma interface e uma experiência do usuário muito semelhantes ao VSCode.

Clique em CTRL (no Windows)/CMD (no Mac) + , (vírgula) para acessar o painel "Configurações".
Na barra de pesquisa, digite "duet ai".
Confira ou ative Cloudcode > Duet AI: Ativar e Cloudcode > Duet AI > Sugestões inline: ativar automaticamente.

Na barra de status na parte de baixo, clique em Cloud Code - Fazer login e siga o fluxo de trabalho de login.
Se você já tiver feito login, a barra de status vai mostrar Cloud Code - Sem projeto.
Clique em "Cloud Code - Sem projeto". Um painel suspenso de ações vai aparecer na parte de cima. Clique em Selecionar um projeto na nuvem do Google Cloud.

Comece a digitar o ID do projeto, e ele vai aparecer na lista.

Selecione seu PROJECT_ID na lista de projetos.
A barra de status na parte de baixo é atualizada para mostrar o ID do projeto. Se não, atualize a guia do editor do Cloud Shell.
Clique no ícone de IA da Duet
na barra de menu à esquerda para abrir a janela de chat da Duet AI. Se você receber uma mensagem dizendo "Selecionar projeto do GCP". Clique e selecione o projeto novamente.
Agora você vê a janela de chat da Duet AI

3. Como configurar a infraestrutura

Para executar o novo serviço de frete no GCP, você precisa dos seguintes recursos do GCP:
- Uma instância do Cloud SQL com um banco de dados.
- Um cluster do GKE para executar o serviço em contêiner.
- Um Artifact Registry para armazenar a imagem Docker.
- Um Cloud Source Repository para o código.
No terminal do Cloud Shell, clone o repositório a seguir e execute os comandos para configurar a infraestrutura no seu projeto do 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. Como desenvolver um serviço Python Flask

O serviço que vamos criar vai consistir nos seguintes arquivos. Não é necessário criar esses arquivos agora. Eles serão criados um de cada vez seguindo as instruções abaixo:
package-service.yaml: uma especificação de API aberta para o serviço de pacotes que tem dados como altura, largura, peso e instruções de manuseio especial.data_model.py: modelo de dados para a especificação da API package-service. Também cria a tabelapackagesno banco de dados product_details.connect_connector.py: conexão do Cloud SQL (define o mecanismo, a sessão e o ORM de base)db_init.py: gera dados de amostra na tabelapackages.main.py: um serviço Python Flask com um endpointGETpara recuperar detalhes do pacote dos dadospackagescom base no product_id.test.py: teste de unidaderequirement.txt: requisitos do PythonDockerfile: para colocar o aplicativo em um contêiner
Se você tiver problemas durante os exercícios, os arquivos finais estarão localizados no APÊNDICE deste codelab para referência.
Na etapa anterior, você criou um repositório do Cloud Source. Copie o repositório. Você vai criar os arquivos do aplicativo na pasta do repositório clonado.
No terminal do Cloud Shell, execute o comando a seguir para clonar o repositório.
cd ~ gcloud source repos clone shipping shipping cd ~/shipping
Abra a barra lateral de chat da Duet AI no menu à esquerda do editor do Cloud Shell. O ícone é parecido com
. Agora você pode usar a Duet AI para receber ajuda com códigos.
package-service.yaml
Sem arquivos abertos, peça à Duet AI para gerar uma especificação de API aberta para o serviço de frete.
Comando 1: gere uma especificação OpenAPI YAML para um serviço que forneça informações de frete e pacote com base em um ID de produto numérico. O serviço precisa incluir informações sobre altura, largura, profundidade, peso e instruções especiais de manuseio dos pacotes.

Há três opções listadas no canto superior direito da janela de código gerado.
Você pode COPY
o código e COLAR em um arquivo.
É possível ADD
o código para o arquivo aberto no momento no editor.
Ou OPEN
o código em um novo arquivo.
Clique em OPEN
o código em um novo arquivo.
Clique em CTRL/CMD + s para salvar o arquivo e armazene-o na pasta do aplicativo com o nome package-service.yaml. Clique em OK.

O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Você também pode testar vários comandos para conferir as respostas da Duet AI.
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
data_model.py
Em seguida, crie o arquivo Python do modelo de dados para o serviço com base na especificação OpenAPI.
Com o arquivo package-service.yaml aberto, insira o seguinte comando.
Comando 1: usando o ORM sqlalchemy do Python, gere um modelo de dados para este serviço de API. Inclua também uma função separada e um ponto de entrada principal que crie as tabelas do banco de dados.

Vamos analisar cada parte gerada. A Duet AI ainda é uma assistente. Embora ela possa ajudar a criar código rapidamente, você ainda precisa revisar e entender o conteúdo gerado.
Primeiro, há uma classe chamada Package do tipoBase que define o modelo de dados para o banco de dados packages, como a seguir:
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))
Em seguida, você precisa de uma função que crie a tabela no banco de dados, como esta:
def create_tables(engine):
Base.metadata.create_all(engine)
Por fim, você precisa de uma função principal que execute a função create_tables para criar a tabela no banco de dados do Cloud SQL, como esta:
if __name__ == '__main__':
from sqlalchemy import create_engine
engine = create_engine('sqlite:///shipping.db')
create_tables(engine)
print('Tables created successfully.')
A função main está criando um mecanismo usando um banco de dados sqlite local. Para usar o Cloud SQL, é necessário mudar isso. Você vai fazer isso um pouco mais tarde.
Usando o OPEN
o código em um novo fluxo de trabalho de arquivo como antes. Salve o código em um arquivo chamado data_model.py (observe o sublinhado no nome, não um traço).
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
connect-connector.py
Crie o conector do Cloud SQL.
Com o arquivo data_model.py aberto, insira os comandos a seguir.
Comando 1: usando a biblioteca cloud-sql-python-connector, gere uma função que inicializa um pool de conexões para uma instância do Cloud SQL para Postgres.

A resposta não usa a biblioteca cloud-sql-python-connector. Você pode refinar os comandos para dar uma ajuda à Duet AI adicionando detalhes à mesma conversa.
Vamos usar outro comando.
Comando 2: precisa usar a biblioteca cloud-sql-python-connector.

Verifique se ele usa a biblioteca cloud-sql-python-connector.
Usando o OPEN
o código em um novo fluxo de trabalho de arquivo como antes. Salve o código em um arquivo chamado connect_conector.py. Talvez seja necessário importar manualmente a biblioteca pg8000. Consulte o arquivo abaixo.
Limpe o histórico de chat da Duet AI e, com o arquivo connect_connector.py aberto, gere o ORM DB engine, sessionmaker e base para ser usado no aplicativo.
Comando 1: crie um mecanismo, uma classe sessionmaker e um ORM de base usando o método connect_with_connector

A resposta pode anexar engine, Session e Base ao arquivo connect_connector.py.
O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Você também pode testar vários comandos para conferir a variação potencial das respostas da Duet AI.
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
Atualizar data_model.py
Você precisa usar o mecanismo criado na etapa anterior (no arquivo connect_connector.py) para criar uma tabela no banco de dados do Cloud SQL.
Limpe o histórico de chat da Duet AI. Abra o arquivo data_model.py. Tente o comando a seguir.
Comando 1: na função principal, importe e use o mecanismo de connect_connector.py

Você vai notar a resposta importando engine de connect_connector (para o Cloud SQL). O create_table usa esse mecanismo (em vez do banco de dados local sqlite padrão).
Atualize o arquivo data_model.py.
O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Você também pode testar vários comandos para conferir as respostas da Duet AI.
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
requirements.txt
Crie um arquivo requirements.txt para o aplicativo.
Abra os arquivos connect_connector.py e data_model.py e insira o seguinte comando.
Comando 1: gere um arquivo de requisitos do pip para esse modelo de dados e serviço
Comando 2: gere um arquivo de requisitos do pip para esse modelo de dados e serviço usando as versões mais recentes

Verifique se os nomes e as versões estão corretos. Por exemplo, na resposta acima, o nome e a versão do google-cloud-sql-connecter estão incorretos. Corrija manualmente as versões e crie um arquivo requirements.txt parecido com este:
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
No terminal de comandos, execute o seguinte:
pip3 install -r requirements.txt
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
Como criar a tabela de pacotes no Cloud SQL
Defina as variáveis de ambiente para o conector do banco de dados do 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
Agora execute data_model.py.
python data_model.py
A saída é semelhante a esta (confira o código para ver o que é esperado):
Tables created successfully.
Conecte-se à instância do Cloud SQL e verifique se o banco de dados foi criado.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Depois de inserir a senha (também evolution), receba as tabelas.
product_details=> \dt
O resultado será assim:
List of relations Schema | Name | Type | Owner --------+----------+-------+----------- public | packages | table | evolution (1 row)
Você também pode verificar o modelo de dados e os detalhes da tabela.
product_details=> \d+ packages
O resultado será assim:
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
Digite \q para sair do Cloud SQL.
db_init.py
Em seguida, vamos adicionar alguns dados de amostra à tabela packages.
Limpe o histórico de chat da Duet AI. Com o arquivo data_model.py aberto, tente os seguintes comandos.
Comando 1: gere uma função que crie 10 linhas de pacotes de amostra e as confirme na tabela de pacotes
Comando 2: usando a sessão de connect_connector, gere uma função que crie 10 linhas de pacotes de amostra e as confirme na tabela de pacotes.

Usando o OPEN
o código em um novo fluxo de trabalho de arquivo como antes. Salve o código em um arquivo chamado db_init.py.
O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Você também pode testar vários comandos para conferir as respostas da Duet AI.
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
Como criar dados de pacotes de amostra
Execute db_init.py na linha de comando.
python db_init.py
O resultado será assim:
Packages created successfully.
Conecte-se à instância do Cloud SQL novamente e verifique se os dados de amostra foram adicionados à tabela "packages".
Conecte-se à instância do Cloud SQL e verifique se o banco de dados foi criado.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Depois de inserir a senha (também evolution), receba todos os dados da tabela de pacotes.
product_details=> SELECT * FROM packages;
O resultado será assim:
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)
Digite \q para sair do Cloud SQL.
main.py
Com os arquivos data_model.py, package-service.yaml e connect_connector.py abertos, crie um main.py para o aplicativo.
Comando 1: usando a biblioteca python flask, crie uma implementação que use endpoints REST HTTP para esse serviço.
Comando 2: usando a biblioteca python flask, crie uma implementação que use endpoints http rest para esse serviço. Importe e use o SessionMaker de connect_conector.py para dados de pacotes.
Comando 3: usando a biblioteca python flask, crie uma implementação que use endpoints http rest para esse serviço. Importe e use o pacote de data_model.py e o SessionMaker de connect_conector.py para dados de pacotes.
Comando 4: usando a biblioteca python flask, crie uma implementação que use endpoints http rest para esse serviço. Importe e use o pacote de data_model.py e o SessionMaker de connect_conector.py para dados de pacotes. Usar o IP do host 0.0.0.0 para app.run

Atualize os requisitos para main.py.
Comando: crie um arquivo de requisitos para main.py

Anexe isso ao arquivo requirements.txt. Use a versão 3.0.0 do Flask.
Usando o OPEN
o código em um novo fluxo de trabalho de arquivo como antes. Salve o código em um arquivo chamado main.py.
O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
5. Como testar e executar o aplicativo
Instale os requisitos.
pip3 install -r requirements.txt
Execute main.py.
python main.py
O resultado será assim:
* 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
Em um segundo terminal, teste o endpoint /packages/<product_id>.
curl localhost:5000/packages/1
O resultado será assim:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Você também pode testar qualquer outro ID de produto nos seus dados de amostra.
Digite CTRL_C para sair do contêiner do Docker em execução no terminal.
Gerar testes de unidade
Com o arquivo main.py aberto, gere testes de unidade.
Comando 1: gere testes de unidade.

Usando o OPEN
o código em um novo fluxo de trabalho de arquivo como antes. Salve o código em um arquivo chamado test.py.
Na função test_get_package, um product_id precisa ser definido. É possível adicionar manualmente.
O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Para redefinir o histórico de conversas da Duet AI, clique no ícone da lixeira
na parte de cima da barra lateral da Duet AI.
Execução de testes de unidade
Execute o teste de unidade.
python test.py
O resultado será assim:
. ---------------------------------------------------------------------- Ran 1 test in 1.061s OK
Feche todos os arquivos no editor do Cloud Shell e limpe o histórico de chat clicando no ícone da lixeira
na barra de status superior.
Dockerfile
Crie um Dockerfile para esse aplicativo.
Abra main.py e tente os comandos a seguir.
Comando 1: gere um Dockerfile para este aplicativo.
Comando 2: gere um Dockerfile para este aplicativo. Copie todos os arquivos para o contêiner.

Você também precisa definir o ENVARS para INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS e DB_NAME. Você pode fazer isso manualmente. O Dockerfile precisa ter esta aparência:
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"]
Usando o OPEN
o código em um novo fluxo de trabalho de arquivo como antes. Salve o código em um arquivo chamado Dockerfile.
O arquivo final está na seção APÊNDICE deste codelab. Se não for, faça as mudanças necessárias manualmente.
Executar o aplicativo localmente
Com o Dockerfile aberto, tente o seguinte comando.
Comando 1: como executar um contêiner localmente usando este Dockerfile?

Siga as instruções.
# Build docker build -t shipping . # And run docker run -p 5000:5000 -it shipping
O resultado será assim:
* 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
Em uma segunda janela de terminal, acesse o contêiner.
curl localhost:5000/packages/1
O resultado será assim:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
O aplicativo conteinerizado está funcionando.
Digite CTRL_C para sair do contêiner do Docker em execução no terminal.
Como criar imagens de contêiner no Artifact Registry
Crie a imagem do contêiner e envie para o 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
O contêiner do aplicativo agora está localizado em us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping, que pode ser implantado no GKE.
6. Como implantar o aplicativo no cluster do GKE
Um cluster do GKE Autopilot foi criado quando você criou os recursos do GCP para este workshop. Conecte-se ao cluster do GKE.
gcloud container clusters get-credentials gke1 \
--region=us-central1
anotar a conta de serviço padrão do Kubernetes com a conta de serviço do Google;
kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com
O resultado será assim:
serviceaccount/default annotated
Prepare e aplique o arquivo 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
O resultado será assim:
deployment.apps/shipping created service/shipping created
Aguarde até que os pods estejam em execução e o serviço tenha um endereço IP de balanceador de carga externo atribuído.
kubectl get pods kubectl get service shipping
O resultado será assim:
# 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 clusters do GKE Autopilot, aguarde alguns instantes até que os recursos estejam prontos.
Acesse o serviço pelo endereço EXTERNAL-IP.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
O resultado será assim:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
7. Crédito extra: como solucionar problemas do aplicativo
Remova o papel do IAM de cliente do Cloud SQL da conta de serviço cloudsqlsa. Isso causa um erro ao se conectar ao banco de dados do Cloud SQL.
gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Reinicie o pod de envio.
kubectl rollout restart deployment shipping
Depois que o pod for reiniciado, tente acessar o serviço shipping novamente.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
O resultado será assim:
... <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 inspecionar os registros, acesse Kubernetes Engine > Cargas de trabalho.

Clique na implantação shipping e depois na guia Registros.

Clique no ícone Ver na Análise de registros
no lado direito da barra de status. Isso abre uma nova janela do Explorador de registros.

Clique em uma das entradas de erro Traceback e em Explicar esta entrada de registro.

Leia a explicação do erro.
Em seguida, vamos pedir ajuda à Duet AI para resolver o erro.
Tente o comando a seguir.
Comando 1: ajude-me a resolver este erro

Insira a mensagem de erro no comando.
Solicitação 2: proibida. O principal autenticado do IAM não parece autorizado a fazer solicitações de API. Verifique se a API Cloud SQL Admin está ativada no seu projeto do GCP e se a função "Cliente do Cloud SQL" foi concedida ao principal do IAM

E então.
Comando 3: como atribuir o papel de cliente do Cloud SQL a uma conta de serviço do Google usando o gcloud?

Atribua a função "Cliente do Cloud SQL" ao cloudsqlsa.
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Aguarde alguns momentos e tente acessar o aplicativo novamente.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
O resultado será assim:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Você usou a Duet AI no Cloud Logging, na Análise de registros e no recurso Explicação de registros para resolver o problema.
8. Conclusão
Parabéns! Você concluiu este codelab.
Neste codelab, você aprendeu a:
- Ative a Duet AI no seu projeto do GCP e configure para uso em um ambiente de desenvolvimento integrado e no Cloud Console.
- Use a Duet AI para geração, conclusão e explicação de código.
- Use a Duet AI para explicar e resolver um problema de aplicativo.
- Recursos da Duet AI, como chat do ambiente de desenvolvimento integrado e conversa multiturno, chat x geração de código inline, ações inteligentes, como explicação de código e confirmação de recitação, entre outros.
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"]