1. Objetivos
O objetivo deste workshop é oferecer treinamento prático sobre o Gemini para usuários e profissionais.
Neste codelab, você vai aprender o seguinte:
- Ative a Duet AI no seu projeto do GCP e configure-a para uso em um ambiente de desenvolvimento integrado e no console do Cloud.
- Use a Duet AI para geração, preenchimento e explicação de código.
- Use a Duet AI para explicar e resolver um problema de aplicativo.
- Recursos da Duet AI, como chat no ambiente de desenvolvimento integrado e chat com várias interações, chat vs. geração de código inline, ações inteligentes como explicação e confirmação de recitação e muito mais.
Narrativa
Para mostrar como a Duet AI para desenvolvedores é usada de maneira autêntica no desenvolvimento diário, as atividades deste workshop ocorrem em um contexto narrativo.
Um novo desenvolvedor entra em uma empresa de e-commerce. Ele tem a tarefa de adicionar um novo serviço (composto por vários serviços) ao aplicativo de e-commerce. O novo serviço fornece informações adicionais (dimensões, peso etc.) sobre os produtos do catálogo. Esse serviço permitirá custos de frete melhores/mais baratos com base nas dimensões e nos pesos do produto.
Como o desenvolvedor é novo na empresa, ele vai usar a Duet AI para geração de código, explicação e documentação.
Depois que o serviço for codificado, um administrador da plataforma vai usar 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, repositório de código, infraestrutura de computação, como GKE ou CloudRun etc.).
Depois que o aplicativo for implantado no GCP, um operador/SRE do aplicativo (SRE, na sigla em inglês) usará a Duet AI e as operações do Cloud para ajudar a solucionar um erro no novo serviço.
Perfil
O workshop aborda 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 sobre como criar os recursos necessários do GCP para executar esse aplicativo podem ser encontrados aqui. Siga as instruções deste guia para implantar os recursos necessários do GCP.
2. Como preparar o ambiente
Como ativar a Duet AI
É possível ativar a Duet AI em um projeto do GCP usando a API (ferramentas gcloud ou IaC, como 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 do Service Usage Viewer Identity and Access Management (IAM).
Pela gcloud
Ative o Cloud Shell:
Configure seu PROJECT_ID
, USER
e ative a API 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}
A saída será assim:
Updated property [core/project]. Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.
Conceda os papéis de usuário do Cloud AI Companion e de visualizador do Service Usage e do Identity and Access Management (IAM) à conta USER. A API Cloud Companion fica por trás dos recursos do console e do ambiente de desenvolvimento integrado 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 (para que a Duet UI só apareça 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 será assim:
... - 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 Cloud AI 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 já está disponível no projeto selecionado do Google Cloud para todos os usuários com os papéis do IAM necessários.
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 com acesso à Duet AI que você quer ativar e clique no ícone de lápis ✏️ Editar principal nessa linha.
No painel de acesso Editar, clique em Adicionar outro papel.
Em "Selecionar um papel", escolha Usuário do Cloud AI Companion.
Clique em Adicionar outro papel e selecione Leitor do Service Usage.
Clique em Salvar.
Como configurar o ambiente de desenvolvimento integrado
Os desenvolvedores podem escolher entre uma variedade de ambientes de desenvolvimento integrado que melhor atendem à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, ambientes de desenvolvimento integrado JetBrains (IntelliJ, PyCharm, GoLand, WebStorm e muito mais), Cloud Workstations e Editor do Cloud Shell.
Neste laboratório, é possível usar o Cloud Workstations ou o Cloud Shell Editor.
Este workshop usa o Cloud Shell Editor.
A configuração do Cloud Workstations pode levar de 20 a 30 minutos.
Para usar imediatamente, acesse o Editor do Cloud Shell.
Para abrir o editor do Cloud Shell, clique no ícone de lápis ✏️ na barra de menus da parte de cima.
O editor do Cloud Shell tem uma interface e UX muito semelhantes ao VSCode.
Clique em CTRL (no Windows)/CMD (no Mac) + , (vírgula) para entrar no painel "Configurações".
Na barra de pesquisa, digite "duet ai".
Verifique ou ative Cloudcode › Duet AI: ativar e Cloudcode › Duet AI › Sugestões inline: ativar automaticamente
Na barra de status da 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 mostrará Cloud Code - No project.
Clique em "Cloud Code - No project" e um painel suspenso de ações vai aparecer na parte de cima. Clique em Selecionar um projeto do Google Cloud.
Comece a digitar o ID do PROJETO e seu projeto aparecerá na lista.
Selecione seu PROJECT_ID na lista de projetos.
A barra de status inferior será atualizada para mostrar o ID do projeto. Se isso não acontecer, talvez seja necessário atualizar a guia do editor do Cloud Shell.
Clique no ícone da Duet AI na barra de menus à esquerda para abrir a janela de chat da Duet AI. Se você receber a mensagem "Selecionar projeto do GCP". Clique e selecione o projeto novamente.
A janela de chat da Duet AI vai aparecer.
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 conteinerizado.
- 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 abaixo 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 criaremos terá os seguintes arquivos. Você não precisa criar esses arquivos agora. Faça isso um de cada vez seguindo as instruções abaixo:
package-service.yaml
: uma especificação OpenAPI para o serviço de pacote que tem dados como altura, largura, peso e instruções especiais de manuseio.data_model.py
: modelo de dados para a especificação da API package-service. Também cria a tabelapackages
no banco de dados product_details.connect_connector.py
: conexão do CloudSQL (define o mecanismo, a sessão e o ORM básico).db_init.py
: gera dados de amostra na tabelapackages
.main.py
: um serviço Python Flask com um endpointGET
para recuperar detalhes do pacote dos dados dopackages
com base no product_id.test.py
: teste de unidaderequirement.txt
: requisitos do PythonDockerfile
: para conteinerizar o aplicativo.
Se você tiver algum problema durante os exercícios, os arquivos finais estão todos no APÊNDICE deste codelab para referência.
Na etapa anterior, você criou um Cloud Source Repository. 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 é possível usar a Duet AI para receber assistência com código.
package-service.yaml
Sem arquivos abertos, peça para a Duet AI gerar uma especificação OpenAPI para o serviço de frete.
Instrução 1: gere uma especificação OpenAPI yaml para um serviço que forneça informações de envio e pacote de acordo com um ID de produto numérico. O serviço precisa incluir informações sobre a 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.
Você pode ADD
(em inglês) o código para o arquivo aberto no Editor.
Ou você pode OPEN
() o código em um novo arquivo.
Clique em OPEN
no código em um novo arquivo.
Clique em CTRL/CMD + s
para salvar o arquivo e armazená-lo na pasta do aplicativo com o nome package-service.yaml
. Clique em OK.
O arquivo final está na seção APÊNDICE deste codelab. Caso contrário, faça as alterações apropriadas manualmente.
Também é possível testar vários comandos para conferir as respostas da Duet AI.
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
data_model.py
Em seguida, você cria o arquivo Python do modelo de dados para o serviço com base na especificação OpenAPI.
Com o arquivo package-service.yaml
aberto, digite o seguinte comando.
Instrução 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 é um assistente e, embora possa ajudar a criar códigos rapidamente, você ainda precisa revisar e entender o conteúdo gerado à medida que avança.
Primeiro, há uma Class chamada Package
do tipo Base
que define o modelo de dados para o banco de dados packages
desta forma:
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 CloudSQL, desta forma:
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, você precisará alterá-lo. Você fará isso um pouco mais tarde.
Use OPEN
para ver 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, e não um traço).
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
connect-connector.py
Crie o conector do CloudSQL.
Com o arquivo data_model.py
aberto, insira os comandos a seguir.
Instrução 1: use a biblioteca cloud-sql-python-connector, gere uma função que inicialize um pool de conexões para uma instância do Cloud SQL do Postgres.
Observe que a resposta não usa a biblioteca cloud-sql-python-connector
. Você pode refinar os comandos e dar um toque na Duet AI adicionando detalhes na mesma conversa.
Vamos usar outro comando.
Prompt 2: é necessário usar a biblioteca cloud-sql-python-connector.
Verifique se ele usa a biblioteca cloud-sql-python-connector
.
Use OPEN
para ver 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 usar no aplicativo.
Instrução 1: criar um mecanismo, uma classe sessionmaker e um ORM básico 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. Caso contrário, faça as alterações apropriadas manualmente.
Também é possível testar vários comandos para conferir a possível variação das respostas da Duet AI.
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
Como 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 CloudSQL.
Limpar o histórico de chat da Duet AI. Abra o arquivo data_model.py
. Tente o seguinte comando.
Instrução 1: na função principal, importar e usar o mecanismo de connect_connector.py
Você verá a resposta importando engine
de connect_connector
(para 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. Caso contrário, faça as alterações apropriadas manualmente.
Também é possível testar vários comandos para conferir as respostas da Duet AI.
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
requirements.txt
Crie um arquivo requirements.txt
para o aplicativo.
Abra connect_connector.py
e o arquivo data_model.py
e digite o seguinte comando.
Instrução 1: gerar um arquivo de requisitos de pip para este modelo de dados e serviço
Instrução 2: gerar um arquivo de requisitos de 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 da google-cloud-sql-connecter
estão incorretos. Corrija manualmente as versões e crie um arquivo requirements.txt
como este:
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
No terminal de comando, execute o seguinte:
pip3 install -r requirements.txt
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
Como criar a tabela de pacotes no CloudSQL
Defina as variáveis de ambiente para o conector de banco de dados do CloudSQL.
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 será semelhante a esta (verifique o código para saber o que é realmente 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), acesse 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 CloudSQL.
db_init.py
Em seguida, vamos adicionar alguns dados de amostra à tabela packages
.
Limpar o histórico de chat da Duet AI. Com o arquivo data_model.py
aberto, tente os comandos a seguir.
Instrução 1: gerar uma função que cria 10 linhas de pacotes de amostra e as envia para a tabela de pacotes
Instrução 2: usando a sessão de connect_connector, gera uma função que cria 10 linhas de pacotes de amostra e as confirma na tabela de pacotes
Use OPEN
para ver 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. Caso contrário, faça as alterações apropriadas manualmente.
Também é possível testar vários comandos para conferir as respostas da Duet AI.
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
Como criar dados de pacotes de amostra
Execute o 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 de pacotes.
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), acesse 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 CloudSQL.
main.py
Com os arquivos data_model.py
, package-service.yaml
e connect_connector.py
abertos, crie um main.py
para o aplicativo.
Prompt 1: Usar a biblioteca python flask: criar uma implementação que use endpoints http REST para este serviço
Prompt 2: Usar a biblioteca python flask – criar uma implementação que use endpoints http REST para esse serviço. importar e usar o SessionMaker de connect_conector.py para dados de pacotes.
Prompt 3: Usar a biblioteca python flask – criar uma implementação que use endpoints http REST para esse serviço. importar e usar o pacote do data_model.py e o SessionMaker de connect_conector.py para dados de pacotes.
Prompt 4: Usar a biblioteca python flask – criar uma implementação que use endpoints http REST para esse serviço. importar e usar o pacote do 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: criar um arquivo de requisitos para main.py
Anexe isso ao arquivo requirements.txt
. Use o Flask versão 3.0.0.
Use OPEN
para ver 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. Caso contrário, faça as alterações apropriadas manualmente.
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
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 do produto nos seus dados de amostra.
Digite CTRL_C
para sair do contêiner do Docker em execução no terminal.
Como gerar testes de unidade
Com o arquivo main.py
aberto, gere testes de unidade.
Instrução 1: gerar testes de unidade.
Use OPEN
para ver 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
, é preciso definir um product_id
. É possível adicioná-lo manualmente.
O arquivo final está na seção APÊNDICE deste codelab. Caso contrário, faça as alterações apropriadas manualmente.
Para redefinir o histórico de chat da Duet AI, clique no ícone de lixeira na parte de cima da barra lateral.
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 de lixeira na barra de status superior.
Dockerfile
Crie um Dockerfile
para esse aplicativo.
Abra main.py
e tente as seguintes instruções.
Instrução 1: gerar um Dockerfile para este aplicativo.
Instrução 2: gerar um Dockerfile para este aplicativo. Copie todos os arquivos para o contêiner.
Também é necessário definir ENVARS
para INSTANCE_CONNECTION_NAME
, DB_USER
, DB_PASS
e DB_NAME
. Você pode fazer isso manualmente. Seu Dockerfile deve ficar assim:
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"]
Use OPEN
para ver 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. Caso contrário, faça as alterações apropriadas manualmente.
Como executar o aplicativo localmente
Com o Dockerfile
aberto, tente o comando a seguir.
Prompt 1: Como executar localmente um contêiner 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 janela do segundo 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.
Criando imagem do contêiner no Artifact Registry
Crie a imagem do contêiner e envie-a 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. Implantando 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
No caso de 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: solução de problemas da inscrição
Remova o papel do IAM de cliente do CloudSQL da conta de serviço cloudsqlsa
. Isso causa um erro ao se conectar ao banco de dados CloudSQL.
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 na guia Registros.
Clique no ícone Ver na Análise de registros no lado direito da barra de status. Uma nova janela da Análise de registros será aberta.
Clique em uma das entradas de erro Traceback
e depois em Explicar esta entrada de registro.
Leia a explicação do erro.
A seguir, vamos usar a Duet AI para ajudar a resolver o erro.
Tente o seguinte comando.
Instrução 1: Ajude-me a resolver este erro
Digite a mensagem de erro no prompt.
Instrução 2: Proibido: o principal do IAM autenticado não parece estar autorizado a fazer solicitações de API. Verifique a "API Cloud SQL Admin" ativado no projeto do GCP e no "Cliente do Cloud SQL" papel foi concedido ao principal do IAM
E então.
Instrução 3: como atribuir o papel de cliente do Cloud SQL a uma conta de serviço do Google usando a gcloud?
Atribua o papel de 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 instantes 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 o seguinte:
- Ative a Duet AI no seu projeto do GCP e configure-a para uso em um ambiente de desenvolvimento integrado e no console do Cloud.
- Use a Duet AI para geração, preenchimento e explicação de código.
- Use a Duet AI para explicar e resolver um problema de aplicativo.
- Recursos da Duet AI, como chat no ambiente de desenvolvimento integrado e chat com várias interações, chat vs. geração de código inline, ações inteligentes como explicação e confirmação de recitação e muito mais.
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"]