Proxy esplicito PSC di Agent Engine

1. Introduzione

Un'interfaccia Private Service Connect è una risorsa che consente a una rete Virtual Private Cloud (VPC) producer di avviare connessioni a varie destinazioni in una rete VPC consumer. Le reti di produttori e consumatori possono trovarsi in progetti e organizzazioni diversi.

Se un collegamento di rete accetta una connessione da un'interfaccia Private Service Connect, Google Cloud assegna all'interfaccia un indirizzo IP da una subnet consumer specificata dal collegamento di rete. Le reti del consumatore e del produttore sono connesse e possono comunicare utilizzando indirizzi IP interni.

Una connessione tra un collegamento di rete e un'interfaccia Private Service Connect è simile alla connessione tra un endpoint Private Service Connect e un collegamento al servizio, ma presenta due differenze fondamentali:

  • Un collegamento di rete consente a una rete producer di avviare connessioni a una rete consumer (uscita del servizio gestito), mentre un endpoint consente a una rete consumer di avviare connessioni a una rete producer (ingresso del servizio gestito).
  • Una connessione di interfaccia Private Service Connect è transitiva. Ciò significa che una rete producer può comunicare con altre reti connesse alla rete consumer.

Considerazioni sull'accessibilità dell'interfaccia PSC di Vertex AI

  • L'interfaccia PSC è in grado di instradare il traffico verso destinazioni VPC o on-premise all'interno del blocco di indirizzi RFC1918.
  • Il targeting dell'interfaccia PSC di blocchi di indirizzi non RFC-1918 richiede un proxy esplicito di cui è stato eseguito il deployment nel VPC del consumer con un indirizzo RFC-1918. All'interno del deployment di Vertex AI, il proxy deve essere definito insieme a un FQDN dell'endpoint di destinazione.
  • Quando configuri il deployment solo con un'interfaccia PSC, questa mantiene l'accesso a internet predefinito. Questo traffico in uscita esce direttamente dalla rete tenant sicura e gestita da Google.

Considerazioni su Vertex AI PSC-Interface VPC-SC

  • Quando il tuo progetto fa parte di un perimetro di Controlli di servizio VPC, l'accesso a internet predefinito dei tenant gestiti da Google viene bloccato dal perimetro per impedire l'esfiltrazione di dati.
  • Per consentire l'accesso al deployment a internet pubblico in questo scenario, devi configurare esplicitamente un percorso di uscita sicuro che indirizzi il traffico tramite il VPC.
  • Il modo consigliato per farlo è configurare un server proxy all'interno del perimetro VPC con un indirizzo RFC1918 e creare un gateway Cloud NAT per consentire alla VM proxy di accedere a internet.

Per ulteriori informazioni, consulta le seguenti risorse:

Esegui il deployment di un agente | AI generativa su Vertex AI | Google Cloud

Configura un'interfaccia Private Service Connect per le risorse Vertex AI | Google Cloud

Cosa creerai

In questo tutorial, creerai un Agent Engine completo di cui è stato eseguito il deployment con l'interfaccia Private Service Connect (PSC) per consentire la connettività a un sito pubblico (https://api.frankfurter.app/) tramite una VM proxy di cui è stato eseguito il deployment nel VPC del consumer con un indirizzo RFC1918. L'esempio di deployment è applicabile in un progetto abilitato per VPC-SC o per gli amministratori che richiedono l'uscita da internet tramite la rete dei clienti anziché il VPC tenant.

Figura 1

f42f2db921f6d5af.png

Creerai un singolo psc-network-attachment nel VPC consumer sfruttando il peering DNS per risolvere la VM proxy della rete consumer nel progetto tenant che ospita Agent Engine, il che comporta i seguenti casi d'uso:

Esegui il deployment di Agent Engine e configura una VM proxy in modo che funga da proxy esplicito, consentendole di raggiungere un URL pubblico https://api.frankfurter.app

Cosa imparerai a fare

  • Come creare un collegamento di rete
  • Come un producer può utilizzare un collegamento di rete per creare un'interfaccia PSC
  • Come stabilire la comunicazione dal producer al consumer utilizzando il peering DNS
  • Come eseguire il deployment e utilizzare una VM proxy per l'uscita da internet

Che cosa ti serve

Progetto Google Cloud

Autorizzazioni IAM

2. Prima di iniziare

Aggiornare il progetto per supportare il tutorial

Questo tutorial utilizza le variabili $per facilitare l'implementazione della configurazione di gcloud in Cloud Shell.

In Cloud Shell, esegui le seguenti operazioni:

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

Abilitazione delle API

In Cloud Shell, esegui le seguenti operazioni:

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"

Verifica che le API siano state abilitate correttamente

gcloud services list --enabled

3. Configurazione consumatore

Crea il VPC consumer

Questo VPC si trova in un progetto cliente. In questo VPC verranno create le seguenti risorse

  • Subnet consumer
  • Subnet del collegamento di rete
  • Router Cloud (obbligatorio per Cloud NAT)
  • Cloud NAT

In Cloud Shell, esegui le seguenti operazioni:

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

Crea le subnet consumer

In Cloud Shell, crea la subnet per la VM proxy:

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

Crea la subnet del collegamento di rete Private Service Connect

In Cloud Shell, crea la subnet per il collegamento di rete PSC:

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

Configurazione di router Cloud e NAT

In questo tutorial, Cloud NAT viene utilizzato per fornire l'accesso a internet alla VM proxy, che non ha un indirizzo IP pubblico. Cloud NAT consente alle VM con solo indirizzi IP privati di connettersi a internet, consentendo loro di eseguire attività come l'installazione di pacchetti software.

In Cloud Shell, crea il router Cloud.

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

In Cloud Shell, crea il gateway NAT con il logging abilitato. Utilizzeremo la registrazione per convalidare l'accesso all'IP pubblico per l'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. Abilitare IAP

Per consentire a IAP di connettersi alle tue istanze VM, crea una regola firewall che:

  • Si applichi a tutte le istanze VM a cui vuoi accedere tramite IAP.
  • Consente il traffico in entrata dall'intervallo IP 35.235.240.0/20. Questo intervallo contiene tutti gli indirizzi IP che utilizzati da IAP per l'inoltro TCP.

In Cloud Shell, crea la regola firewall IAP.

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

5. Crea istanze VM consumer

In Cloud Shell, crea l'istanza VM consumer, proxy-vm, che fungerà da proxy esplicito per Agent Engine. Utilizzeremo tinyproxy come applicazione per il proxy del traffico 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. Collegamento di rete Private Service Connect

I collegamenti di rete sono risorse regionali che rappresentano il lato consumer di un'interfaccia Private Service Connect. Associ un'unica subnet a un collegamento di rete e il producer assegna gli IP all'interfaccia Private Service Connect da quella subnet. La subnet deve trovarsi nella stessa regione del collegamento di rete. Un collegamento di rete deve trovarsi nella stessa regione del servizio di produzione.

Crea il collegamento di rete

In Cloud Shell, crea il collegamento di rete.

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

Elencare i collegamenti di rete

In Cloud Shell, elenca il collegamento di rete.

gcloud compute network-attachments list

Descrivi i collegamenti di rete

In Cloud Shell, descrivi il collegamento di rete.

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

Prendi nota del nome del collegamento di rete PSC, psc-network-attachment, che verrà utilizzato dal producer durante la creazione dell'interfaccia Private Service Connect.

Per visualizzare l'URL dell'allegato di rete PSC in Cloud Console, vai a:

Servizi di rete → Private Service Connect → Collegamento di rete → psc-network-attachment

8eec51cb197da218.png

7. Zona DNS privata

Creerai una zona Cloud DNS per demo.com e la popolerai con un record A che rimanda agli indirizzi IP di proxy-vm. In seguito, il peering DNS verrà implementato in Agent Engine, il che consentirà l'accesso ai record DNS del consumatore.

In Cloud Shell, esegui il comando seguente per creare un nome 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"

Ottieni e memorizza gli indirizzi IP delle istanze utilizzate per i record A DNS.

In Cloud Shell, esegui un comando describe sulle istanze VM.

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

In Cloud Shell, crea il set di record per la VM proxy-vm.demo.com, assicurandoti di aggiornare l'indirizzo IP in base all'output del tuo 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"

Crea una regola Cloud Firewall per consentire l'accesso dall'interfaccia PSC

Nella sezione seguente, crea una regola firewall che consenta al traffico proveniente dall'allegato di rete PSC di accedere a proxy-vm nel VPC consumer.

In Cloud Shell, crea la regola firewall in entrata.

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. Crea un notebook Jupyter

La sezione seguente ti guida nella creazione di un blocco note Jupyter. Questo notebook verrà utilizzato per il deployment di Agent Engine che ha come target un proxy esplicito per l'uscita da internet.

Crea un service account gestito dall'utente

Nella sezione seguente creerai un service account che verrà associato all'istanza di Vertex AI Workbench utilizzata nel tutorial.

Nel tutorial, al service account verranno applicati i seguenti ruoli:

In Cloud Shell, crea il service account.

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

In Cloud Shell, aggiorna il service account con il ruolo Storage Admin.

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

In Cloud Shell, aggiorna il service account con il ruolo Utente Vertex AI.

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

In Cloud Shell, aggiorna il service account con il ruolo Amministratore di Artifact Registry.

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

In Cloud Shell, consenti al service account del notebook di utilizzare il service account Compute Engine predefinito.

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. Aggiorna il proxy esplicito

Nella sezione seguente, dovrai eseguire l'accesso SSH al proxy esplicito e aggiornare il file di configurazione tinyproxy.conf, quindi eseguire un ripristino.

Da Cloud Shell

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

Apri il file di configurazione di tinyproxy e aggiornalo utilizzando un editor a tua scelta. Di seguito è riportato un esempio che utilizza 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. Crea un'istanza di Vertex AI Workbench

Nella sezione seguente, crea un'istanza di Vertex AI Workbench che incorpori il service account creato in precedenza, notebook-sa.

In Cloud Shell, crea l'istanza 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. Aggiornamento di Vertex AI Service Agent

Vertex AI agisce per tuo conto per eseguire operazioni come l'ottenimento di un indirizzo IP dalla subnet di collegamento di rete PSC utilizzata per creare l'interfaccia PSC. A questo scopo, Vertex AI utilizza un service agent (elencato di seguito) che richiede l'autorizzazione Network Admin:

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

In Cloud Shell, ottieni il numero del progetto.

gcloud projects describe $projectid | grep projectNumber

In Cloud Shell, imposta il numero del progetto.

projectnumber=YOUR-PROJECT-Number

In Cloud Shell, crea un service account per AI Platform. Salta questo passaggio se hai un service account esistente nel tuo progetto.

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

In Cloud Shell, aggiorna l'account agente di servizio con il ruolo compute.networkAdmin.

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

In Cloud Shell, aggiorna l'account agente di servizio con il ruolo dns.peer

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

Aggiornamento del service account predefinito

Concedi al tuo service account predefinito l'accesso a Vertex AI. Tieni presente che la propagazione della modifica dell'accesso potrebbe richiedere un po' di tempo.

In Cloud Shell, aggiorna il service account predefinito con il ruolo aiplatform.user

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

12. Proxy VM Tcpdump

Per convalidare la connettività IP da Agent Engine, possiamo utilizzare TCPDUMP. Ciò ci consentirà di osservare la comunicazione proveniente dalla subnet di collegamento di rete PSC, 192.168.10.0/28, quando viene richiamata la richiesta GET da Agent Engine all'URL pubblico.

Da Cloud Shell, esegui l'accesso SSH alla VM proxy.

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

Dal sistema operativo proxy-vm esegui tcpdump.

sudo tcpdump -i any net 192.168.10.0/28 -nn

13. Esegui il deployment di Agent Engine

Nota: utilizzeremo la console GCP e il blocco note JupyterLab per completare le attività in questa sezione

Nella sezione seguente, creerai un blocco note che esegue le seguenti attività:

  • Utilizza l'API Frankfurter (https://api.frankfurter.app/) per ottenere i dati sui tassi di cambio
  • Fa riferimento a un proxy esplicito (proxy_server) che ha come target la VM proxy nel VPC dei consumer utilizzando il FQDN proxy-vm.demo.com
  • Definisci dnsPeeringConfigs "domain": "demo.com."

Esegui il job di addestramento nell'istanza di Vertex AI Workbench.

  • Nella console Google Cloud, vai a Vertex AI → Workbench.
  • Accanto al nome dell'istanza di Vertex AI Workbench (workbench-tutorial), fai clic su Apri JupyterLab. L'istanza di Vertex AI Workbench si apre in JupyterLab.
  • Seleziona File > Nuovo > Notebook.
  • Seleziona Kernel > Python 3.

Installa le librerie Python necessarie: installa le librerie richieste per Agent Engine, tra cui pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys e langchain-google-vertexai.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

!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

Riavvia il kernel di Jupyter Notebook: assicurati che le librerie appena installate vengano caricate correttamente.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

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

import IPython

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

Imposta le variabili di progetto e bucket: definisci l'ID progetto Google Cloud, il numero di progetto, il nome del servizio, la directory GCS, l'endpoint, il nome del bucket e la posizione.

Aggiorna i seguenti campi prima di eseguire la cella

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

Nota: utilizzeremo la variabile BUCKET per creare un bucket Cloud Storage nel passaggio successivo.

Nel blocco note JupyterLab, crea una nuova cella, aggiorna ed esegui quanto segue.

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"}

Crea un bucket GCS: crea un bucket Cloud Storage per archiviare il codice dell'agente.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

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

Definisci il nome del collegamento di rete: specifica il nome del collegamento di rete Private Service Connect.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

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

Inizializza le librerie client Python: configura le librerie client necessarie per i servizi Google Cloud.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

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)

Configura l'agente e gli strumenti: definisci la classe StreamingAgent e la funzione get_exchange_rate per recuperare i tassi di cambio utilizzando l'API Frankfurter tramite il proxy esplicito.

Nel notebook JupyterLab, crea una nuova cella ed esegui la configurazione riportata di seguito. Tieni presente i seguenti punti salienti:

  • La funzione def get_exchange_rate utilizzerà l'API Frankfurter (https://api.frankfurter.app/) per ottenere i dati sul tasso di cambio.
  • proxy_server = "http://proxy-vm.demo.com:8888" FQDN è associato alla VM proxy di cui è stato eseguito il deployment nel VPC consumer. Utilizziamo il peering DNS per risolvere l'FQDN in un passaggio successivo.
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()

Carica i file dell'agente in Cloud Storage: carica l'agente serializzato e i relativi requisiti nel bucket GCS designato.

Nel notebook JupyterLab, crea una nuova cella ed esegui il seguente comando:

# 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}

Esegui il deployment di Agent Engine: esegui il deployment di Agent Engine, configurandolo con l'interfaccia PSC e il peering DNS per risolvere l'FQDN della VM proxy nel VPC consumer.

Nel blocco note JupyterLab, crea ed esegui la cella riportata di seguito. Tieni presente i seguenti punti salienti:

  • Il peering DNS con i VPC consumer è configurato utilizzando dnsPeeringConfigs (dnsPeeringConfigs) per il nome di dominio 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)

Monitora lo stato del deployment: controlla lo stato dell'operazione di deployment di Agent Engine.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

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

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

Nota: il completamento di questa operazione può richiedere circa 5 minuti. Esegui di nuovo la cella per controllare lo stato di avanzamento. Non procedere alla sezione successiva finché non visualizzi un output simile allo screenshot riportato di seguito.

# 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))

Esempio di esecuzione riuscita:

3f6dcd1074af7651.png

Esegui query sull'agente di cui è stato eseguito il deployment: invia una query al motore dell'agente di cui è stato eseguito il deployment per testarne la funzionalità.

Nel blocco note JupyterLab, crea una nuova cella ed esegui il seguente comando.

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)

Trasmetti in streaming i risultati della query: trasmetti in streaming l'output della query di Agent Engine.

Nel notebook JupyterLab, crea una nuova cella ed esegui il seguente codice che attiverà la chiamata API all'URL pubblico utilizzando il proxy esplicito nel VPC dei consumer.

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))

Esempio di esecuzione riuscita:

1bd81d12426a348f.png

14. Convalida di Tcpdump

Visualizza l'output di tcpdump che descrive in dettaglio la comunicazione tra l'indirizzo IP di collegamento di rete PSC utilizzato da Agent Engine e Prox-VM al momento della pubblicazione della richiesta.

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. Convalida dell'interfaccia PSC

Puoi anche visualizzare gli IP di collegamento di rete utilizzati da Agent Engine accedendo a:

Servizi di rete → Private Service Connect → Collegamento di rete → psc-network-attachment

Seleziona il progetto tenant (il nome del progetto termina con -tp)

8a4b5a6e5dfd63d7.png

Il campo evidenziato indica l'indirizzo IP utilizzato da Agent Engine dall'allegato di rete PSC.

c618359f6eafc0c6.png

16. Convalida di Cloud Logging

Esci dalla sessione TCPDump di proxy-vm ed esegui un PING su api.frankfurter.app per ottenere l'indirizzo IP pubblico associato.

ping -c4 api.frankfurter.app 

L'esempio identifica 104.26.1.198 come IP pubblico per 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

Diamo un'occhiata al logging NAT per vedere se viene osservato il traffico per 104.26.1.198.

Vai a:

Monitoraggio → Esplora log

Utilizza il seguente filtro:

resource.type="nat_gateway"

31024dc29c39084.png

Seleziona il periodo di tempo, quindi Esegui query.

5976857e92d149d3.png

Espandi la voce di log che identifica l'IP pubblico (di destinazione) (104.26.1.198) di api.frankfurter.app e l'indirizzo IP di origine e il nome della VM proxy che convalida l'utilizzo del proxy esplicito per l'uscita da internet.

14e293a7fea68db4.png

17. Esegui la pulizia

Nel notebook JupyterLab, crea una nuova cella ed esegui il seguente comando che attiverà l'eliminazione del deployment di 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)

Da Cloud Shell, elimina i componenti del 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. Complimenti

Congratulazioni, hai configurato e convalidato correttamente Agent Engine di cui è stato eseguito il deployment con l'interfaccia Private Service Connect con traffico in uscita da internet eseguito tramite un proxy esplicito.

Hai creato l'infrastruttura consumer e hai aggiunto un collegamento di rete che ha consentito al producer di creare una VM con più NIC per collegare la comunicazione tra consumer e producer. Hai imparato a creare un peering proxy e DNS esplicito che consentisse la connettività a internet.

Cosmopup pensa che i tutorial siano fantastici.

c911c127bffdee57.jpeg

Passaggi successivi

Ulteriori letture e video

Documenti di riferimento