1. 简介
Private Service Connect 接口是一种资源,允许提供方 Virtual Private Cloud (VPC) 网络发起与使用方 VPC 网络中的各种目的地的连接。提供方网络与使用方网络可以位于不同的项目和组织中。
如果网络连接接受来自 Private Service Connect 接口的连接,Google Cloud 会为该接口分配由网络连接指定的使用方子网的 IP 地址。使用方和提供方网络已连接,可以使用内部 IP 地址进行通信。
网络连接与 Private Service Connect 接口之间的连接与 Private Service Connect 端点与服务连接之间的连接类似,但存在以下两个主要区别:
- 网络连接允许提供方网络发起与使用方网络的连接(代管式服务出站流量),而端点则允许使用方网络发起与提供方网络的连接(代管式服务入站流量)。
- Private Service Connect 接口连接具有传递性。这意味着提供方网络可以与连接到使用方网络的其他网络通信。
Vertex AI PSC 接口可访问性注意事项
- PSC 接口能够将流量路由到 RFC1918 地址块内的 VPC 或本地目标。
- 如果 PSC 接口以非 rfc-1918 地址块为目标,则需要在使用方的 VPC 中部署一个具有 rfc-1918 地址的显式代理。在 Vertex AI 部署中,必须定义代理以及目标端点的 FQDN。
- 如果您仅使用 PSC 接口配置部署,则该部署会保留其默认的互联网访问权限。此出站流量直接从安全的 Google 管理的租户网络流出。
Vertex AI PSC 接口 VPC-SC 注意事项
- 当您的项目属于 VPC Service Controls 边界时,该边界会阻止 Google 管理的租户的默认互联网访问权限,以防止数据渗漏。
- 如需在此场景中允许部署访问公共互联网,您必须明确配置一条安全出站路径,以通过 VPC 路由流量。
- 实现此目的的推荐方法是在 VPC 边界内设置具有 RFC1918 地址的代理服务器,并创建 Cloud NAT 网关以允许代理虚拟机访问互联网。
如需了解详情,请参阅以下资源:
部署代理 | Vertex AI 上的生成式 AI | Google Cloud
为 Vertex AI 资源设置 Private Service Connect 接口 | Google Cloud
构建内容
在本教程中,您将构建一个全面的 Agent Engine,该引擎部署了 Private Service Connect (PSC) 接口,以允许通过部署在使用方 VPC 中的代理虚拟机(具有 RFC1918 地址)连接到公共网站 (https://api.frankfurter.app/)。此部署示例适用于已启用 VPC-SC 的项目,或适用于需要通过客户网络(而非租户 VPC)进行互联网出站流量的管理员。
图 1
您将在使用方 VPC 中创建一个 psc-network-attachment,利用 DNS 对等互连来解析托管 Agent Engine 的租户项目中的使用方网络 proxy-vm,从而实现以下使用情形:
部署 Agent Engine 并配置代理虚拟机以充当显式代理,从而使其能够访问公共网址 https://api.frankfurter.app
学习内容
- 如何创建网络连接
- 提供方如何使用网络连接创建 PSC 接口
- 如何使用 DNS 对等互连建立从提供方到使用方的通信
- 如何部署和使用代理虚拟机进行互联网出站流量
所需条件
Google Cloud 项目
IAM 权限
- Compute Network Admin (roles/compute.networkAdmin)
- Compute Instance Admin (roles/compute.instanceAdmin)
- Compute Security Admin (roles/compute.securityAdmin)
- DNS Administrator (roles/dns.admin)
- IAP-secured Tunnel User (roles/iap.tunnelResourceAccessor)
- Logging Admin (roles/logging.admin)
- Notebooks Admin (roles/notebooks.admin)
- Project IAM Admin (roles/resourcemanager.projectIamAdmin)
- Service Account Admin (roles/iam.serviceAccountAdmin)
- Service Usage Admin (roles/serviceusage.serviceUsageAdmin)
2. 准备工作
更新项目以支持本教程
本教程使用 $变量来帮助在 Cloud Shell 中实现 gcloud 配置。
在 Cloud Shell 中,执行以下操作:
gcloud config list project
gcloud config set project [YOUR-PROJECT-NAME]
projectid=YOUR-PROJECT-NAME
echo $projectid
API 启用
在 Cloud Shell 中,执行以下操作:
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"
验证 API 是否已成功启用
gcloud services list --enabled
3. 使用方设置
创建消费者 VPC
此 VPC 位于客户项目中。系统将在此 VPC 中创建以下资源
- 消费类子网
- 网络连接子网
- Cloud Router(Cloud NAT 必需)
- Cloud NAT
在 Cloud Shell 中,执行以下操作:
gcloud compute networks create consumer-vpc --project=$projectid --subnet-mode=custom
创建使用方子网
在 Cloud Shell 中,为代理虚拟机创建子网:
gcloud compute networks subnets create rfc1918-subnet1 --project=$projectid --range=10.10.10.0/28 --network=consumer-vpc --region=us-central1
创建 Private Service Connect 网络连接子网
在 Cloud Shell 中,为 PSC 网络连接创建子网:
gcloud compute networks subnets create intf-subnet --project=$projectid --range=192.168.10.0/28 --network=consumer-vpc --region=us-central1
Cloud Router 和 NAT 配置
在本教程中,Cloud NAT 用于为没有公共 IP 地址的代理虚拟机提供互联网访问权限。Cloud NAT 可让仅具有专用 IP 地址的虚拟机连接到互联网,从而执行安装软件包等任务。
在 Cloud Shell 中,创建 Cloud Router。
gcloud compute routers create cloud-router-for-nat --network consumer-vpc --region us-central1
在 Cloud Shell 中,创建启用了日志记录的 NAT 网关。我们将使用日志记录来验证对 Frankfurter API (https://api.frankfurter.app/) 的公共 IP 的访问权限。
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. 启用 IAP
如需允许 IAP 连接到您的虚拟机实例,请创建一个防火墙规则,该规则应:
- 适用于您希望使用 IAP 可访问的所有虚拟机实例。
- 允许来自 IP 范围 35.235.240.0/20 的入站流量。此范围包含 IAP 用于 TCP 转发的所有 IP 地址。
在 Cloud Shell 中,创建 IAP 防火墙规则。
gcloud compute firewall-rules create ssh-iap-consumer \
--network consumer-vpc \
--allow tcp:22 \
--source-ranges=35.235.240.0/20
5. 创建使用方虚拟机实例
在 Cloud Shell 中,创建使用方虚拟机实例 proxy-vm,该实例将充当 Agent Engine 的显式代理。我们将使用 tinyproxy 作为代理 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. Private Service Connect 网络连接
网络连接是区域级资源,表示 Private Service Connect 接口的使用方端。您将单个子网与一个网络连接相关联,而提供方将该子网的 IP 分配给 Private Service Connect 接口。子网必须与网络连接位于同一区域。网络连接必须与提供方服务位于同一区域。
创建网络连接
在 Cloud Shell 中,创建网络连接。
gcloud compute network-attachments create psc-network-attachment \
--region=us-central1 \
--connection-preference=ACCEPT_AUTOMATIC \
--subnets=intf-subnet
列出网络连接
在 Cloud Shell 中,列出网络连接。
gcloud compute network-attachments list
描述网络连接
在 Cloud Shell 中,描述网络连接。
gcloud compute network-attachments describe psc-network-attachment --region=us-central1
记下 PSC 网络连接名称 psc-network-attachment
,提供方在创建 Private Service Connect 接口时会使用该名称。
如需在 Cloud 控制台中查看 PSC 网络附加网址,请前往以下位置:
网络服务 → Private Service Connect → 网络连接 → psc-network-attachment
7. 专用 DNS 区域
您将为 demo.com
创建一个 Cloud DNS 区域,并使用指向代理虚拟机的 IP 地址的 A 记录填充该区域。之后,DNS 对等互连将部署在 Agent Engine 中,从而允许访问使用方的 DNS 记录。
在 Cloud Shell 中,执行以下操作以创建 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"
获取并存储用于 DNS A 记录的实例的 IP 地址。
在 Cloud Shell 中,对虚拟机实例执行 describe 操作。
gcloud compute instances describe proxy-vm --zone=us-central1-a | grep networkIP:
在 Cloud Shell 中,为虚拟机 proxy-vm.demo.com 创建记录集,确保根据您环境的输出更新 IP 地址。
gcloud dns --project=$projectid record-sets create proxy-vm.demo.com. --zone="private-dns-codelab" --type="A" --ttl="300" --rrdatas="10.10.10.2"
创建云防火墙规则以允许从 PSC 接口进行访问
在下一部分中,创建一个防火墙规则,以允许源自 PSC 网络连接的流量访问使用方 VPC 中的 proxy-vm。
在 Cloud Shell 中,创建入站防火墙规则。
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. 创建 Jupyter 笔记本
以下部分将指导您创建 Jupyter 笔记本。此笔记本将用于部署以显式代理为目标的 Agent Engine,以实现互联网出站流量。
创建用户管理的服务账号
在下一部分中,您将创建一个服务账号,该账号将与本教程中使用的 Vertex AI Workbench 实例相关联。
在本教程中,服务账号将具有以下角色:
在 Cloud Shell 中,创建服务账号。
gcloud iam service-accounts create notebook-sa \
--display-name="notebook-sa"
在 Cloud Shell 中,使用 Storage Admin 角色更新服务账号。
gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/storage.admin"
在 Cloud Shell 中,使用 Vertex AI User 角色更新服务账号。
gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/aiplatform.user"
在 Cloud Shell 中,使用 Artifact Registry Admin 角色更新服务账号。
gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/artifactregistry.admin"
在 Cloud Shell 中,允许笔记本服务账号使用 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. 更新显式代理
在下一部分中,您需要通过 SSH 连接到显式代理,更新 tinyproxy.conf 配置文件,然后执行重置。
从 Cloud Shell
gcloud compute ssh --zone us-central1-a "proxy-vm" --tunnel-through-iap --project $projectid
打开 tinyproxy 配置文件,使用您选择的编辑器进行更新。以下是使用 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. 创建 Vertex AI Workbench 实例
在下一部分中,创建一个包含之前创建的服务账号 notebook-sa 的 Vertex AI Workbench 实例。
在 Cloud Shell 中,创建 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. Vertex AI Service Agent 更新
Vertex AI 会代表您执行操作,例如从用于创建 PSC 接口的 PSC 网络连接子网获取 IP 地址。为此,Vertex AI 使用需要 Network Admin 权限的服务代理(如下所示):
service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com
在 Cloud Shell 中,获取您的项目编号。
gcloud projects describe $projectid | grep projectNumber
在 Cloud Shell 中,设置您的项目编号。
projectnumber=YOUR-PROJECT-Number
在 Cloud Shell 中,为 AI Platform 创建服务账号。如果您的项目中有现有服务账号,请跳过此步骤。
gcloud beta services identity create --service=aiplatform.googleapis.com --project=$projectnumber
在 Cloud Shell 中,使用角色 compute.networkAdmin 更新服务代理账号。
gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/compute.networkAdmin"
在 Cloud Shell 中,使用角色 dns.peer 更新服务代理账号
gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/dns.peer"
默认服务账号更新
向您的默认服务账号授予对 Vertex AI 的访问权限。请注意,访问权限更改可能需要一段时间才能拓展。
在 Cloud Shell 中,使用 aiplatform.user 角色更新默认服务账号
gcloud projects add-iam-policy-binding $projectid \
--member="serviceAccount:$projectnumber-compute@developer.gserviceaccount.com" \
--role="roles/aiplatform.user"
12. 代理虚拟机的 Tcpdump
为了验证从代理引擎到目标 IP 的 IP 连接,我们可以使用 TCPDUMP。这样一来,当从 Agent Engine 调用公共网址的 get 请求时,我们就可以观察到源自 PSC 网络附加子网 (192.168.10.0/28) 的通信。
通过 Cloud Shell ssh 连接到代理虚拟机。
gcloud compute ssh --zone us-central1-a "proxy-vm" --tunnel-through-iap --project $projectid
从代理虚拟机操作系统执行 tcpdump。
sudo tcpdump -i any net 192.168.10.0/28 -nn
13. 部署 Agent Engine
注意:我们将使用 GCP 控制台和 JupyterLab notebook 完成本部分中的任务
在下一部分中,您将创建一个笔记本,用于执行以下任务:
- 使用 Frankfurter API (https://api.frankfurter.app/) 获取汇率数据
- 引用使用 FQDN proxy-vm.demo.com 定位到消费者 VPC 中的代理虚拟机 (proxy_server) 的显式代理
- 定义 dnsPeeringConfigs “domain”: “demo.com.”
在 Vertex AI Workbench 实例中运行训练作业。
- 在 Google Cloud 控制台中,依次前往 Vertex AI → Workbench
- 在 Vertex AI Workbench 实例名称 (workbench-tutorial) 旁边,点击“打开 JupyterLab”。您的 Vertex AI Workbench 实例会打开 JupyterLab。
- 依次选择“文件”>“新建”>“笔记本”
- 依次选择“内核”>“Python 3”
安装必要的 Python 库:安装 Agent Engine 所需的库,包括 pyyaml、google-cloud-aiplatform、cloudpickle、google-cloud-api-keys 和 langchain-google-vertexai。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
!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
重启 Jupyter Notebook 内核:确保新安装的库已正确加载。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
# Restart the notebook kernel after install, so you can run langchain successfully.
import IPython
app = IPython.Application.instance()
app.kernel.do_shutdown(True)
设置项目和存储分区变量:定义您的 Google Cloud 项目 ID、项目编号、服务名称、GCS 目录、端点、存储分区名称和位置。
在运行单元格之前,请更新以下字段
- PROJECT_ID = "enter-your-projectid"
- PROJECT_NUMBER = "enter-your-projectnumber"
- BUCKET= "enter-a-unique-bucket-name"
注意:我们将在下一步中使用 BUCKET 变量创建 Cloud Storage 存储分区。
在 JupyterLab 笔记本中,创建一个新单元格,更新并运行以下代码。
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"}
创建 GCS 存储分区:创建一个 Cloud Storage 存储分区,用于存储代理代码。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
!gcloud storage buckets create gs://{BUCKET}
定义网络连接名称:指定 Private Service Connect 网络连接的名称。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
NETWORK_ATTACHMENT_NAME = 'psc-network-attachment' #@param {type:"string"}
初始化 Python 客户端库:为 Google Cloud 服务设置必要的客户端库。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
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)
配置代理和工具:定义 StreamingAgent 类和 get_exchange_rate 函数,以通过显式代理使用 Frankfurter API 获取汇率。
在 JupyterLab 笔记本中,创建一个新单元并运行以下配置,请注意以下重点:
- get_exchange_rate 函数将使用 Frankfurter API (https://api.frankfurter.app/) 获取汇率数据。
- proxy_server = "http://proxy-vm.demo.com:8888" FQDN 与部署在使用方 VPC 中的代理虚拟机相关联。我们将在后面的步骤中使用 DNS 对等互连来解析 FQDN。
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()
将代理文件上传到 Cloud Storage:将序列化代理及其要求上传到您指定的 GCS 存储分区。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码:
# 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}
部署 Agent Engine:部署 Agent Engine,并使用 PSC 接口和 DNS 对等互连对其进行配置,以解析使用方 VPC 中的代理虚拟机的 FQDN。
在 JupyterLab 笔记本中,创建并运行以下单元格,注意以下重点:
- 使用 dnsPeeringConfigs (dnsPeeringConfigs) 为域名 demo.com 配置与使用方 VPC 的 DNS 对等互连。
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)
监控部署状态:检查代理引擎部署操作的状态。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
operation_id = json.loads(response.content)["name"].split("/")[7]
pprint.pprint(operation_id)
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
注意:此操作可能需要大约 5 分钟才能完成。重新运行该单元以查看进度。在看到类似于下方屏幕截图的输出之前,请勿继续执行下一部分。
# 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))
成功运行的示例:
查询已部署的代理:向已部署的 Agent Engine 发送查询,以测试其功能。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。
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)
流式传输查询结果:流式传输 Agent Engine 查询的输出。
在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码,该代码将使用消费者 VPC 中的显式代理触发对公共网址的 API 调用。
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))
成功运行的示例:
14. Tcpdump 验证
查看 tcpdump 输出,其中详细说明了在请求发布时,Agent Engine 使用的 PSC 网络附加 IP 地址与 Prox-VM 之间的通信。
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. PSC 接口验证
您还可以通过前往以下位置来查看 Agent Engine 使用的网络附件 IP:
网络服务 → Private Service Connect → 网络连接 → psc-network-attachment
选择租户项目(项目名称以 -tp 结尾)
突出显示的字段表示 Agent Engine 从 PSC 网络连接使用的 IP 地址。
16. Cloud Logging 验证
退出代理虚拟机的 TCPDump 会话,然后对 Frankfurter api.frankfurter.app 执行 PING,以获取关联的公共 IP 地址。
ping -c4 api.frankfurter.app
此示例将 104.26.1.198 标识为 api.frankfurter.app 的公共 IP
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
我们来看一下 NAT 日志,看看是否观察到 104.26.1.198 的流量。
前往以下位置:
监控 → 日志浏览器
使用以下过滤条件:
resource.type="nat_gateway"
选择时间段,然后运行查询
展开日志条目,其中包含 api.frankfurter.app 的(目标)公共 IP (104.26.1.198) 和源 IP 地址,以及验证互联网出站流量是否使用显式代理的 proxy-vm 的名称。
17. 清理
在 JupyterLab 笔记本中,创建一个新单元格并运行以下命令,以触发删除 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)
从 Cloud Shell 中删除教程组件。
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. 恭喜
恭喜!您已成功配置并验证了通过显式代理执行互联网出站流量的 Private Service Connect 接口部署的 Agent Engine。
您创建了使用方基础设施,并添加了网络连接,以允许提供方创建多网卡虚拟机来桥接使用方和提供方之间的通信。您学习了如何创建允许互联网连接的显式代理和 DNS 对等互连。
Cosmopup 认为教程很棒!