Proxy explícito do PSC do Agent Engine

1. Introdução

A interface do Private Service Connect é um recurso que permite que uma rede de nuvem privada virtual (VPC, na sigla em inglês) do produtor inicie conexões com vários destinos em uma rede VPC do consumidor. As redes de produtor e consumidor podem estar em diferentes projetos e organizações.

Se um anexo de rede aceitar uma conexão de uma interface do Private Service Connect, o Google Cloud alocará à interface um endereço IP de uma sub-rede do consumidor especificada pelo anexo de rede. As redes de consumidores e produtores estão conectadas e podem se comunicar por endereços IP internos.

Uma conexão entre um anexo de rede e uma interface do Private Service Connect é semelhante à conexão entre um endpoint do Private Service Connect e um anexo de serviço, mas há duas diferenças principais:

  • Um anexo de rede permite que uma rede produtora inicie conexões com uma rede consumidora (saída de serviço gerenciada), enquanto um endpoint permite que uma rede consumidora inicie conexões com uma rede produtora (entrada de serviço gerenciada).
  • Uma conexão de interface do Private Service Connect é transitiva. Isso significa que uma rede do produtor pode se comunicar com outras que estão conectadas à rede do consumidor.

Considerações sobre a acessibilidade da interface do PSC da Vertex AI

  • A interface do PSC pode rotear o tráfego para destinos baseados em VPC ou locais no bloco de endereços RFC1918.
  • O direcionamento de interface do PSC a blocos de endereços não rfc-1918 exige um proxy explícito implantado na VPC do consumidor com um endereço rfc-1918. Na implantação da Vertex AI, o proxy precisa ser definido com um FQDN do endpoint de destino.
  • Quando você configura a implantação apenas com uma interface do PSC, ela mantém o acesso padrão à Internet. Esse tráfego de saída sai diretamente da rede de locatário segura e gerenciada pelo Google.

Considerações sobre a VPC-SC da interface PSC da Vertex AI

  • Quando seu projeto faz parte de um perímetro do VPC Service Controls, o acesso padrão à Internet dos tenants gerenciados pelo Google é bloqueado pelo perímetro para evitar a exfiltração de dados.
  • Para permitir que a implantação acesse a Internet pública nesse cenário, configure explicitamente um caminho de saída seguro que roteie o tráfego pela sua VPC.
  • A maneira recomendada de fazer isso é configurar um servidor proxy dentro do perímetro da VPC com um endereço RFC1918 e criar um gateway do Cloud NAT para permitir que a VM proxy acesse a Internet.

Para mais informações, consulte os seguintes recursos:

Implantar um agente | IA generativa na Vertex AI | Google Cloud

Configurar uma interface do Private Service Connect para recursos da Vertex AI | Google Cloud

O que você vai criar

Neste tutorial, você vai criar um Agent Engine abrangente implantado com uma interface do Private Service Connect (PSC) para permitir a conectividade com um site público (https://api.frankfurter.app/) por uma VM de proxy implantada na VPC do consumidor com um endereço RFC1918. A implantação de exemplo é aplicável em um projeto ativado para VPC-SC ou para administradores que exigem saída da Internet pela rede dos clientes em vez da VPC do locatário.

Figura 1.

f42f2db921f6d5af.png

Você vai criar um único psc-network-attachment na VPC do consumidor usando o peering de DNS para resolver a proxy-vm da rede do consumidor no projeto do locatário que hospeda o Agent Engine, resultando nos seguintes casos de uso:

Implante o Agent Engine e configure uma VM de proxy para atuar como um proxy explícito, permitindo que ela alcance um URL público https://api.frankfurter.app

O que você vai aprender

  • Como criar um anexo de rede
  • Como um produtor pode usar um anexo de rede para criar uma interface do PSC
  • Como estabelecer comunicação do produtor para o consumidor usando o peering de DNS
  • Como implantar e usar uma VM de proxy para saída da Internet

O que é necessário

Projeto do Google Cloud

Permissões do IAM

2. Antes de começar

Atualizar o projeto para oferecer suporte ao tutorial

Este tutorial usa $variables para ajudar na implementação da configuração do gcloud no Cloud Shell.

No Cloud Shell, faça o seguinte:

gcloud config list project
gcloud config set project [YOUR-PROJECT-NAME]
projectid=YOUR-PROJECT-NAME
echo $projectid

Ativação da API

No Cloud Shell, faça o seguinte:

gcloud services enable "compute.googleapis.com"
gcloud services enable "aiplatform.googleapis.com"
gcloud services enable "dns.googleapis.com"
gcloud services enable "notebooks.googleapis.com"
gcloud services enable "storage.googleapis.com"
gcloud services enable "iap.googleapis.com"

Verificar se as APIs foram ativadas

gcloud services list --enabled

3. Configuração do consumidor

Criar a VPC do consumidor

Essa VPC reside em um projeto do cliente. Os seguintes recursos serão criados nesta VPC:

  • Sub-rede do consumidor
  • Sub-rede de anexo de rede
  • Cloud Router (necessário para o Cloud NAT)
  • Cloud NAT

No Cloud Shell, faça o seguinte:

gcloud compute networks create consumer-vpc --project=$projectid --subnet-mode=custom

Criar as sub-redes do consumidor

No Cloud Shell, crie a sub-rede para a VM do proxy:

gcloud compute networks subnets create rfc1918-subnet1 --project=$projectid --range=10.10.10.0/28 --network=consumer-vpc --region=us-central1

Criar a sub-rede de anexo de rede do Private Service Connect

No Cloud Shell, crie a sub-rede para a vinculação de rede do PSC:

gcloud compute networks subnets create intf-subnet --project=$projectid --range=192.168.10.0/28 --network=consumer-vpc --region=us-central1

Configuração do Cloud Router e do NAT

Neste tutorial, o Cloud NAT é usado para fornecer acesso à Internet à VM de proxy, que não tem um endereço IP público. O Cloud NAT permite que VMs com apenas endereços IP particulares se conectem à Internet, permitindo que elas executem tarefas como instalar pacotes de software.

No Cloud Shell, crie o Cloud Router.

gcloud compute routers create cloud-router-for-nat --network consumer-vpc --region us-central1

No Cloud Shell, crie o gateway NAT com a geração de registros ativada. Vamos usar o registro em registros para validar o acesso ao IP público da API Frankfurter (https://api.frankfurter.app/).

gcloud compute routers nats create cloud-nat-us-central1 --router=cloud-router-for-nat --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --region us-central1 --enable-logging --log-filter=ALL

4. Ativar o IAP

Para permitir que o IAP se conecte às suas instâncias de VM, crie uma regra de firewall que:

  • Aplica-se a todas as instâncias de VM que você quer acessar usando o IAP.
  • Permite o tráfego de entrada do intervalo de IP 35.235.240.0/20. Esse intervalo contém todos os endereços IP que o IAP usa para o encaminhamento de TCP.

No Cloud Shell, crie a regra de firewall do IAP.

gcloud compute firewall-rules create ssh-iap-consumer \
    --network consumer-vpc \
    --allow tcp:22 \
    --source-ranges=35.235.240.0/20

5. Criar instâncias de VM do consumidor

No Cloud Shell, crie a instância de VM do consumidor, proxy-vm, que vai servir como proxy explícito para o Agent Engine. Vamos usar o tinyproxy como aplicativo para fazer proxy do tráfego HTTP.

gcloud compute instances create proxy-vm \
    --project=$projectid \
    --machine-type=e2-micro \
    --image-family debian-11 \
    --no-address \
    --can-ip-forward \
    --image-project debian-cloud \
    --zone us-central1-a \
    --subnet=rfc1918-subnet1 \
    --shielded-secure-boot \
    --metadata startup-script="#! /bin/bash
      sudo apt-get update
      sudo apt-get install tcpdump
      sudo apt-get install tinyproxy -y
      sudo apt-get install apache2 -y
      sudo service apache2 restart
      echo 'proxy server !!' | tee /var/www/html/index.html
      EOF"

6. Anexo de rede do Private Service Connect

Os anexos de rede são recursos regionais que representam o lado do consumidor de uma interface do Private Service Connect. Você associa uma única sub-rede a um anexo de rede, e o produtor atribui IPs à interface do Private Service Connect a partir dessa sub-rede. A sub-rede precisa estar na mesma região do anexo de rede. Um anexo de rede precisa estar na mesma região do serviço do produtor.

Criar o anexo de rede

No Cloud Shell, crie o anexo de rede.

gcloud compute network-attachments create psc-network-attachment \
    --region=us-central1 \
    --connection-preference=ACCEPT_AUTOMATIC \
    --subnets=intf-subnet

Listar os anexos de rede

No Cloud Shell, liste o anexo de rede.

gcloud compute network-attachments list

Descrever os anexos de rede

No Cloud Shell, descreva o anexo de rede.

gcloud compute network-attachments describe psc-network-attachment --region=us-central1

Anote o nome do anexo de rede do PSC, psc-network-attachment, que será usado pelo produtor ao criar a interface do Private Service Connect.

Para ver o URL de anexo de rede do PSC no console do Cloud, navegue até:

Serviços de rede → Private Service Connect → Anexo de rede → psc-network-attachment

8eec51cb197da218.png

7. Zona de DNS particular

Você vai criar uma zona do Cloud DNS para demo.com e preenchê-la com um registro A que aponta para os endereços IP da proxy-vm. Depois, o peering de DNS será implantado no Agent Engine, o que permitirá o acesso aos registros de DNS do consumidor.

No Cloud Shell, execute o seguinte comando para criar um nome de DNS demo.com.

gcloud dns --project=$projectid managed-zones create private-dns-codelab --description="" --dns-name="demo.com." --visibility="private" --networks="https://compute.googleapis.com/compute/v1/projects/$projectid/global/networks/consumer-vpc"

Obtenha e armazene os endereços IP das instâncias usadas para registros A de DNS.

No Cloud Shell, execute uma descrição nas instâncias de VM.

gcloud compute instances describe proxy-vm --zone=us-central1-a | grep  networkIP:

No Cloud Shell, crie o conjunto de registros para a VM, proxy-vm.demo.com, e atualize o endereço IP com base na saída do seu ambiente.

gcloud dns --project=$projectid record-sets create proxy-vm.demo.com. --zone="private-dns-codelab" --type="A" --ttl="300" --rrdatas="10.10.10.2"

Criar uma regra do Cloud Firewall para permitir o acesso da interface do PSC

Na seção a seguir, crie uma regra de firewall que permita o tráfego originado do acesso ao anexo de rede do PSC à proxy-vm na VPC do consumidor.

No Cloud Shell, crie a regra de firewall de entrada.

gcloud compute firewall-rules create allow-access-to-compute \
    --network=consumer-vpc \
    --action=ALLOW \
    --rules=ALL \
    --direction=INGRESS \
    --priority=1000 \
    --source-ranges="192.168.10.0/28" \
    --destination-ranges="10.10.10.0/28" \
    --enable-logging

8. Crie um notebook do Jupyter

A seção a seguir orienta você na criação de um notebook do Jupyter. Este notebook será usado para implantar o Agent Engine direcionando um proxy explícito para saída da Internet.

Criar uma conta de serviço gerenciada pelo usuário

Na seção a seguir, você vai criar uma conta de serviço que será associada à instância do Vertex AI Workbench usada no tutorial.

No tutorial, a conta de serviço terá as seguintes funções aplicadas:

No Cloud Shell, crie a conta de serviço.

gcloud iam service-accounts create notebook-sa \
    --display-name="notebook-sa"

No Cloud Shell, atualize a conta de serviço com o papel de administrador do Storage.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/storage.admin"

No Cloud Shell, atualize a conta de serviço com o papel de usuário da Vertex AI.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/aiplatform.user"

No Cloud Shell, atualize a conta de serviço com o papel Administrador do Artifact Registry.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/artifactregistry.admin"

No Cloud Shell, permita que a conta de serviço do notebook use a conta de serviço padrão do Compute Engine.

gcloud iam service-accounts add-iam-policy-binding \
    $(gcloud projects describe $(gcloud config get-value project) --format='value(projectNumber)')-compute@developer.gserviceaccount.com \
    --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountUser"

9. Atualizar o proxy explícito

Na seção a seguir, você precisará fazer SSH no proxy explícito e atualizar o arquivo de configuração tinyproxy.conf, seguido de uma redefinição.

No Cloud Shell

gcloud compute ssh --zone us-central1-a "proxy-vm" --tunnel-through-iap --project $projectid

Abra o arquivo de configuração do tinyproxy e atualize usando um editor de sua escolha. Confira um exemplo usando o VIM.

sudo vim /etc/tinyproxy/tinyproxy.conf

# Locate the "Listen" configuration line to restrict listening to only its private IP address of the Proxy-VM, rather than all interfaces. 

Listen 10.10.10.2

# Locate the "Allow" configuration line to allow requests ONLY from the PSC Network Attachment Subnet

Allow 192.168.10.0/24

Save the configs by the following steps:
1. Press the `ESC` key to enter Command Mode.
2. Type `:wq` to save (w) and quit (q).
3. Press `Enter`

Restart the tinyproxy service to apply the changes:
sudo systemctl restart tinyproxy

Validate the tinyproxy service is running:
sudo systemctl status tinyproxy

Perform an exit returning to cloud shell
exit

10. criar uma instância do Vertex AI Workbench

Na seção a seguir, crie uma instância do Vertex AI Workbench que incorpore a conta de serviço criada anteriormente, notebook-sa.

No Cloud Shell, crie a instância private-client.

gcloud workbench instances create workbench-tutorial --vm-image-project=cloud-notebooks-managed --vm-image-family=workbench-instances --machine-type=n1-standard-4 --location=us-central1-a --subnet-region=us-central1 --subnet=rfc1918-subnet1 --disable-public-ip --shielded-secure-boot=true --shielded-integrity-monitoring=true --shielded-vtpm=true --service-account-email=notebook-sa@$projectid.iam.gserviceaccount.com

11. Atualização do agente de serviço da Vertex AI

A Vertex AI age em seu nome para realizar operações como a obtenção de um endereço IP da sub-rede de anexo de rede do PSC usada para criar a interface do PSC. Para isso, a Vertex AI usa um agente de serviço (listado abaixo) que exige a permissão de administrador de rede:

service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com

No Cloud Shell, recupere o número do projeto.

gcloud projects describe $projectid | grep projectNumber

No Cloud Shell, defina o número do projeto.

projectnumber=YOUR-PROJECT-Number

No Cloud Shell, crie uma conta de serviço para o AI Platform. Pule esta etapa se você já tiver uma conta de serviço no projeto.

gcloud beta services identity create --service=aiplatform.googleapis.com --project=$projectnumber

No Cloud Shell, atualize a conta do agente de serviço com a função compute.networkAdmin.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/compute.networkAdmin"

No Cloud Shell, atualize a conta do agente de serviço com a função dns.peer

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/dns.peer"

Atualização da conta de serviço padrão

Conceda à sua conta de serviço padrão acesso à Vertex AI. Pode levar algum tempo para a mudança no acesso ser propagada.

No Cloud Shell, atualize a conta de serviço padrão com a função aiplatform.user

gcloud projects add-iam-policy-binding $projectid \
  --member="serviceAccount:$projectnumber-compute@developer.gserviceaccount.com" \
    --role="roles/aiplatform.user"

12. Tcpdump da VM de proxy

Para validar a conectividade IP do Agent Engine, podemos usar o TCPDUMP. Isso nos permite observar a comunicação originada da sub-rede de anexação de rede do PSC, 192.168.10.0/28, ao invocar a solicitação GET do Agent Engine para o URL público.

No Cloud Shell, conecte-se via SSH à VM de proxy.

gcloud compute ssh --zone us-central1-a "proxy-vm" --tunnel-through-iap --project $projectid

No SO da VM de proxy, execute o tcpdump.

sudo tcpdump -i any net 192.168.10.0/28 -nn

13. Implantar o Agent Engine

Observação:vamos usar o console do GCP e o notebook do JupyterLab para concluir as tarefas desta seção.

Na seção a seguir, você vai criar um notebook que executa as seguintes tarefas:

  • Usa a API Frankfurter (https://api.frankfurter.app/) para receber dados de taxa de câmbio.
  • Faz referência a um proxy explícito (proxy_server) direcionado à VM de proxy na VPC dos consumidores usando o FQDN proxy-vm.demo.com
  • Defina dnsPeeringConfigs "domain": "demo.com."

Execute o job de treinamento na instância do Vertex AI Workbench.

  • No console do Google Cloud, acesse Vertex AI → Workbench.
  • Ao lado do nome da instância do Vertex AI Workbench (workbench-tutorial), clique em "Abrir JupyterLab". A instância do Vertex AI Workbench será aberta no JupyterLab.
  • Selecione Arquivo > Novo > Notebook.
  • Selecione Kernel > Python 3

Instale as bibliotecas necessárias do Python: instale as bibliotecas necessárias para o Agent Engine, incluindo pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys e langchain-google-vertexai.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

!pip install pyyaml
!pip install google-cloud-aiplatform[agent_engines,langchain]==1.96.0
!pip install cloudpickle==3.1.1
!pip install google-cloud-api-keys
!pip install langchain-google-vertexai==2.0.24

Reinicie o kernel do Jupyter Notebook: garanta que as bibliotecas recém-instaladas sejam carregadas corretamente.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

# Restart the notebook kernel after install, so you can run langchain successfully.

import IPython

app = IPython.Application.instance()
app.kernel.do_shutdown(True)

Defina as variáveis de projeto e bucket: defina o ID do projeto do Google Cloud, o número do projeto, o nome do serviço, o diretório do GCS, o endpoint, o nome do bucket e o local.

Atualize os campos a seguir antes de executar a célula

  • PROJECT_ID = "enter-your-projectid"
  • PROJECT_NUMBER = "enter-your-projectnumber"
  • BUCKET= "enter-a-unique-bucket-name"

Observação: vamos usar a variável BUCKET para criar um bucket do Cloud Storage na próxima etapa.

No notebook do JupyterLab, crie uma nova célula, atualize e execute o seguinte.

PROJECT_ID = "enter-your-projectid"  #@param {type:"string"}
PROJECT_NUMBER = "enter-your-projectnumber"  #@param {type:"string"}
SERVICE_NAME = "aiplatform"  #@param ["autopush-aiplatform", "staging-aiplatform", "aiplatform"]
# @markdown  Specify where your agent code should be written in GCS:
GCS_DIR = "reasoning-engine-test"  #@param {type:"string"}
ENDPOINT = "https://us-central1-aiplatform.googleapis.com" # @param ["https://us-central1-aiplatform.googleapis.com", "https://us-central1-autopush-aiplatform.sandbox.googleapis.com", "https://us-central1-staging-aiplatform.sandbox.googleapis.com"]
BUCKET= "enter-a-unique-bucket-name" #@param {type:"string"}
LOCATION="us-central1" #@param {type:"string"}

Crie um bucket do GCS: crie um bucket do Cloud Storage para armazenar o código do agente.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

!gcloud storage buckets create gs://{BUCKET}

Defina o nome do anexo de rede: especifique o nome do anexo de rede do Private Service Connect.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

NETWORK_ATTACHMENT_NAME = 'psc-network-attachment' #@param {type:"string"}

Inicialize as bibliotecas de cliente do Python: configure as bibliotecas de cliente necessárias para os serviços do Google Cloud.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

import json
import pprint

import cloudpickle
from google import auth as google_auth
from google.auth.transport import requests as google_requests
from google.cloud import storage
import yaml


def get_identity_token():
    """Gets ID token for calling Cloud Run."""
    credentials, _ = google_auth.default()
    auth_request = google_requests.Request()
    credentials.refresh(auth_request)
    return credentials.id_token

if not GCS_DIR or "your_ldap" in GCS_DIR:
    raise ValueError("GCS_DIR must be set or you must set your ldap.")

if not PROJECT_ID:
    raise ValueError("PROJECT_ID must be set.")


client = storage.Client(project=PROJECT_ID)
bucket = client.get_bucket(BUCKET)

Configure o agente e as ferramentas: defina a classe StreamingAgent e a função get_exchange_rate para buscar taxas de câmbio usando a API Frankfurter pelo proxy explícito.

No notebook do JupyterLab, crie uma nova célula e execute a configuração abaixo. Observe os seguintes destaques:

  • A função "def get_exchange_rate" vai usar a API Frankfurter (https://api.frankfurter.app/) para receber os dados de taxa de câmbio.
  • proxy_server = "http://proxy-vm.demo.com:8888" O FQDN está associado à VM de proxy implantada na VPC do consumidor. Estamos usando o peering de DNS para resolver o FQDN em uma etapa posterior.
from langchain_google_vertexai import ChatVertexAI
from langchain.agents import AgentExecutor
from langchain.agents.format_scratchpad.tools import format_to_tool_messages
from langchain.agents.output_parsers.tools import ToolsAgentOutputParser
from langchain.tools.base import StructuredTool
from langchain_core import prompts
from re import S
from typing import Callable, Sequence
import google.auth
import vertexai


class StreamingAgent:

    def __init__(
            self,
            model: str,
            tools: Sequence[Callable],
            project_id: str,
        ):
        self.model_name = model
        self.tools = tools
        self.project_id = project_id

    def set_up(self):
        """All unpickle-able logic should go here.

        The .set_up() method should not be called for an object that is being
        prepared for deployment.
        """
        creds, _ = google.auth.default(quota_project_id=self.project_id)
        vertexai.init(project=self.project_id, location="us-central1", credentials=creds)

        prompt = {
            "input": lambda x: x["input"],
            "agent_scratchpad": (
                lambda x: format_to_tool_messages(x["intermediate_steps"])
            ),
        } | prompts.ChatPromptTemplate.from_messages([
            ("user", "{input}"),
            prompts.MessagesPlaceholder(variable_name="agent_scratchpad"),
        ])

        llm = ChatVertexAI(model_name=self.model_name)
        if self.tools:
            llm = llm.bind_tools(tools=self.tools)

        self.agent_executor = AgentExecutor(
            agent=prompt | llm | ToolsAgentOutputParser(),
            tools=[StructuredTool.from_function(tool) for tool in self.tools],
        )

    def query(self, input: str):
        """Query the application.

        Args:
            input: The user prompt.

        Returns:
            The output of querying the application with the given input.
        """
        return self.agent_executor.invoke(input={"input": input})

    def stream_query(self, input: str):
        """Query the application and stream the output.

        Args:
            input: The user prompt.

        Yields:
            Chunks of the response as they become available.
        """
        for chunk in self.agent_executor.stream(input={"input": input}):
            yield chunk

def get_exchange_rate(
    currency_from: str = "USD",
    currency_to: str = "EUR",
    currency_date: str = "latest",
):
    """Retrieves the exchange rate between two currencies on a specified date.

    Uses the Frankfurter API (https://api.frankfurter.app/) to obtain
    exchange rate data.

    Args:
        currency_from: The base currency (3-letter currency code).
            Defaults to "USD" (US Dollar).
        currency_to: The target currency (3-letter currency code).
            Defaults to "EUR" (Euro).
        currency_date: The date for which to retrieve the exchange rate.
            Defaults to "latest" for the most recent exchange rate data.
            Can be specified in YYYY-MM-DD format for historical rates.

    Returns:
        dict: A dictionary containing the exchange rate information.
            Example: {"amount": 1.0, "base": "USD", "date": "2023-11-24",
                "rates": {"EUR": 0.95534}}
    """
    import requests

    proxy_server = "http://proxy-vm.demo.com:8888" # This is the VM's FQDN to reach the proxy vm in the consumers network

    proxies = {
       "http": proxy_server,
       "https": proxy_server,
    }
    response = requests.get(
        f"https://api.frankfurter.app/{currency_date}",
        params={"from": currency_from, "to": currency_to},
        proxies=proxies,
    )
    return response.json()

Faça upload dos arquivos do agente para o Cloud Storage: faça upload do agente serializado e dos requisitos dele para o bucket do GCS designado.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

# Upload files to Cloud Storage.
if not GCS_DIR:
    raise ValueError("GCS_DIR must be set.")

FILE = "streaming_agent.pkl"
blob = bucket.blob(f"{GCS_DIR}/{FILE}")
with blob.open("wb") as f:
    cloudpickle.dump(
        StreamingAgent(
            model="gemini-2.0-flash-001",  # Required.
            tools=[get_exchange_rate],  # Optional.
            project_id=PROJECT_ID
        ), f)


requirements = """
google-cloud-aiplatform[agent_engines,langchain]==1.96.0
cloudpickle==3.1.1
"""

blob = bucket.blob(f"{GCS_DIR}/requirements-streaming.txt")
blob.upload_from_string(requirements)

!gsutil ls gs://{BUCKET}/{GCS_DIR}

Implante o Agent Engine: configure o Agent Engine com a interface do PSC e o peering de DNS para resolver o FQDN da VM proxy na VPC do consumidor.

No notebook do JupyterLab, crie e execute a célula abaixo. Observe os seguintes destaques:

  • O peering de DNS para VPCs consumidoras é configurado usando dnsPeeringConfigs (dnsPeeringConfigs) para o nome de domínio demo.com.
import requests


token = !gcloud auth application-default print-access-token

response = requests.post(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/{LOCATION}/reasoningEngines",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
    data=json.dumps({
        "displayName": "PSC-I Explicit Proxy",
        "description": "test psc-i agent + proxy vm",
        "spec": {
            "packageSpec": {
                "pickleObjectGcsUri": f"gs://{BUCKET}/{GCS_DIR}/streaming_agent.pkl",
                "requirementsGcsUri": f"gs://{BUCKET}/{GCS_DIR}/requirements-streaming.txt",
                "pythonVersion": "3.10"
            },
            "deploymentSpec": {
                "pscInterfaceConfig": {
                    "networkAttachment": NETWORK_ATTACHMENT_NAME,
                    "dnsPeeringConfigs": [
                    {
                      "domain": "demo.com.",
                      "targetProject": PROJECT_ID,
                      "targetNetwork": "consumer-vpc", #Consumer VPC
                    },
                  ],
                }
            }
        },
    })
)

pprint.pprint(json.loads(response.content))
reasoning_engine_id = json.loads(response.content)["name"].split("/")[5]
pprint.pprint(reasoning_engine_id)

Monitore o status da implantação: verifique o status da operação de implantação do Agent Engine.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

operation_id = json.loads(response.content)["name"].split("/")[7]
pprint.pprint(operation_id)

No notebook do JupyterLab, crie uma célula e execute o seguinte:

Observação: essa operação pode levar cerca de cinco minutos para ser concluída. Execute a célula novamente para verificar o progresso. Não avance para a próxima seção até ver uma saída semelhante à captura de tela abaixo.

# You can run this multiple times to check the status of the deployment operation, operation takes approx 5 min.
token = !gcloud auth application-default print-access-token
response = requests.get(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/{LOCATION}/operations/{operation_id}        ",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    }
)
pprint.pprint(json.loads(response.content))

Exemplo de uma execução bem-sucedida:

3f6dcd1074af7651.png

Consultar o agente implantado: envie uma consulta ao Agent Engine implantado para testar a funcionalidade dele.

No notebook do JupyterLab, crie uma célula e execute o seguinte:

response = requests.post(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/{LOCATION}/reasoningEngines/{reasoning_engine_id}:query",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
    data=json.dumps({ "input": {"input": "What is the exchange rate from US dollars to Euro?"} })
)
print(response.text)

Transmitir resultados da consulta: transmita a saída da consulta do Agent Engine.

No notebook do JupyterLab, crie uma célula e execute o seguinte comando, que vai acionar a chamada de API para o URL público usando o proxy explícito na VPC dos consumidores.

token = !gcloud auth application-default print-access-token
print(f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/us-central1/reasoningEngines/{reasoning_engine_id}:streamQuery")

response = requests.post(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/us-central1/reasoningEngines/{reasoning_engine_id}:streamQuery",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
    data=json.dumps({ "input": {"input": "What is the exchange rate from US dollars to Euro?"} })
)
for chunk in response.iter_lines():
    print(chunk.decode('utf-8'))
# pprint.pprint(json.loads(response.content))

Exemplo de uma execução bem-sucedida:

1bd81d12426a348f.png

14. Validação do tcpdump

Confira a saída do tcpdump que detalha a comunicação entre o endereço IP de anexo de rede do PSC usado pelo Agent Engine e a Prox-VM após a postagem da solicitação.

user@proxy-vm:~$ sudo tcpdump -i any net 192.168.10.0/28 -nn
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
22:17:53.983212 ens4  In  IP 192.168.10.2.22261 > 10.10.10.2.8888: Flags [S], seq 3841740961, win 28800, options [mss 1440,sackOK,TS val 4245243253 ecr 0,nop,wscale 7], length 0
22:17:53.983252 ens4  Out IP 10.10.10.2.8888 > 192.168.10.2.22261: Flags [S.], seq 2232973833, ack 3841740962, win 64768, options [mss 1420,sackOK,TS val 2251247643 ecr 4245243253,nop,wscale 7], length 0
22:17:53.985167 ens4  In  IP 192.168.10.2.22261 > 10.10.10.2.8888: Flags [.], ack 1, win 225, options [nop,nop,TS val 4245243256 ecr 2251247643], length 0
22:17:53.986476 ens4  In  IP 192.168.10.2.22261 > 10.10.10.2.8888: Flags [P.], seq 1:45, ack 1, win 16384, options [nop,nop,TS val 4245243256 ecr 2251247643], length 44
22:17:53.986485 ens4  Out IP 10.10.10.2.8888 > 192.168.10.2.22261: Flags [.], ack 45, win 506, options [nop,nop,TS val 2251247646 ecr 4245243256], length 0
22:17:54.043347 ens4  Out IP 10.10.10.2.8888 > 192.168.10.2.22261: Flags [P.], seq 1:71, ack 45, win 506, options [nop,nop,TS val 2251247703 ecr 4245243256], length 70

15. Validação da interface do PSC

Também é possível conferir os IPs de vinculação de rede usados pelo Agent Engine navegando até:

Serviços de rede → Private Service Connect → Anexo de rede → psc-network-attachment

Selecione o projeto do locatário (nome do projeto que termina em -tp).

8a4b5a6e5dfd63d7.png

O campo destacado indica o endereço IP usado pelo Agent Engine no anexo de rede do PSC.

c618359f6eafc0c6.png

16. Validação do Cloud Logging

Saia da sessão TCPDump da proxy-vm e execute um PING para Frankfurter api.frankfurter.app para receber o endereço IP público associado.

ping -c4 api.frankfurter.app 

O exemplo identifica 104.26.1.198 como o IP público de api.frankfurter.app

user@proxy-vm:~$ ping -c4 api.frankfurter.app

PING api.frankfurter.app (104.26.1.198) 56(84) bytes of data.

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=1 ttl=61 time=10.9 ms

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=2 ttl=61 time=10.9 ms

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=3 ttl=61 time=10.9 ms

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=4 ttl=61 time=10.9 ms

Vamos analisar o registro em NAT para verificar se o tráfego de 104.26.1.198 é observado.

Acesse:

Monitoramento → Explorador de registros

Use o seguinte filtro:

resource.type="nat_gateway"

31024dc29c39084.png

Selecione o período e clique em "Executar consulta".

5976857e92d149d3.png

Expanda a entrada de registro que identifica o IP público (de destino) (104.26.1.198) de api.frankfurter.app e o endereço IP de origem e o nome da proxy-vm que valida o uso do proxy explícito para saída da Internet.

14e293a7fea68db4.png

17. Limpar

No notebook do JupyterLab, crie uma célula e execute o seguinte comando, que vai acionar a exclusão da implantação do Agent Engine.

token = !gcloud auth application-default print-access-token

response = requests.delete(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/us-central1/reasoningEngines/{reasoning_engine_id}",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
)
print(response.text)

No Cloud Shell, exclua os componentes do tutorial.

gcloud dns record-sets delete proxy-vm.demo.com --zone=private-dns-codelab  --type=A

gcloud dns managed-zones delete private-dns-codelab

gcloud compute instances delete proxy-vm --zone=us-central1-a --quiet

gcloud compute instances delete workbench-tutorial --zone=us-central1-a --quiet

gcloud compute routers delete cloud-router-for-nat --region=us-central1 --quiet

gcloud compute network-attachments delete psc-network-attachment --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet rfc1918-subnet1 --region=us-central1 --quiet

gcloud compute networks delete consumer-vpc --quiet

18. Parabéns

Parabéns! Você configurou e validou o Agent Engine implantado com a interface do Private Service Connect e a saída da Internet realizada por um proxy explícito.

Você criou a infraestrutura do consumidor e adicionou um anexo de rede que permitiu ao produtor criar uma VM de várias NICs para fazer a ponte entre a comunicação do consumidor e do produtor. Você aprendeu a criar um proxy explícito e um peering de DNS que permitiram a conectividade com a Internet.

A Cosmopup acha que os tutoriais são incríveis!

c911c127bffdee57.jpeg

Qual é a próxima etapa?

Leituras e vídeos complementares

Documentos de referência