Proxy explícito de la interfaz de PSC de Vertex AI Pipelines

1. Introducción

Una interfaz de Private Service Connect es un recurso que permite que una red de nube privada virtual (VPC) de productor inicie conexiones a varios destinos en una red de VPC de consumidor. Las redes de productores y consumidores pueden estar en diferentes proyectos y organizaciones.

Si un adjunto de red acepta una conexión desde una interfaz de Private Service Connect, Google Cloud asigna a la interfaz una dirección IP de una subred de consumidor que especifica el adjunto de red. Las redes del consumidor y del productor están conectadas y pueden comunicarse mediante direcciones IP internas.

Una conexión entre un adjunto de red y una interfaz de Private Service Connect es similar a la conexión entre un extremo de Private Service Connect y un adjunto de servicio, pero tiene dos diferencias clave:

  • Un adjunto de red permite que una red de productor inicie conexiones a una red de consumidor (salida de servicio administrado), mientras que un extremo permite que una red de consumidor inicie conexiones a una red de productor (entrada de servicio administrado).
  • Una conexión de la interfaz de Private Service Connect es transitiva. Esto significa que una red del productor puede comunicarse con otras redes que están conectadas a la red del consumidor.

Consideraciones sobre la accesibilidad a la interfaz de PSC de Vertex AI

  • La interfaz de PSC puede enrutar el tráfico a destinos basados en la VPC o en las instalaciones dentro del bloque de direcciones RFC1918.
  • La interfaz de PSC que segmenta bloques de direcciones que no son RFC-1918 requiere un proxy explícito implementado en la VPC del consumidor con una dirección RFC-1918. Dentro de la implementación de Vertex AI, el proxy se debe definir junto con un FQDN del extremo de destino. Consulta la figura 1, que representa el proxy explícito configurado en las VPC de los clientes para facilitar el enrutamiento a los siguientes CIDR que no son de RFC-1918:

[1] 240.0.0.0/4

[2] 203.0.113.0/2

[3]10.10.20.0/28 no requiere proxy, ya que se encuentra dentro del rango de RFC1918.

  • Cuando configuras tu implementación solo con una interfaz de PSC, esta conserva su acceso predeterminado a Internet. Este tráfico saliente sale directamente de la red de usuarios segura y administrada por Google.

476f87a96f153b95.png

Consideraciones sobre la VPC-SC de la interfaz de PSC de Vertex AI

  • Cuando tu proyecto forma parte de un perímetro de Controles del servicio de VPC, el perímetro bloquea el acceso predeterminado a Internet de los arrendatarios administrados por Google para evitar el robo de datos.
  • Para permitir que la implementación acceda a Internet pública en este caso, debes configurar de forma explícita una ruta de salida segura que enrute el tráfico a través de tu VPC. La forma recomendada de lograr esto es configurar un servidor proxy dentro del perímetro de tu VPC con una dirección RFC1918 y crear una puerta de enlace de Cloud NAT para permitir que la VM proxy acceda a Internet.

Para obtener más información, consulta los siguientes recursos:

Configura una interfaz de Private Service Connect para los recursos de Vertex AI | Google Cloud

Qué compilarás

En este instructivo, compilarás una implementación integral de Vertex AI Pipelines con una interfaz de Private Service Connect (PSC) para permitir la conectividad desde el productor hasta el procesamiento del consumidor, como se ilustra en la Figura 1, que apunta a extremos que no son rfc-1928.

Figura 2

782ba8f1f3c3f522.png

Crearás un solo psc-network-attachment en la VPC del consumidor aprovechando el intercambio de tráfico de DNS para resolver las VMs de los consumidores en el proyecto del inquilino que aloja Vertex AI Training, lo que generará los siguientes casos de uso:

  1. Implementa Vertex AI Pipelines y configura una VM de proxy para que actúe como un proxy explícito, lo que le permite realizar un wget en una VM de la subred de clase E.

Qué aprenderás

  • Cómo crear un adjunto de red
  • Cómo un productor puede usar un adjunto de red para crear una interfaz de PSC
  • Cómo establecer la comunicación del productor al consumidor con el intercambio de tráfico de DNS
  • Cómo establecer comunicación con el espacio de direcciones IP que no son rfc1918 desde Vertex AI Pipelines

Requisitos

Proyecto de Google Cloud

Permisos de IAM

2. Antes de comenzar

Actualiza el proyecto para que admita el instructivo

En este instructivo, se usan variables para facilitar la implementación de la configuración de gcloud en Cloud Shell.

En Cloud Shell, haz lo siguiente:

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

Habilitación de la API

En Cloud Shell, haz lo siguiente:

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. Configuración del consumidor

Crea la VPC del consumidor

En Cloud Shell, haz lo siguiente:

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

Crea las subredes de consumidor

En Cloud Shell, haz lo siguiente:

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

En Cloud Shell, haz lo siguiente:

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

Crea la subred del adjunto de red de Private Service Connect

En Cloud Shell, haz lo siguiente:

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

Configuración de Cloud Router y NAT

En este instructivo, se usa Cloud NAT para proporcionar acceso a Internet a la VM de proxy, que no tiene una dirección IP pública. Cloud NAT permite que las VMs con solo direcciones IP privadas se conecten a Internet, lo que les permite realizar tareas como instalar paquetes de software.

Dentro de Cloud Shell, crea el Cloud Router.

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

Dentro de Cloud Shell, crea la puerta de enlace de 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. Habilitar IAP

Para permitir que IAP se conecte a tus instancias de VM, crea una regla de firewall que cumpla con lo siguiente:

  • Se aplica a todas las instancias de VM a las que deseas acceder con IAP.
  • Permite el tráfico de entrada desde el rango de IP 35.235.240.0/20. Este rango contiene todas las direcciones IP que IAP usa para el reenvío de TCP.

Dentro de Cloud Shell, crea la regla de firewall de IAP.

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

5. Crea instancias de VM de consumidor

Dentro de Cloud Shell, crea la instancia de VM del consumidor, 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"

En Cloud Shell, crea la instancia de VM del consumidor, proxy-vm, que actuará como proxy explícito para Vertex AI Pipelines. Usaremos tinyproxy como la aplicación para el tráfico HTTP de proxy, aunque también se admite 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. Adjunto de red de Private Service Connect

Los adjuntos de red son recursos regionales que representan el lado del consumidor de una interfaz de Private Service Connect. Debes asociar una sola subred con un adjunto de red y el productor asigna IPs a la interfaz de Private Service Connect desde esa subred. La subred debe estar en la misma región que el adjunto de red. Un adjunto de red debe estar en la misma región que el servicio del productor.

Crea el adjunto de red

Dentro de Cloud Shell, crea la conexión de red.

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

Enumera los archivos adjuntos de red

Dentro de Cloud Shell, enumera el adjunto de red.

gcloud compute network-attachments list

Describe los adjuntos de red

Dentro de Cloud Shell, describe el adjunto de red.

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

Toma nota del nombre del adjunto de red de PSC, psc-network-attachment, que usará el productor cuando cree la interfaz de Private Service Connect.

Para ver la URL de la conexión de red de PSC en la consola de Cloud, navega a la siguiente ubicación:

Servicios de red → Private Service Connect → Adjunto de red → psc-network-attachment

e191e54a103d2222.png

7. Zona de DNS privada

Crearás una zona de Cloud DNS para demo.com y la completarás con registros A que apunten a las direcciones IP de tus VMs. Más adelante, se implementará el intercambio de tráfico de DNS en el trabajo de Vertex AI Pipelines, lo que le permitirá acceder a los registros DNS del consumidor.

En Cloud Shell, haz lo siguiente:

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"

Dentro de Cloud Shell, ejecuta una descripción de las instancias de VM para obtener las direcciones IP respectivas.

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:

Dentro de Cloud Shell, crea el conjunto de registros para la VM, class-e-vm, y asegúrate de actualizar la dirección IP según el resultado de tu entorno.

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"

En Cloud Shell, crea el conjunto de registros para la VM, proxy-vm, y asegúrate de actualizar la dirección IP según el resultado de tu entorno.

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

Crea una regla de Cloud Firewall para permitir el acceso desde la interfaz de PSC

En la siguiente sección, crea una regla de firewall que permita que el tráfico que se origina en el adjunto de red de PSC acceda a los recursos de procesamiento de RFC1918 en la VPC del consumidor.

En Cloud Shell, crea la regla de firewall de entrada que permite el acceso desde la subred de Network Attachment de PSC a 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

En Cloud Shell, crea la regla de firewall de entrada que permite el acceso desde la subred proxy-vm a la subred class-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. Actualiza el proxy explícito

En la siguiente sección, deberás acceder al proxy explícito a través de SSH y actualizar el archivo de configuración tinyproxy.conf antes de realizar un restablecimiento.

Desde Cloud Shell

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

Abre el archivo de configuración de tinyproxy y actualízalo con el editor que prefieras. A continuación, se muestra un ejemplo con 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. Crea un notebook de Jupyter

En la siguiente sección, se te guiará para crear un notebook de Jupyter. Este notebook se usará para implementar un trabajo de Vertex AI Pipelines que envíe un wget desde Vertex AI Pipelines a las instancias de prueba. La ruta de datos entre Vertex AI Pipelines y la red del consumidor que contiene las instancias usa una interfaz de red de Private Service Connect.

Crea una cuenta de servicio administrada por el usuario

En la siguiente sección, crearás una cuenta de servicio que se asociará con la instancia de Vertex AI Workbench que se usa en el instructivo.

En el instructivo, la cuenta de servicio tendrá los siguientes roles aplicados:

Dentro de Cloud Shell, crea la cuenta de servicio.

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

En Cloud Shell, actualiza la cuenta de servicio con el rol de administrador de Storage.

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

Dentro de Cloud Shell, actualiza la cuenta de servicio con el rol de usuario de Vertex AI.

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

Dentro de Cloud Shell, actualiza la cuenta de servicio con el rol de administrador de Artifact Registry.

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

Dentro de Cloud Shell, actualiza la cuenta de servicio con el rol de editor de Cloud Build.

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

Dentro de Cloud Shell, permite que la cuenta de servicio del notebook use la cuenta de servicio predeterminada de 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. Crea una instancia de Vertex AI Workbench

En la siguiente sección, crea una instancia de Vertex AI Workbench que incorpore la cuenta de servicio creada anteriormente, notebook-sa.

Dentro de Cloud Shell, crea la instancia de 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. Actualización del agente de servicio de Vertex AI

Vertex AI actúa en tu nombre para realizar operaciones como obtener una dirección IP de la subred del adjunto de red de PSC que se usa para crear la interfaz de PSC. Para ello, Vertex AI usa un agente de servicio (que se indica a continuación) que requiere permiso de administrador de red.

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

En Cloud Shell, obtén el número de tu proyecto.

gcloud projects describe $projectid | grep projectNumber

En Cloud Shell, obtén el número de tu proyecto.

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

En Cloud Shell, establece el número de tu proyecto.

projectnumber=YOUR-PROJECT-Number

En Cloud Shell, crea una cuenta de servicio para AI Platform. Omite este paso si ya tienes una cuenta de servicio en tu proyecto.

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

Dentro de Cloud Shell, actualiza la cuenta del agente de servicio con el rol compute.networkAdmin.

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

Dentro de Cloud Shell, actualiza la cuenta del agente de servicio con el rol dns.peer

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

Actualización de la cuenta de servicio predeterminada

Habilita la API de Compute Engine y otorga acceso a tu cuenta de servicio predeterminada a Vertex AI. Ten en cuenta que el cambio de acceso puede tardar un poco en propagarse.

En Cloud Shell, actualiza la cuenta de servicio predeterminada con el rol aiplatform.user

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

En Cloud Shell, actualiza la cuenta de servicio predeterminada con el rol storage.admin

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

En Cloud Shell, actualiza la cuenta de servicio predeterminada con el rol storage.admin

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

12. Habilita Tcpdump

Para validar la conectividad IP desde Vertex AI Pipelines, podemos usar TCPDUMP. Esto nos permitirá observar la comunicación que se origina en la subred de la vinculación de red de PSC, 192.168.10.0/28, cuando se invoca la solicitud get de Vertex AI Pipelines a la VM, class-e-vm.demo.com (240.0.0.0/4).

Desde Cloud Shell, establece una conexión SSH con la VM de proxy.

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

Desde el SO de la VM del proxy, ejecuta el filtrado de tcpdump en la VM de clase E y en la subred de la conexión de red de PSC.

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

Abre una nueva pestaña de Cloud Shell, actualiza la variable de tu proyecto y accede con SSH a class-e-vm.

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

Desde el SO de la VM de clase E, ejecuta el filtrado de tcpdump en la subred de proxy-vm.

sudo tcpdump -i any net 10.10.10.0/28 -nn

13. Implementa un trabajo de Vertex AI Pipelines

En la siguiente sección, crearás un notebook para realizar un wget exitoso desde Vertex AI Pipelines al proxy explícito. Esto te permite acceder a VMs que no son RFC 1918, como class-e-vm. No se requiere un proxy explícito para que Vertex AI Pipelines acceda a rfc1918-vm, ya que su destino es una dirección IP RFC 1918.

Ejecuta el trabajo de entrenamiento en la instancia de Vertex AI Workbench.

  1. En la consola de Google Cloud, ve a la pestaña Instancias en la página de Vertex AI Workbench.
  2. Junto al nombre de la instancia de Vertex AI Workbench (workbench-tutorial), haz clic en Open JupyterLab. Tu instancia de Vertex AI Workbench abre JupyterLab.
  3. Selecciona Archivo > Nuevo > Notebook.
  4. Selecciona Kernel > Python 3.

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

# 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

En tu notebook de JupyterLab, crea una celda nueva, actualiza y ejecuta lo siguiente. Asegúrate de actualizar PROJECT_ID con los detalles de tu entorno.

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)

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

# 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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta la siguiente configuración. Ten en cuenta los siguientes aspectos destacados:

  • proxy_server = "http://proxy-vm.demo.com:8888" El FQDN está asociado con la VM de proxy implementada en la VPC del consumidor. Usaremos la interconexión de DNS para resolver el FQDN en un paso posterior.
%%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)

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

%%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"]

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente. Ignora el error (gcloud.builds.submit) si está presente.

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

En tu notebook de JupyterLab, crea y ejecuta la siguiente celda. Ten en cuenta los siguientes aspectos destacados:

  • El intercambio de tráfico de DNS a las VPC de consumidor se configura con dnsPeeringConfigs (dnsPeeringConfigs) para el nombre de dominio demo.com.
  • El proxy explícito, definido como la variable PROXY_VM_IP, es proxy-vm.demo.com. La resolución se controla a través del intercambio de tráfico de DNS dentro de la VPC del consumidor.
  • El puerto 8888 es el puerto de escucha (predeterminado) configurado en tinyproxy.
  • Wget a class-e-vm-demo.com se resuelve a través del intercambio de tráfico de DNS.
  • El código especifica el "psc-network-attachment" para Vertex, lo que le permite utilizar la subred de adjunto de red para implementar dos instancias de la interfaz de 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))

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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)

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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)

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

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

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

# 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. Validación de la interfaz de PSC

También puedes ver las IPs de la vinculación de red que usa Vertex AI Pipelines. Para ello, navega a la siguiente ubicación:

Servicios de red → Private Service Connect → Adjunto de red → psc-network-attachment

Selecciona el proyecto de usuario (el nombre del proyecto termina en -tp).

f47150235fedb8ce.png

El campo destacado indica la dirección IP que usa Vertex AI Pipelines desde el adjunto de red de PSC.

39e7b251aeb4f191.png

15. Validación de Cloud Logging

El trabajo de Vertex AI Pipelines tardará aproximadamente 14 minutos en ejecutarse la primera vez. Las ejecuciones posteriores serán mucho más cortas. Para validar que el resultado sea correcto, haz lo siguiente:

Navega a Vertex AI → Entrenamiento → Trabajos personalizados

Selecciona el trabajo personalizado ejecutado

a9be0395c842aa6f.png

Selecciona Ver registros.

53e30765ba5827f3.png

Una vez que Cloud Logging esté disponible, selecciona Ejecutar consulta (Run Query) que genera la selección destacada a continuación, lo que confirma que se realizó correctamente un wget desde Vertex AI Pipelines a la VM de clase E.

f2c5d9fdf5cc8bed.png

3b3788603bb433ee.png

16. Validación de TCPDump

Revisemos el resultado de TCPDUMP que valida aún más la conectividad a las instancias de procesamiento:

Desde proxy-vm, observa el HTTP GET y el 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

Desde class-e-vm, observa el HTTP GET y el 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. Limpia

Desde Cloud Shell, borra los componentes del instructivo.

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. Felicitaciones

¡Felicitaciones! Configuraste y validaste correctamente una interfaz de Private Service Connect con Vertex AI Pipelines.

Creaste la infraestructura del consumidor y agregaste un adjunto de red que permitió al productor crear una VM con varias NIC para conectar la comunicación entre el consumidor y el productor. Aprendiste a crear el intercambio de tráfico de DNS mientras implementabas un proxy explícito en la red de VPC del consumidor que permitía la conectividad a la instancia de VM de clase E a la que no se puede acceder directamente desde Vertex.

Cosmopup cree que los instructivos son increíbles.

c911c127bffdee57.jpeg

¿Qué sigue?

Lecturas y videos adicionales

Documentos de referencia