Proxy explicite PSC Agent Engine

1. Introduction

Une interface Private Service Connect est une ressource qui permet à un réseau cloud privé virtuel (VPC) de producteur d'initier des connexions avec différentes destinations dans un réseau VPC consommateur. Les réseaux de producteurs et les réseaux de clients peuvent appartenir à différents projets et organisations.

Si un rattachement de réseau accepte une connexion depuis une interface Private Service Connect, Google Cloud attribue à l'interface une adresse IP d'un sous-réseau client spécifié par le rattachement de réseau. Les réseaux utilisateur et producteur sont connectés et peuvent communiquer à l'aide d'adresses IP internes.

Une connexion entre un rattachement de réseau et une interface Private Service Connect est semblable à la connexion entre un point de terminaison Private Service Connect et un rattachement de service, avec toutefois deux différences majeures :

  • Un rattachement de réseau permet à un réseau producteur d'établir des connexions avec un réseau consommateur (sortie de service géré), tandis qu'un point de terminaison permet à un réseau consommateur d'établir des connexions avec un réseau producteur (entrée de service géré).
  • Une connexion d'interface Private Service Connect est transitive. Cela signifie qu'un réseau de producteur peut communiquer avec d'autres réseaux connectés au réseau du client.

Considérations concernant l'accessibilité de l'interface PSC Vertex AI

  • L'interface PSC est capable de router le trafic vers des destinations VPC ou sur site dans le bloc d'adresses RFC1918.
  • L'interface PSC ciblant des blocs d'adresses non-RFC 1918 nécessite un proxy explicite déployé dans le VPC du consommateur avec une adresse RFC 1918. Dans le déploiement Vertex AI, le proxy doit être défini avec un nom de domaine complet du point de terminaison cible.
  • Lorsque vous configurez votre déploiement avec une interface PSC uniquement, il conserve son accès Internet par défaut. Ce trafic sortant quitte directement le réseau locataire sécurisé et géré par Google.

Considérations concernant l'interface VPC-SC de Vertex AI PSC

  • Lorsque votre projet fait partie d'un périmètre VPC Service Controls, l'accès à Internet par défaut des locataires gérés par Google est bloqué par le périmètre pour empêcher l'exfiltration de données.
  • Pour autoriser l'accès au déploiement à l'Internet public dans ce scénario, vous devez configurer explicitement un chemin de sortie sécurisé qui achemine le trafic via votre VPC.
  • La méthode recommandée pour y parvenir consiste à configurer un serveur proxy à l'intérieur de votre périmètre VPC avec une adresse RFC1918 et à créer une passerelle Cloud NAT pour permettre à la VM proxy d'accéder à Internet.

Pour en savoir plus, consultez les ressources suivantes :

Déployer un agent | IA générative sur Vertex AI | Google Cloud

Configurer une interface Private Service Connect pour les ressources Vertex AI | Google Cloud

Ce que vous allez faire

Dans ce tutoriel, vous allez créer un moteur d'agent complet déployé avec une interface Private Service Connect (PSC) pour permettre la connectivité à un site public (https://api.frankfurter.app/) via une VM de proxy déployée dans le VPC du consommateur avec une adresse RFC1918. L'exemple de déploiement s'applique dans un projet VPC-SC activé ou pour les administrateurs qui ont besoin d'une sortie Internet via le réseau client au lieu du VPC locataire.

Figure 1

f42f2db921f6d5af.png

Vous allez créer un seul psc-network-attachment dans le VPC consommateur en utilisant l'appairage DNS pour résoudre la VM proxy du réseau consommateur dans le projet locataire hébergeant Agent Engine, ce qui permet les cas d'utilisation suivants :

Déployer Agent Engine et configurer une VM proxy pour qu'elle agisse en tant que proxy explicite, ce qui lui permet d'accéder à une URL publique https://api.frankfurter.app

Points abordés

  • Créer un rattachement de réseau
  • Comment un producteur peut utiliser un rattachement de réseau pour créer une interface PSC
  • Établir une communication du producteur au consommateur à l'aide de l'appairage DNS
  • Déployer et utiliser une VM proxy pour la sortie Internet

Prérequis

Projet Google Cloud

Autorisations IAM

2. Avant de commencer

Mettre à jour le projet pour qu'il soit compatible avec le tutoriel

Ce tutoriel utilise des $variables pour faciliter l'implémentation de la configuration gcloud dans Cloud Shell.

Dans Cloud Shell, procédez comme suit :

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

Activation de l'API

Dans Cloud Shell, procédez comme suit :

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"

Vérifier que les API sont activées

gcloud services list --enabled

3. Configuration du client

Créer le VPC consommateur

Ce VPC réside dans un projet client. Les ressources suivantes seront créées dans ce VPC :

  • Sous-réseau du client
  • Sous-réseau de rattachement de réseau
  • Cloud Router (requis pour Cloud NAT)
  • Cloud NAT

Dans Cloud Shell, procédez comme suit :

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

Créer les sous-réseaux consommateurs

Dans Cloud Shell, créez le sous-réseau pour la VM proxy :

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

Créer le sous-réseau de rattachement de réseau Private Service Connect

Dans Cloud Shell, créez le sous-réseau pour l'association de réseau PSC :

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

Configuration de Cloud Router et de NAT

Dans ce tutoriel, Cloud NAT est utilisé pour fournir un accès à Internet à la VM proxy, qui ne dispose pas d'adresse IP publique. Cloud NAT permet aux VM ne disposant que d'adresses IP privées de se connecter à Internet, ce qui leur permet d'effectuer des tâches telles que l'installation de packages logiciels.

Dans Cloud Shell, créez le routeur Cloud Router.

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

Dans Cloud Shell, créez la passerelle NAT avec la journalisation activée. Nous utiliserons la journalisation pour valider l'accès à l'adresse IP publique de 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. Activer IAP

Pour permettre à IAP de se connecter à vos instances de VM, créez une règle de pare-feu qui :

  • S'applique à toutes les instances de VM auxquelles vous souhaitez être accessible à l'aide d'IAP.
  • Autorise le trafic entrant à partir de la plage d'adresses IP 35.235.240.0/20. Cette plage contient toutes les adresses IP qu'IAP utilise pour le transfert TCP.

Dans Cloud Shell, créez la règle de pare-feu IAP.

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

5. Créer des instances de VM consommateur

Dans Cloud Shell, créez l'instance de VM consommateur, proxy-vm, qui servira de proxy explicite pour Agent Engine. Nous utiliserons tinyproxy comme application pour le trafic HTTP de proxy.

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. Rattachement de réseau Private Service Connect

Les rattachements de réseau sont des ressources régionales qui représentent le côté utilisateur d'une interface Private Service Connect. Vous associez un seul sous-réseau à un rattachement de réseau, et le producteur attribue des adresses IP à l'interface Private Service Connect à partir de ce sous-réseau. Le sous-réseau doit se trouver dans la même région que le rattachement de réseau. Un rattachement réseau doit se trouver dans la même région que le service producteur.

Créer le rattachement de réseau

Dans Cloud Shell, créez le rattachement de réseau.

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

Lister les rattachements de réseau

Dans Cloud Shell, listez le rattachement réseau.

gcloud compute network-attachments list

Décrire les rattachements de réseau

Dans Cloud Shell, décrivez le rattachement de réseau.

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

Notez le nom du rattachement de réseau PSC, psc-network-attachment, qui sera utilisé par le producteur lors de la création de l'interface Private Service Connect.

Pour afficher l'URL d'association au réseau PSC dans la console Cloud, accédez à :

Services réseau → Private Service Connect → Rattachement de réseau → psc-network-attachment

8eec51cb197da218.png

7. Zone DNS privée

Vous allez créer une zone Cloud DNS pour demo.com et la remplir avec un enregistrement A qui pointe vers les adresses IP de votre VM de proxy. L'appairage DNS sera ensuite déployé dans Agent Engine, ce qui permettra d'accéder aux enregistrements DNS du consommateur.

Dans Cloud Shell, exécutez la commande suivante pour créer un nom 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"

Obtenez et stockez les adresses IP des instances utilisées pour les enregistrements A DNS.

Dans Cloud Shell, exécutez une commande "describe" sur les instances de VM.

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

Dans Cloud Shell, créez l'ensemble d'enregistrements pour la VM proxy-vm.demo.com. Veillez à mettre à jour l'adresse IP en fonction de la sortie de votre environnement.

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

Créer une règle Cloud Firewall pour autoriser l'accès depuis l'interface PSC

Dans la section suivante, créez une règle de pare-feu qui autorise le trafic provenant de l'attachement de réseau PSC à accéder à la VM de proxy dans le VPC consommateur.

Dans Cloud Shell, créez la règle de pare-feu d'entrée.

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. Créer un notebook Jupyter

La section suivante vous explique comment créer un notebook Jupyter. Ce notebook sera utilisé pour déployer Agent Engine en ciblant un proxy explicite pour la sortie Internet.

Créer un compte de service géré par l'utilisateur

Dans la section suivante, vous allez créer un compte de service qui sera associé à l'instance Vertex AI Workbench utilisée dans le tutoriel.

Dans le tutoriel, les rôles suivants seront appliqués au compte de service :

Dans Cloud Shell, créez le compte de service.

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

Dans Cloud Shell, mettez à jour le compte de service avec le rôle "Administrateur Storage".

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

Dans Cloud Shell, mettez à jour le compte de service avec le rôle Utilisateur Vertex AI.

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

Dans Cloud Shell, mettez à jour le compte de service avec le rôle Administrateur Artifact Registry.

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

Dans Cloud Shell, autorisez le compte de service du notebook à utiliser le compte de service Compute Engine par défaut.

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. Mettre à jour le proxy explicite

Dans la section suivante, vous devrez vous connecter en SSH au proxy explicite, puis mettre à jour le fichier de configuration tinyproxy.conf et effectuer une réinitialisation.

Depuis Cloud Shell

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

Ouvrez le fichier de configuration tinyproxy et mettez-le à jour à l'aide de l'éditeur de votre choix. Vous trouverez ci-dessous un exemple utilisant 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. Créer une instance Vertex AI Workbench

Dans la section suivante, créez une instance Vertex AI Workbench qui intègre le compte de service notebook-sa créé précédemment.

Dans Cloud Shell, créez l'instance de client privé.

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. Mise à jour de l'agent de service Vertex AI

Vertex AI agit en votre nom pour effectuer des opérations telles que l'obtention d'une adresse IP à partir du sous-réseau de rattachement de réseau PSC utilisé pour créer l'interface PSC. Pour ce faire, Vertex AI utilise un agent de service (listé ci-dessous) qui nécessite l'autorisation Administrateur réseau :

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

Dans Cloud Shell, obtenez le numéro de votre projet.

gcloud projects describe $projectid | grep projectNumber

Dans Cloud Shell, définissez le numéro de votre projet.

projectnumber=YOUR-PROJECT-Number

Dans Cloud Shell, créez un compte de service pour AI Platform. Ignorez cette étape si vous disposez déjà d'un compte de service dans votre projet.

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

Dans Cloud Shell, mettez à jour le compte de l'agent de service avec le rôle compute.networkAdmin.

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

Dans Cloud Shell, mettez à jour le compte de l'agent de service avec le rôle dns.peer.

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

Mise à jour du compte de service par défaut

Accordez à votre compte de service par défaut l'accès à Vertex AI. Notez que la propagation de la modification d'accès peut prendre un certain temps.

Dans Cloud Shell, mettez à jour le compte de service par défaut avec le rôle aiplatform.user.

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

12. Tcpdump de la VM du proxy

Pour valider la connectivité IP depuis Agent Engine, nous pouvons utiliser TCPDUMP. Cela nous permettra d'observer la communication provenant du sous-réseau de rattachement au réseau PSC, 192.168.10.0/28, lors de l'appel de la requête GET depuis Agent Engine vers l'URL publique.

Depuis Cloud Shell, connectez-vous en SSH à la VM de proxy.

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

Exécutez tcpdump à partir de l'OS de la VM proxy.

sudo tcpdump -i any net 192.168.10.0/28 -nn

13. Déployer Agent Engine

Remarque : Nous allons utiliser la console GCP et le notebook JupyterLab pour effectuer les tâches de cette section.

Dans la section suivante, vous allez créer un notebook qui effectue les tâches suivantes :

  • Utilise l'API Frankfurter (https://api.frankfurter.app/) pour obtenir des données sur les taux de change.
  • Fait référence à un proxy explicite (proxy_server) ciblant la VM de proxy dans le VPC des consommateurs à l'aide du nom de domaine complet proxy-vm.demo.com
  • Définissez dnsPeeringConfigs "domain": "demo.com."

Exécutez le job d'entraînement dans l'instance Vertex AI Workbench.

  • Dans la console Google Cloud, accédez à Vertex AI > Workbench.
  • À côté du nom de votre instance Vertex AI Workbench (workbench-tutorial), cliquez sur "Ouvrir JupyterLab". Votre instance Vertex AI Workbench ouvre JupyterLab.
  • Sélectionnez Fichier > Nouveau > Notebook.
  • Sélectionnez Kernel > Python 3.

Installez les bibliothèques Python nécessaires : installez les bibliothèques requises pour Agent Engine, y compris pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys et langchain-google-vertexai.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

!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

Redémarrez le noyau Jupyter Notebook : assurez-vous que les bibliothèques nouvellement installées sont correctement chargées.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

import IPython

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

Définissez les variables de projet et de bucket : définissez l'ID de votre projet Google Cloud, le numéro de projet, le nom du service, le répertoire GCS, le point de terminaison, le nom du bucket et l'emplacement.

Mettez à jour les champs suivants avant d'exécuter la cellule.

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

Remarque : Nous utiliserons la variable BUCKET pour créer un bucket Cloud Storage à l'étape suivante.

Dans votre notebook JupyterLab, créez une cellule, puis mettez à jour et exécutez le code suivant.

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

Créez un bucket GCS : créez un bucket Cloud Storage pour stocker le code de l'agent.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Définissez le nom du rattachement de réseau : spécifiez le nom de votre rattachement de réseau Private Service Connect.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Initialisez les bibliothèques clientes Python : configurez les bibliothèques clientes nécessaires pour les services Google Cloud.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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)

Configurer l'agent et les outils : définissez la classe StreamingAgent et la fonction get_exchange_rate pour récupérer les taux de change à l'aide de l'API Frankfurter via le proxy explicite.

Dans votre notebook JupyterLab, créez une cellule et exécutez la configuration ci-dessous. Notez les points suivants :

  • La fonction "get_exchange_rate" utilisera l'API Frankfurter (https://api.frankfurter.app/) pour obtenir les données sur les taux de change.
  • proxy_server = "http://proxy-vm.demo.com:8888" Le nom de domaine complet est associé à la VM de proxy déployée dans le VPC consommateur. Nous utilisons le peering DNS pour résoudre le nom de domaine complet lors d'une étape ultérieure.
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()

Importez les fichiers de l'agent dans Cloud Storage : importez l'agent sérialisé et ses exigences dans le bucket GCS désigné.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante :

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

Déployez Agent Engine : déployez Agent Engine en le configurant avec l'interface PSC et l'appairage DNS pour résoudre le nom de domaine complet de la VM proxy dans le VPC consommateur.

Dans votre notebook JupyterLab, créez et exécutez la cellule ci-dessous. Notez les points suivants :

  • L'appairage DNS aux VPC consommateurs est configuré à l'aide de dnsPeeringConfigs (dnsPeeringConfigs) pour le nom de domaine 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)

Surveillez l'état du déploiement : vérifiez l'état de l'opération de déploiement du moteur d'agent.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

Remarque : Cette opération peut prendre environ cinq minutes. Réexécutez la cellule pour vérifier la progression. Veuillez ne pas passer à la section suivante tant que vous n'avez pas obtenu un résultat semblable à celui de la capture d'écran ci-dessous.

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

Exemple d'exécution réussie :

3f6dcd1074af7651.png

Interrogez l'agent déployé : envoyez une requête à l'agent déployé pour tester ses fonctionnalités.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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)

Diffuser les résultats de la requête : diffusez la sortie de la requête Agent Engine.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante, qui déclenchera l'appel d'API à l'URL publique à l'aide du proxy explicite dans le VPC des consommateurs.

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

Exemple d'exécution réussie :

1bd81d12426a348f.png

14. Validation Tcpdump

Affichez la sortie tcpdump qui détaille la communication entre l'adresse IP de l'attachement réseau PSC utilisée par Agent Engine et la Prox-VM lors de la publication de la requête.

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. Validation de l'interface PSC

Vous pouvez également afficher les adresses IP de l'attachement réseau utilisées par Agent Engine en accédant à :

Services réseau → Private Service Connect → Rattachement de réseau → psc-network-attachment

Sélectionnez le projet locataire (nom de projet se terminant par "-tp").

8a4b5a6e5dfd63d7.png

Le champ en surbrillance indique l'adresse IP utilisée par Agent Engine à partir du rattachement de réseau PSC.

c618359f6eafc0c6.png

16. Validation de Cloud Logging

Quittez la session TCPDump de la VM proxy et effectuez un PING vers api.frankfurter.app pour obtenir l'adresse IP publique associée.

ping -c4 api.frankfurter.app 

L'exemple identifie 104.26.1.198 comme adresse IP publique pour 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

Examinons la journalisation NAT pour voir si le trafic pour 104.26.1.198 est observé.

Accédez à l'un des éléments suivants :

Surveillance → Explorateur de journaux

Utilisez le filtre suivant :

resource.type="nat_gateway"

31024dc29c39084.png

Sélectionnez la période, puis cliquez sur "Exécuter la requête".

5976857e92d149d3.png

Développez l'entrée de journal qui identifie l'adresse IP publique (de destination) (104.26.1.198) de api.frankfurter.app, ainsi que l'adresse IP source et le nom de la VM de proxy qui valide l'utilisation du proxy explicite pour la sortie Internet.

14e293a7fea68db4.png

17. Effectuer un nettoyage

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante pour déclencher la suppression du déploiement 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)

Dans Cloud Shell, supprimez les composants du tutoriel.

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. Félicitations

Félicitations, vous avez configuré et validé Agent Engine déployé avec l'interface Private Service Connect, avec une sortie Internet effectuée via un proxy explicite.

Vous avez créé l'infrastructure consommateur et ajouté un rattachement de réseau qui a permis au producteur de créer une VM multi-NIC pour faire le pont entre les communications consommateur et producteur. Vous avez appris à créer un proxy explicite et un appairage DNS qui permettaient la connectivité Internet.

Cosmopup pense que les tutoriels sont géniaux !!

c911c127bffdee57.jpeg

Et ensuite ?

Lectures et vidéos complémentaires

Documents de référence