Vertex AI Pipelines PSC 接口显式代理

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。请参阅图 1,该图表示在客户 VPC 中配置的显式代理,以方便将流量路由到以下非 RFC-1918 CIDR:

[1] 240.0.0.0/4

[2] 203.0.113.0/2

[3]10.10.20.0/28 不需要代理,属于 rfc1918 范围。

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

476f87a96f153b95.png

Vertex AI PSC 接口 VPC-SC 注意事项

  • 当您的项目属于 VPC Service Controls 边界时,该边界会阻止 Google 管理的租户的默认互联网访问权限,以防止数据渗漏。
  • 如需在此场景中允许部署访问公共互联网,您必须明确配置一条安全出站路径,以通过您的 VPC 路由流量。实现此目的的推荐方法是在 VPC 边界内设置具有 RFC1918 地址的代理服务器,并创建 Cloud NAT 网关以允许代理虚拟机访问互联网。

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

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

构建内容

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

图 2

782ba8f1f3c3f522.png

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

  1. 部署 Vertex AI Pipelines 并配置代理虚拟机以充当显式代理,从而允许其针对 E 类子网中的虚拟机执行 wget。

学习内容

  • 如何创建网络连接
  • 提供方如何使用网络连接创建 PSC 接口
  • 如何使用 DNS 对等互连建立从提供方到使用方的通信
  • 如何从 Vertex AI Pipelines 建立与非 rfc1918 IP 地址空间的通信

所需条件

Google Cloud 项目

IAM 权限

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 "cloudresourcemanager.googleapis.com"
gcloud services enable "artifactregistry.googleapis.com"
gcloud services enable "cloudbuild.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

创建 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

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 网关。

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 中,创建消费者虚拟机实例 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 \
    --metadata startup-script="#! /bin/bash
      sudo apt-get update
      sudo apt-get install tcpdump
      sudo apt-get install apache2 -y
      sudo service apache2 restart
      echo 'Class-e server !!' | tee /var/www/html/index.html
      EOF"

在 Cloud Shell 中,创建将用作 Vertex AI Pipelines 显式代理的使用方虚拟机实例 proxy-vm。我们将使用 tinyproxy 作为代理 HTTP 流量的应用,不过它也支持 HTTPS。

gcloud compute instances create proxy-vm \
    --project=$projectid \
    --machine-type=e2-micro \
    --image-family debian-11 \
    --no-address \
    --can-ip-forward \
    --shielded-secure-boot \
    --image-project debian-cloud \
    --zone us-central1-a \
    --subnet=rfc1918-subnet1 \
    --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-network-attachment 名称,提供方在创建 Private Service Connect 接口时会使用该名称。

如需在 Cloud 控制台中查看 PSC 网络附加网址,请前往以下位置:

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

e191e54a103d2222.png

7. 专用 DNS 区域

您将为 demo.com 创建一个 Cloud DNS 地区,并使用指向虚拟机 IP 地址的 A 记录填充该地区。稍后,DNS 对等互连将部署在 Vertex AI Pipelines 作业中,从而使其能够访问使用方的 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 中,对虚拟机实例执行 describe 操作,以获取相应的 IP 地址。

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

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

在 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 中,为虚拟机 proxy-vm 创建记录集,确保根据您环境的输出更新 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 中的 RFC1918 计算资源。

在 Cloud Shell 中,创建入站流量防火墙规则,以允许从 PSC 网络连接子网访问 proxy-vm。

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

在 Cloud Shell 中,创建入站流量防火墙规则,以允许从代理虚拟机子网访问 E 类子网。

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.10.0/28" \
    --destination-ranges="240.0.0.0/4" \
    --enable-logging

8. 更新显式代理

在下一部分中,您需要通过 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

9. 创建 Jupyter 笔记本

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

创建用户管理的服务账号

在下一部分中,您将创建一个服务账号,该账号将与本教程中使用的 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 中,使用 Cloud Build 编辑者角色更新服务账号。

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

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

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 中,获取您的项目编号。

gcloud projects describe $projectid | grep projectNumber
projectNumber: '234086459238'

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

默认服务账号更新

启用 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"

在 Cloud Shell 中,使用 storage.admin 角色更新默认服务账号

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

在 Cloud Shell 中,使用 storage.admin 角色更新默认服务账号

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

12. 启用 Tcpdump

如需验证 Vertex AI Pipelines 的 IP 连接,我们可以使用 TCPDUMP。这样一来,当从 Vertex AI Pipelines 调用对虚拟机 class-e-vm.demo.com (240.0.0.0/4) 的 get 请求时,我们便可以观察到源自 PSC 网络连接子网 192.168.10.0/28 的通信。

通过 Cloud Shell ssh 连接到代理虚拟机。

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

从 proxy-vm 操作系统执行 tcpdump 过滤,以过滤 class-e-vm 和 PSC 网络连接子网。

sudo tcpdump -i any net 240.0.0.0/4 or 192.168.10.0/28 -nn

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

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

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

sudo tcpdump -i any net 10.10.10.0/28 -nn

13. 部署 Vertex AI Pipelines 作业

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

在 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 笔记本中,创建一个新单元格并运行以下代码。

# Install gcloud
!pip install google-cloud

# Install the pipeline required packages
!pip install --upgrade google-cloud-aiplatform \
                         google-cloud-storage \
                         kfp \
                         google-cloud-pipeline-components

# Import libraries
from time import gmtime, strftime
import json
import requests

在 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://proxy-vm.demo.com:8888" 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 non-rfc1918 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://proxy-vm.demo.com:8888" # replace with you VM's IP and proxy 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 对等互连。
  • 显式代理(定义为变量 PROXY_VM_IP)为 proxy-vm.demo.com。解析通过使用方 VPC 内的 DNS 对等互连来处理。
  • 端口 8888 是在 tinyproxy 中配置的监听端口(默认)
  • 通过 DNS 对等互连解析对 class-e-vm-demo.com 的 Wget 请求
  • 该代码为 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 = "proxy-vm.demo.com" #@param {type:"string"}
PROXY_VM_PORT = "8888" #@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 结尾)

f47150235fedb8ce.png

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

39e7b251aeb4f191.png

15. Cloud Logging 验证

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

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

选择已执行的自定义作业

a9be0395c842aa6f.png

选择“查看日志”

53e30765ba5827f3.png

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

f2c5d9fdf5cc8bed.png

3b3788603bb433ee.png

16. TCPDump 验证

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

从代理虚拟机观察 HTTP GET 和 200 OK

03:05:34.778574 ens4  Out IP 10.10.10.2.40326 > 240.0.0.2.80: Flags [P.], seq 1:63, ack 1, win 511, options [nop,nop,TS val 1435446009 ecr 2475360885], length 62: HTTP: GET / HTTP/1.0
03:05:34.778946 ens4  In  IP 240.0.0.2.80 > 10.10.10.2.40326: Flags [.], ack 63, win 506, options [nop,nop,TS val 2475360889 ecr 1435446009], length 0
03:05:34.778974 ens4  Out IP 10.10.10.2.40326 > 240.0.0.2.80: Flags [P.], seq 63:185, ack 1, win 511, options [nop,nop,TS val 1435446010 ecr 2475360889], length 122: HTTP
03:05:34.781999 ens4  In  IP 240.0.0.2.80 > 10.10.10.2.40326: Flags [.], ack 185, win 506, options [nop,nop,TS val 2475360892 ecr 1435446010], length 0
03:05:34.906678 ens4  In  IP 240.0.0.2.80 > 10.10.10.2.40326: Flags [P.], seq 1:265, ack 185, win 506, options [nop,nop,TS val 2475361016 ecr 1435446010], length 264: HTTP: HTTP/1.1 200 OK

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

03:05:34.778768 ens4  In  IP 10.10.10.2.40326 > 240.0.0.2.80: Flags [P.], seq 1:63, ack 1, win 511, options [nop,nop,TS val 1435446009 ecr 2475360885], length 62: HTTP: GET / HTTP/1.0
03:05:34.778819 ens4  Out IP 240.0.0.2.80 > 10.10.10.2.40326: Flags [.], ack 63, win 506, options [nop,nop,TS val 2475360889 ecr 1435446009], length 0
03:05:34.781815 ens4  In  IP 10.10.10.2.40326 > 240.0.0.2.80: Flags [P.], seq 63:185, ack 1, win 511, options [nop,nop,TS val 1435446010 ecr 2475360889], length 122: HTTP
03:05:34.781856 ens4  Out IP 240.0.0.2.80 > 10.10.10.2.40326: Flags [.], ack 185, win 506, options [nop,nop,TS val 2475360892 ecr 1435446010], length 0
03:05:34.906503 ens4  Out IP 240.0.0.2.80 > 10.10.10.2.40326: Flags [P.], seq 1:265, ack 185, win 506, options [nop,nop,TS val 2475361016 ecr 1435446010], length 264: HTTP: HTTP/1.1 200 OK

17. 清理

从 Cloud Shell 中删除教程组件。

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 dns record-sets delete class-e-vm.demo.com --zone=private-dns-codelab  --type=A
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 networks delete consumer-vpc --quiet

18. 恭喜

恭喜!您已成功配置并验证了与 Vertex AI Pipelines 的 Private Service Connect 接口。

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

Cosmopup 认为教程很棒!

c911c127bffdee57.jpeg

后续操作

深入阅读和视频

参考文档