Vertex AI Pipelines PSC 接口 SWP

1. 简介

Private Service Connect 接口是一种资源,允许提供方虚拟私有云 (VPC) 网络发起与使用方 VPC 网络中的各种目的地的连接。提供方网络与使用方网络可以位于不同的项目和组织中。

如果网络连接接受来自 Private Service Connect 接口的连接,Google Cloud 会为该接口分配由网络连接指定的使用方子网的 IP 地址。使用方和提供方网络已连接,可以使用内部 IP 地址进行通信。

网络连接与 Private Service Connect 接口之间的连接与 Private Service Connect 端点与服务连接之间的连接类似,但存在以下两个主要区别:

  • 网络连接允许提供方网络发起与使用方网络的连接(托管式服务出站流量),而端点则允许使用方网络发起与提供方网络的连接(托管式服务入站流量)。
  • Private Service Connect 接口连接具有传递性。这意味着提供方网络可以与连接到使用方网络的其他网络通信。

d7dc28d6567e6283.png图 1

Vertex AI PSC 接口可达性注意事项

  • Vertex AI PSC 接口能够将流量路由到 RFC1918 地址块中的 VPC 或本地目标。
  • 如果 PSC 接口以非 RFC-1918 地址块为目标,则需要在消费者的 VPC 中部署具有 RFC-1918 地址的显式代理。在 Vertex AI 部署中,必须定义代理以及目标端点的 FQDN。请参阅图 1,该图显示了在使用方 VPC 中配置的显式代理模式安全 Web 代理 (SWP),以方便路由到以下非 RFC-1918 CIDR:
  1. 240.0.0.0/4
  2. 203.0.113.0/24
  3. 10.10.20.0/28 无需代理,属于 RFC-1918 范围。
  4. 互联网出站流量

Google 管理的租户网络的互联网连接

不含 VPC-SC 的 Vertex AI PSC 接口

  • 如果您仅为部署配置了 PSC 接口,则部署会保留其默认的互联网访问权限。此出站流量直接从 Google 管理的租户网络出站。

将 Vertex AI PSC 接口与 VPC-SC 搭配使用

  • 如果您的项目属于 VPC Service Controls 边界的一部分,该边界会禁用 Google 管理的租户的默认互联网访问权限,以防止数据渗漏。
  • 如需在此场景中允许部署访问公共互联网,您必须明确配置一条安全的出站流量路径,以通过连接到 Vertex AI 的 VPC 路由流量。在具有 RFC 1918 地址的 VPC 网络内部署代理服务器,并搭配使用 Cloud NAT 网关,是实现此目标的一种方法。请注意,您还可以使用 Secure Web Proxy 将流量转发到互联网。创建 Secure Web Proxy 时,系统会自动创建 Cloud NAT 网关。

如需了解详情,请参阅以下资源:

为 Vertex AI 资源设置 Private Service Connect 接口 | Google Cloud

构建内容

在本教程中,您将构建一个全面的 Vertex AI Pipelines 部署,其中包含 Private Service Connect (PSC) 接口,以允许从生产者连接到消费者的计算资源,如图 1 所示,目标是非 RFC 1918 端点 class-e-subnet

2d095dc2f4de6b4b.png图 2

您将在使用方 VPC 中创建一个 psc-network-attachment,利用 DNS 对等互连来解析租户项目中托管 Vertex AI Training 的使用方虚拟机,从而实现以下使用情形:

部署 Vertex AI Pipelines 并以显式代理模式配置 Secure Web Proxy,使其能够针对 E 类子网中的虚拟机执行 wget

学习内容

  • 如何创建网络连接
  • 提供方如何使用网络连接创建 PSC 接口
  • 如何建立 DNS 对等互连,以从 Google 代管式 VPC 网络解析在使用者 VPC 网络中配置的专用网域
  • 如何将流量从 Vertex AI PSC 接口转发到 Secure Web Proxy
  • 如何从 Vertex AI Pipelines 建立与非 RFC-1918 IP 地址空间的通信

所需条件

Google Cloud 项目

IAM 权限

2. 准备工作

更新项目以支持本教程

本教程使用 $变量来帮助在 Cloud Shell 中实现 gcloud 配置。

在 Cloud Shell 中,执行以下操作:

gcloud config list project
gcloud config set project [YOUR-PROJECT-ID]
projectid=YOUR-PROJECT-ID
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 "cloudresourcemanager.googleapis.com"
gcloud services enable "artifactregistry.googleapis.com"
gcloud services enable "cloudbuild.googleapis.com"
gcloud services enable "networkservices.googleapis.com"
gcloud services enable "networksecurity.googleapis.com"
gcloud services enable "certificatemanager.googleapis.com"

3. 使用方设置

创建使用方 VPC

在 Cloud Shell 中,执行以下操作:

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

创建使用方子网

在 Cloud Shell 中,执行以下操作:

gcloud compute networks subnets create class-e-subnet --project=$projectid --range=240.0.0.0/4 --network=consumer-vpc --region=us-central1

在 Cloud Shell 中,执行以下操作:

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

创建代理专用子网

gcloud compute networks subnets create proxy-only-uscentral1 \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE \
    --region=us-central1 \
    --network=consumer-vpc \
    --range=10.10.100.0/26

创建 Private Service Connect 网络连接子网

在 Cloud Shell 中,执行以下操作:

gcloud compute networks subnets create intf-subnet \
--project=$projectid \
--range=192.168.10.0/28 \
--network=consumer-vpc \
--region=us-central1 \
--enable-private-ip-google-access

Cloud Router 和 NAT 配置

Google Cloud Secure Web Proxy 会在其部署的区域中自动预配和管理 Cloud NAT 网关和关联的 Cloud Router。

4. 启用 IAP

如需允许 IAP(Identity-Aware Proxy)连接到您的虚拟机实例,请创建一条防火墙规则,该规则应:

  • 适用于您希望使用 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 中,创建消费者虚拟机实例 class-e-vm

gcloud compute instances create class-e-vm \
    --project=$projectid \
    --machine-type=e2-micro \
    --image-family debian-11 \
    --no-address \
    --shielded-secure-boot \
    --image-project debian-cloud \
    --zone us-central1-a \
    --subnet=class-e-subnet \ 
    --private-network-ip=240.0.0.2

6. Secure Web Proxy

安全 Web 代理的显式模式(或显式代理路由模式)是一种部署方法,其中必须明确配置客户端工作负载,以使用 SWP 的内部 IP 地址或完全限定域名和端口作为其转发代理。

在以下步骤中,请务必将 YOUR-PROJECT-ID 修改为您的项目 ID

创建 Web 代理

在 Cloud Shell 中,使用文本编辑器创建 policy.yaml 文件:

cat > policy.yaml << EOF
description: basic Secure Web Proxy policy
name: projects/$projectid/locations/us-central1/gatewaySecurityPolicies/policy1
EOF

在 Cloud Shell 中,生成 Secure Web Proxy 政策:

gcloud network-security gateway-security-policies import policy1 \
    --source=policy.yaml \
    --location=us-central1

在以下部分中,创建一个规则以允许基于主机 sessionMatcher 访问 class-e-vm

在 Cloud Shell 中,使用文本编辑器创建 rule1.yaml 文件:

cat > rule1.yaml << EOF
name: projects/$projectid/locations/us-central1/gatewaySecurityPolicies/policy1/rules/allow-nonrfc-classe
description: Allow nonrfc class-e
enabled: true
priority: 1
basicProfile: ALLOW
sessionMatcher: host() == 'class-e-vm.demo.com'
EOF

在下一部分中,您将创建一个规则,以允许 Jupyter 笔记本访问 "class-e" 虚拟机,从而允许在 "class-e" 虚拟机上安装 apache2。

在 Cloud Shell 中,使用文本编辑器创建 rule2.yaml 文件:

cat > rule2.yaml << EOF
name: projects/$projectid/locations/us-central1/gatewaySecurityPolicies/policy1/rules/allow-apache2
description: Allow Apache2 install on class-e VM
enabled: true
priority: 2
basicProfile: ALLOW
sessionMatcher: inIpRange(source.ip,'240.0.0.2')
EOF

在 Cloud Shell 中,生成安全政策规则 1:

gcloud network-security gateway-security-policies rules import allow-nonrfc-classe \
    --source=rule1.yaml \
    --location=us-central1 \
    --gateway-security-policy=policy1

在 Cloud Shell 中,生成安全政策规则 2:

gcloud network-security gateway-security-policies rules import allow-apache2 \
    --source=rule2.yaml \
    --location=us-central1 \
    --gateway-security-policy=policy1

如需支持 Vertex AI Training,请使用以下设置配置 Secure Web Proxy 网关:

  • 监听端口:使用在 Vertex AI 应用的代码显式代理设置中配置的同一端口(例如 8080)。
  • 地址:从 RFC 1918 范围分配专用 IP 地址。
  • 路由模式:将此项设置为 EXPLICIT_ROUTING_MODE

在 Cloud Shell 中,创建一个 gateway.yaml 文件来定义 Secure Web Proxy 网关:

cat > gateway.yaml << EOF
name: projects/$projectid/locations/us-central1/gateways/swp1
type: SECURE_WEB_GATEWAY
addresses: ["10.10.10.5"]
ports: [8080]
gatewaySecurityPolicy: projects/$projectid/locations/us-central1/gatewaySecurityPolicies/policy1
network: projects/$projectid/global/networks/consumer-vpc
subnetwork: projects/$projectid/regions/us-central1/subnetworks/rfc1918-subnet1
routingMode: EXPLICIT_ROUTING_MODE
EOF

在 Cloud Shell 中,生成 Secure Web Proxy 实例:

gcloud network-services gateways import swp1 \
    --source=gateway.yaml \
    --location=us-central1

Secure Web Proxy 可能需要几分钟才能完成部署。

e8a4cf23bfc63030.png

7. 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_MANUAL \
    --subnets=intf-subnet

注意:您无需在此附件中明确提及接受的项目 ID,因为在配置 Vertex AI 时,Google 管理的租户项目会自动添加,就好像配置了“自动接受”一样

列出网络连接

在 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

b969cca5242d9c8a.png

8. 专用 DNS 区域

您将为 demo.com 创建一个 Cloud DNS 地区,并使用指向虚拟机 IP 地址的 A 记录填充该地区。稍后,将在 Vertex AI Pipelines 作业中部署 DNS 对等互连,以便该作业能够访问使用方的 DNS 记录。

在 Cloud Shell 中,执行以下操作:

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"

在 Cloud Shell 中,为虚拟机 class-e-vm 创建记录集,确保根据您环境的输出更新 IP 地址。

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

在 Cloud Shell 中,为 Secure Web Proxy 创建记录集,确保根据您环境的输出更新 IP 地址。

gcloud dns --project=$projectid record-sets create explicit-swp.demo.com. --zone="private-dns-codelab" --type="A" --ttl="300" --rrdatas="10.10.10.5"

创建云防火墙规则以允许从 PSC 接口进行访问

在下一部分中,创建一个防火墙规则,以允许源自 PSC 网络连接的流量访问使用方 VPC 中的 RFC 1918 计算资源。

在 Cloud Shell 中,创建入站流量防火墙规则,以允许从代理专用子网访问 E 类子网。由于 SWP 会以仅代理子网作为源地址来发起连接。

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

9. 创建 Jupyter 笔记本

以下部分将指导您创建 Jupyter 笔记本。此笔记本将用于部署 Vertex AI Pipelines 作业,该作业会将 wget 从 Vertex AI Pipelines 发送到测试实例。Vertex AI Pipelines 与包含实例的使用方网络之间的数据路径使用 Private Service Connect 接口。

创建用户管理的服务账号

在下一部分中,您将创建一个服务账号,该账号将与本教程中使用的 Vertex AI Workbench 实例相关联。

在本教程中,服务账号将具有以下角色:

登录 Cloud Shell 并执行以下操作:

创建服务账号。

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

使用 Storage Admin 角色更新服务账号。

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

使用 AI Platform User 角色更新服务账号。

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

使用 Artifact Registry Admin 角色更新服务账号。

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

使用 Cloud Build 编辑者角色更新服务账号。

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

允许笔记本服务账号使用 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"

10. 创建 Vertex AI Workbench 实例

在下一部分中,创建一个包含之前创建的服务账号 notebook-sa 的 Vertex AI Workbench 实例。

在 Cloud Shell 中,创建专用客户端实例。

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 控制台中的 Vertex AI,确保 Vertex AI API 已启用。

在 Cloud Shell 中

获取项目编号。

gcloud projects describe $projectid | grep projectNumber

设置项目编号。

projectnumber=YOUR-PROJECT-NUMBER

为 AI Platform 创建服务账号。如果您的项目中有现有服务账号,请跳过此步骤。

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

使用 compute.networkAdmin 角色更新服务代理账号。

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

使用角色 dns.peer 更新服务代理账号

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

默认服务账号更新

启用 Compute Engine API 并向默认服务账号授予对 Vertex AI 的访问权限。请注意,访问权限更改可能需要一段时间才能传播。

使用 Cloud Shell 更新默认服务账号,如下所示:

使用角色 aiplatform.user 更新默认服务账号

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

使用角色 storage.admin 更新默认服务账号

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

使用角色 artifactregistry.admin 更新默认服务账号

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

12. 在“class-e-vm”上安装 Apache2 并启用 Tcpdump:

通过 Secure Web Proxy 安装 class-e-vm

打开新的 Cloud Shell 标签页,更新项目变量,然后通过 SSH 连接到 class-e-vm

gcloud compute ssh --zone us-central1-a "class-e-vm" --tunnel-through-iap --project $projectid
sudo apt-get -o Acquire::http::Proxy="http://10.10.10.5:8080" update
sudo apt-get -o Acquire::http::Proxy="http://10.10.10.5:8080" install apache2 -y
sudo service apache2 restart
echo 'class-e Server !!' | sudo tee /var/www/html/index.html

在代理专用子网上执行 tcpdump 过滤,供 Secure Web Proxy 用于将流量转发到目标。

从 class-e-vm 操作系统执行对 proxy-vm 子网的 tcpdump 过滤。

sudo tcpdump -i any net 10.10.100.0/24 -nn

注意:请确保您在 workbench-tutorial 实例子网上开启专用 Google 访问通道,以便打开 JupyterLab 会话。

13. 部署 Vertex AI Pipelines 作业

在下一部分中,您将创建一个笔记本,以执行从 Vertex AI Pipelines 到显式代理的成功 wget。这样一来,您就可以访问非 RFC 1918 虚拟机,例如 class-e-vm。由于 rfc1918-vm 的目标是 RFC 1918 IP 地址,因此 Vertex AI Pipelines 无需使用显式代理即可访问 rfc1918-vm

在 Vertex AI Workbench 实例中运行训练作业。

  1. 在 Google Cloud 控制台中,前往 Vertex AI Workbench 页面上的“实例”标签页。
  2. 在 Vertex AI Workbench 实例名称 (workbench-tutorial) 旁边,点击“打开 JupyterLab”。您的 Vertex AI Workbench 实例会打开 JupyterLab。
  3. 依次选择“文件”>“新建”>“笔记本”
  4. 依次选择“内核”>“Python 3”

在 JupyterLab 笔记本中,创建一个新单元格,更新并运行以下代码。请务必使用您环境的详细信息更新 PROJECT_ID。

import json
import requests
import pprint

PROJECT_ID = 'YOUR-PROJECT-ID' #Enter your project ID
PROJECT_NUMBER=!gcloud projects list --filter="project_id:$PROJECT_ID" --format="value(PROJECT_NUMBER)"
PROJECT_NUMBER=str(PROJECT_NUMBER).strip('[').strip(']').strip("'")
print(PROJECT_NUMBER)

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

# us-central1 is used for the codelab
REGION = "us-central1" #@param {type:"string"}
SERVICE_NAME = "aiplatform" #@param {type:"string"}
SERVICE ="{}.googleapis.com".format(SERVICE_NAME)
ENDPOINT="{}-{}.googleapis.com".format(REGION, SERVICE_NAME)
API_VERSION = "v1" # @param {type: "string"}

LOCATION = REGION

在 JupyterLab 笔记本中,创建一个新单元并运行以下配置,请注意以下重点:

  • proxy_server = "http://explicit-swp.demo.com:8080"
  • FQDN 与部署在使用方 VPC 中的代理虚拟机相关联。我们将在后面的步骤中使用 DNS 对等互连来解析 FQDN。
%%writefile main.py

import logging
import socket
import sys
import os

def make_api_request(url: str, proxy_vm_ip: str, proxy_vm_port: str):
    """
    Makes a GET request to a nonRFC-1918 API and saves the response.

    Args:
        url: The URL of the API to send the request to.
    """
    import requests

    try:
        # response = requests.get(url)
        proxy_server = f"http://explicit-swp.demo.com:8080" # replace it with your Secure Web proxy Ip-address and the port.

        proxies = {
          "http": proxy_server,
          "https": proxy_server,
        }

        response = requests.get(url, proxies=proxies)
        logging.info(response.text)

        response.raise_for_status()  # Raise an exception for bad status codes
        logging.info(f"Successfully fetched data from {url}")
    except requests.exceptions.RequestException as e:
        logging.error(f"An error occurred: {e}")
        raise e

if __name__ == '__main__':
  # Configure logging to print clearly to the console
  logging.basicConfig(
      level=logging.INFO,
      format='%(levelname)s: %(message)s',
      stream=sys.stdout
  )
  url_to_test = os.environ['NONRFC_URL']
  proxy_vm_ip = os.environ['PROXY_VM_IP']
  proxy_vm_port = os.environ['PROXY_VM_PORT']

  logging.info(f"url_to_test: {url_to_test}")
  logging.info(f"proxy_vm_ip: {proxy_vm_ip}")
  logging.info(f"proxy_vm_port: {proxy_vm_port}")
  make_api_request(url_to_test, proxy_vm_ip, proxy_vm_port)

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

%%writefile Dockerfile
FROM python:3.9-slim

RUN apt-get update && \
  apt-get install -y iputils-ping && \
  apt-get install -y wget

RUN pip install cloudml-hypertune requests kfp

COPY main.py /main.py

ENTRYPOINT ["python3", "/main.py"]

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

!gcloud artifacts repositories create pipelines-test-repo-psc --repository-format=docker --location=us-central1

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

IMAGE_PROJECT = PROJECT_ID
IMAGE_REPO = 'pipelines-test-repo-psc' 
IMAGE_NAME = 'nonrfc-ip-call'
TAG = 'v1'

IMAGE_URI= f'us-central1-docker.pkg.dev/{IMAGE_PROJECT}/{IMAGE_REPO}/{IMAGE_NAME}:{TAG}'
IMAGE_URI

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

!gcloud auth configure-docker us-docker.pkg.dev --quiet

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。忽略错误 (gcloud.builds.submit)(如果存在)。

!gcloud builds submit --tag {IMAGE_URI} --region=us-central1

在 JupyterLab 笔记本中,创建并运行以下单元格,注意以下重点:

  • 使用 dnsPeeringConfigs (dnsPeeringConfigs) 为域名 demo.com 配置与使用方 VPC 的 DNS 对等互连。
  • 此处的显式路由模式 Web 代理为 explicit-swp.demo.com。解析通过使用方 VPC 内的 DNS 对等互连进行处理。
  • 端口 8080 是在 Secure Web Proxy 中配置的监听端口(默认)
  • 通过 DNS 对等互连解析从 wget 到 class-e-vm-demo.com 的流量
  • 该代码为 Vertex 指定了“psc-network-attachment”,使其能够利用网络连接子网部署两个 PSC 接口实例。
import json
from datetime import datetime


JOB_ID_PREFIX='test_psci-nonRFC' #@param {type:"string"}
JOB_ID = '{}_{}'.format(JOB_ID_PREFIX, datetime.now().strftime("%Y%m%d%H%M%S"))

# PSC-I configs

PRODUCER_PROJECT_ID = PROJECT_ID
DNS_DOMAIN = 'class-e-vm.demo.com' #@param {type:"string"}
NON_RFC_URL = f"http://{DNS_DOMAIN}"

PROXY_VM_IP = "explicit-swp.demo.com" #@param {type:"string"}
PROXY_VM_PORT = "8080" #@param {type:"string"}

CUSTOM_JOB = {
  "display_name": JOB_ID,
  "job_spec": {
      "worker_pool_specs": [
          {
           "machine_spec": {
             "machine_type": "n1-standard-4",
           },
           "replica_count": 1,
           "container_spec": {
             "image_uri": IMAGE_URI,
             "env": [{
               "name": "NONRFC_URL",
               "value": NON_RFC_URL
             },
             {
               "name": "PROXY_VM_IP",
               "value": PROXY_VM_IP
             },
             {
               "name": "PROXY_VM_PORT",
               "value": PROXY_VM_PORT
             }]
           },
         },
      ],
      "enable_web_access": True,
      "psc_interface_config": {
        "network_attachment": "psc-network-attachment",
        "dns_peering_configs": [
          {
            "domain": "demo.com.",
            "target_project": PROJECT_ID,
            "target_network": "consumer-vpc"
          },
        ]
      },
  }
}

print(json.dumps(CUSTOM_JOB, indent=2))

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

import requests
bearer_token = !gcloud auth application-default print-access-token
headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {}'.format(bearer_token[0]),
}

request_uri = f"https://{REGION}-aiplatform.googleapis.com/{API_VERSION}/projects/{PROJECT_NUMBER}/locations/{REGION}/customJobs/"

print("request_uri: ", request_uri)

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

response_autopush = requests.post(request_uri, json=CUSTOM_JOB, headers=headers)
response = response_autopush
print("response:", response)
if response.reason == 'OK':
  job_name = response.json()['name']
  job_id = job_name.split('/')[-1]
  print("Created Job: ", response.json()['name'])
else:
  print(response.text)

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

# Print KFP SDK version (should be >= 1.6)
! python3 -c "import kfp; print('KFP SDK version: {}'.format(kfp.__version__))"

# Print AI Platform version
! python3 -c "from google.cloud import aiplatform; print('AI Platform version: {}'.format(aiplatform.__version__))"

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

BUCKET_URI = "your-unique-bucket" # Provide a globally unique bucket name

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

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

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

# pipeline parameters
CACHE_PIPELINE = False # @param {type: "string"}
_DEFAULT_IMAGE = IMAGE_URI
BUCKET_URI = "gs://{BUCKET_URI}"  # @param {type: "string"}
PIPELINE_ROOT = f"{BUCKET_URI}/pipeline_root/intro"
PIPELINE_DISPLAY_NAME = "pipeline_nonRFCIP" # @param {type: "string"}

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

from re import S
import kfp
from kfp import dsl
from kfp.dsl import container_component, ContainerSpec
from kfp import compiler
from google.cloud import aiplatform


# ==== Component with env variable ====

@container_component
def dns_peering_test_op(dns_domain: str, proxy_vm_ip:str, proxy_vm_port:str):
    return ContainerSpec(
        image=_DEFAULT_IMAGE,
        command=["bash", "-c"],
        args=[
            """
            apt-get update && apt-get install inetutils-traceroute inetutils-ping netcat-openbsd curl -y

            echo "Local IP(s): $(hostname -I)"

            echo "Attempting to trace route to %s"
            traceroute -w 1 -m 7 "%s"

            echo "Sending curl requests to http://%s via proxy %s:%s and recording trace..."
            if curl -L -v --trace-ascii /dev/stdout -x http://%s:%s "http://%s"; then
                echo "Curl request succeeded!"
            else
                echo "Curl request failed!"
                exit 1
            fi
            """ % (dns_domain, dns_domain, dns_domain, proxy_vm_ip, proxy_vm_port, proxy_vm_ip, proxy_vm_port, dns_domain)

        ]
    )

# ==== Pipeline ====
@dsl.pipeline(
    name="dns-peering-test-pipeline",
    description="Test DNS Peering using env variable",
    pipeline_root=PIPELINE_ROOT,
)
def dns_peering_test_pipeline(dns_domain: str, proxy_vm_ip:str, proxy_vm_port:str):
    dns_test_task = dns_peering_test_op(dns_domain=dns_domain, proxy_vm_ip=proxy_vm_ip, proxy_vm_port=proxy_vm_port)
    dns_test_task.set_caching_options(enable_caching=CACHE_PIPELINE)

# ==== Compile pipeline ====
if __name__ == "__main__":
    aiplatform.init(project=PROJECT_ID, location=LOCATION)

    compiler.Compiler().compile(
        pipeline_func=dns_peering_test_pipeline,
        package_path="dns_peering_test_pipeline.yaml",
    )
    print("✅ Pipeline compiled to dns_peering_test_pipeline.yaml")

在 JupyterLab 笔记本中,创建一个新单元格并运行以下代码。

# Define the PipelineJob body; see API Reference https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.pipelineJobs/create

import requests, json
import datetime

bearer_token = !gcloud auth application-default print-access-token
headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {}'.format(bearer_token[0]),
}

request_uri = f"https://{REGION}-aiplatform.googleapis.com/{API_VERSION}/projects/{PROJECT_NUMBER}/locations/{REGION}/pipelineJobs/"

print("request_uri: ", request_uri)

14. PSC 接口验证

您还可以通过以下方式查看 Vertex AI Pipelines 使用的网络附加 IP:

网络服务 → Private Service Connect → 网络连接 → psc-network-attachment

选择租户项目(项目名称以 -tp 结尾)

a2e0b6d6243f26f1.png

突出显示的字段表示 Vertex AI Pipelines 通过 PSC 网络连接使用的 IP 地址。

11e411ea919d3bad.png

15. Cloud Logging 验证

Vertex AI Pipelines 作业首次运行大约需要 14 分钟,后续运行时间会短得多。如需验证结果是否成功,请执行以下操作:

依次前往 Vertex AI → 训练 → 自定义作业

选择已执行的自定义作业

2f467254aa0c2e3a.png

选择“查看日志”

8d525d3b152bcc61.png

Cloud Logging 可用后,选择“运行查询”,该查询会生成以下突出显示的选项,以确认从 Vertex AI Pipelines 到 class-e-vmwget 是否成功。

a4f9e9167f4ce1ae.png

38972f834aa2bd1d.png

16. TCPDump 验证

下面我们来查看 TCPDUMP 输出,以进一步验证与计算实例的连接:

class-e-vm 观察 HTTP GET 和 200 OK

XXXXXXXXX@class-e-vm:~$ sudo tcpdump -i any net 10.10.100.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
05:51:14.173641 ens4  In  IP 10.10.100.8.55306 > 240.0.0.2.80: Flags [S], seq 1747181041, win 65535, options [mss 1420,sackOK,TS val 3942828403 ecr 0,nop,wscale 8], length 0
05:51:14.173668 ens4  Out IP 240.0.0.2.80 > 10.10.100.8.55306: Flags [S.], seq 3013226100, ack 1747181042, win 64768, options [mss 1420,sackOK,TS val 1886125065 ecr 3942828403,nop,wscale 7], length 0
05:51:14.174977 ens4  In  IP 10.10.100.8.55306 > 240.0.0.2.80: Flags [.], ack 1, win 1054, options [nop,nop,TS val 3942828405 ecr 1886125065], length 0
05:51:14.175066 ens4  In  IP 10.10.100.8.55306 > 240.0.0.2.80: Flags [P.], seq 1:223, ack 1, win 1054, options [nop,nop,TS val 3942828405 ecr 1886125065], length 222: HTTP: GET / HTTP/1.1
05:51:14.175096 ens4  Out IP 240.0.0.2.80 > 10.10.100.8.55306: Flags [.], ack 223, win 505, options [nop,nop,TS val 1886125066 ecr 3942828405], length 0
05:51:14.239042 ens4  Out IP 240.0.0.2.80 > 10.10.100.8.55306: Flags [P.], seq 1:246, ack 223, win 505, options [nop,nop,TS val 1886125130 ecr 3942828405], length 245: HTTP: HTTP/1.1 200 OK

17. 清理

从 Cloud Shell 中删除教程组件。

gcloud workbench instances delete workbench-tutorial --project=$projectid --location=us-central1-a

gcloud network-security gateway-security-policies rules delete allow-nonrfc-classe \
    --gateway-security-policy=policy1 \
    --location=us-central1

gcloud network-security gateway-security-policies rules delete allow-apache2 \
    --gateway-security-policy=policy1 \
    --location=us-central1

gcloud network-security gateway-security-policies delete policy1 \
    --location=us-central1
gcloud network-services gateways delete swp1 \
    --location=us-central1

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 dns record-sets delete class-e-vm.demo.com --zone=private-dns-codelab  --type=A
gcloud dns record-sets delete explicit-swp.demo.com --zone=private-dns-codelab  --type=A

gcloud dns managed-zones delete private-dns-codelab

gcloud computeinstances delete class-e-vm --project=$projectid --zone=us-central1-a --quiet
gcloud compute networks delete consumer-vpc --quiet

18. 恭喜

恭喜!您已成功配置并验证了从 Vertex AI Pipelines Private Service Connect 接口到非 RFC IP 范围的连接(通过 Secure Web Proxy)。

您创建了使用方基础设施,并添加了一个网络连接,允许提供方创建多 NIC 虚拟机来桥接使用方和提供方之间的通信。您已了解如何在部署使用方 VPC 网络中的显式代理时创建 DNS 对等互连,从而实现与无法直接从 Vertex 路由的 class-e-vm 实例的连接。

678ba30d64a76795.png

后续操作

深入阅读和视频

参考文档