Déploiement de modèles de conteneurs personnalisés sur vertex ai : un guide de production

Un guide sur la construction de déploiements de modèles ml sécurisés, évolutifs et conformes au rgpd sur vertex ai, en tirant parti de terraform, des contrôles de service vpc et d'une surveillance avancée dans les régions de l'ue.

Déploiement de modèles de conteneurs personnalisés sur vertex ai : un guide de production
TL;DR

Un guide sur la construction de déploiements de modèles ml sécurisés, évolutifs et conformes au rgpd sur vertex ai, en tirant parti de terraform, des contrôles de service vpc et d'une surveillance avancée dans les régions de l'ue.

Création de points de terminaison ml sécurisés et évolutifs avec vertex ai : un guide pour les praticiens de l'ue

Lorsque je crée des solutions d'apprentissage automatique pour la production, je ne pense pas seulement à faire inférer un modèle ; je pense à l'ensemble du cycle de vie : sécurité, évolutivité, observabilité et, de plus en plus, conformité réglementaire. Pour ceux d'entre nous qui opèrent au sein de l'union européenne, des considérations supplémentaires comme la résidence des données et la conformité au rgpd ne sont pas facultatives – elles sont primordiales. C'est pourquoi je me suis plongé dans vertex ai de google cloud, une plateforme gérée qui répond efficacement à ces défis, en particulier pour les modèles de conteneurs personnalisés.

Dans ce guide, je vous expliquerai comment je déploie un modèle pytorch ou tensorflow personnalisé à l'aide du registre de modèles et des points de terminaison de prédiction de vertex ai. Mon objectif est de vous montrer comment créer une image de conteneur prête pour la production, enregistrer votre modèle et le déployer sur un point de terminaison privé sécurisé avec les contrôles de service vpc. Nous aborderons également la configuration de l'auto-mise à l'échelle, la répartition du trafic pour les versions canary et la mise en place d'une surveillance complète avec cloud logging et la surveillance des modèles vertex ai. Je mettrai l'accent sur une perspective européenne tout au long, en utilisant des régions comme europe-west1 et europe-west4 pour répondre aux exigences de résidence des données et en discutant des implications du rgpd et de l'eu chips act pour les stratégies d'inférence cloud. À la fin, vous aurez l'expertise nécessaire pour déployer et gérer vos modèles personnalisés sur vertex ai en toute confiance, en vous assurant qu'ils sont sécurisés, performants et conformes.

Prérequis

Avant de commencer, assurez-vous que votre environnement local et votre projet google cloud sont configurés. Je suppose que vous avez :

  • projet google cloud : avec la facturation activée.
  • gcloud cli : installé et configuré (version 460.0.0 ou supérieure).
  • docker : desktop ou engine installé.
  • python : 3.12+ et pip.
  • terraform cli : installé (version 1.7.0 ou supérieure).
  • compréhension de base : des concepts d'apprentissage automatique, de docker et de gcp.

Outils que j'utiliserai

  • gcloud cli
  • docker
  • python 3.12+
  • terraform cli
  • google cloud sdk pour python (google-cloud-aiplatform)

Pour commencer : préparation de mon environnement

Avant de me lancer dans le déploiement, je m'assure toujours que mon environnement google cloud est préparé et que ma machine locale dispose des outils nécessaires. Pour ce guide, je travaille avec un projet google cloud où la facturation est activée et mon gcloud cli est authentifié. Toutes les ressources que nous provisionnerons seront dans des régions européennes pour s'aligner sur nos objectifs de conformité ue.

Configuration du projet gcp

Tout d'abord, je confirme que ma configuration gcloud pointe vers mon projet et ma région cibles. Je me base généralement sur europe-west4 pour mes déploiements ue.

gcloud config set project $(gcloud config get-value project)
gcloud config set region europe-west4
gcloud auth application-default login

Autorisations iam requises

Le compte de service que j'utilise pour les opérations terraform et gcloud a besoin de rôles iam spécifiques. Pour la configuration initiale, roles/owner est souvent utilisé, mais pour la production, appliquez le principe du moindre privilège, en utilisant une combinaison des éléments suivants :

  • `roles/resourcemanager.projectiamadmin
*

roles/serviceusage.serviceusageadmin

*

roles/compute.networkadmin

*

roles/aiplatform.admin

*

roles/artifactregistry.admin

*

roles/storage.admin

*

roles/logging.configwriter

*

roles/monitoring.editor

*

roles/accesscontextmanager.policyadmin`

Environnement python

Pour garder mes dépendances propres et isolées, je crée et active toujours un environnement virtuel python dédié pour chaque projet. Cela évite les conflits et assure la reproductibilité.

python3.12 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install google-cloud-aiplatform==1.42.0 google-cloud-storage==2.10.0 flask==3.0.3 gunicorn==22.0.0 transformers==4.38.2 torch==2.2.1 sentencepiece==0.1.99

Construction : les étapes de mise en œuvre

Étape 1 : amorçage de l'infrastructure gcp avec terraform

Ma première étape consiste à provisionner l'infrastructure à l'aide de l'infrastructure en tant que code. Pour cela, j'utilise terraform. Cela m'aide à garantir la reproductibilité, à maintenir le contrôle de version et à tout conserver dans la région ue que j'ai choisie. Je configure l'activation de l'api du projet, un réseau vpc personnalisé, un connecteur d'accès vpc sans serveur, un compte de service dédié pour vertex ai et un référentiel artifact registry. Ces composants sont cruciaux pour un déploiement de modèle sécurisé et privé.

Pour les provisionner, je les définirai dans mes fichiers main.tf, variables.tf et terraform.tfvars.

# main.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_project_service" "api_services" {
  for_each = toset([
    "artifactregistry.googleapis.com",
    "compute.googleapis.com",
    "containerregistry.googleapis.com", # Pour la compatibilité ascendante avec docker.
    "aiplatform.googleapis.com",
    "vpcaccess.googleapis.com",
    "cloudbuild.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "accesscontextmanager.googleapis.com", # Pour les contrôles de service vpc
    "logging.googleapis.com",
    "monitoring.googleapis.com"
  ])
  service = each.key
  project = var.project_id
  disable_on_destroy = false
}

resource "google_compute_network" "vpc_network" {
  project = var.project_id
  name    = "vertex-ai-custom-vpc"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "vpc_subnetwork" {
  project       = var.project_id
  name          = "vertex-ai-custom-subnet"
  ip_cidr_range = "10.10.0.0/20"
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

resource "google_vpc_access_connector" "connector" {
  project = var.project_id
  name    = "vertex-ai-connector"
  region  = var.region
  ip_cidr_range = "10.8.0.0/28"
  network = google_compute_network.vpc_network.id

  depends_on = [
    google_project_service.api_services["vpcaccess.googleapis.com"]
  ]
}

resource "google_service_account" "vertex_sa" {
  project      = var.project_id
  account_id   = "vertex-ai-model-deployer"
  display_name = "Compte de service pour le déploiement de modèles vertex ai"
}

resource "google_project_iam_member" "vertex_sa_permissions" {
  for_each = toset([
    "roles/aiplatform.user",
    "roles/artifactregistry.writer",
    "roles/storage.objectadmin",
    "roles/logging.logwriter",
    "roles/monitoring.metricwriter",
    "roles/compute.networkuser" # Requis pour l'accès vpc
  ])
  project = var.project_id
  role    = each.key
  member  = "serviceAccount:${google_service_account.vertex_sa.email}"
}

resource "google_artifact_registry_repository" "model_repo" {
  project       = var.project_id
  location      = var.region
  repository_id = "vertex-ai-model-images"
  description   = "Images docker pour le service de modèles personnalisés vertex ai"
  format        = "DOCKER"

  depends_on = [
    google_project_service.api_services["artifactregistry.googleapis.com"]
  ]
}
# variables.tf
variable "project_id" {
  description = "l'id du projet google cloud."
  type        = string
}

variable "region" {
  description = "la région gcp pour les déploiements (par exemple, europe-west4)."
  type        = string
  default     = "europe-west4"
}

variable "access_policy_number" {
  description = "le numéro de la politique d'accès de votre organisation pour les contrôles de service vpc. trouvez-le en utilisant `gcloud access-context-manager policies list --organization organization_id`."
  type        = string
}

variable "model_display_name" {
  description = "nom d'affichage pour le modèle vertex ai."
  type        = string
  default     = "sentimentanalysismodel"
}

variable "vertex_model_resource_name" {
  description = "nom complet de la ressource du modèle vertex ai de l'étape 3 (gcloud ai models list --format='value(name)')."
  type        = string
}
# terraform.tfvars (exemple)
project_id           = "my-gcp-project-id"
region               = "europe-west4"
access_policy_number = "123456789"
model_display_name   = "sentimentanalysismodel"
vertex_model_resource_name = "projects/your_project_number/locations/europe-west4/models/your_model_id"

Après avoir configuré ces fichiers, j'exécute terraform pour provisionner les ressources :

terraform init
terraform plan
terraform apply --auto-approve

Résultat attendu :

Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

Dépannage : * error 403: the caller does not have permission : je vérifierais que mon utilisateur authentifié gcloud dispose de roles/owner ou des rôles iam spécifiques que j'ai listés dans les prérequis. * api not enabled : je vérifierais que toutes les ressources google_project_service requises sont correctement listées et activées dans mon main.tf.

Étape 2 : développement et conteneurisation de mon serveur de modèles personnalisés

Ensuite, je dois empaqueter mon modèle et sa logique de service dans un conteneur docker léger et optimisé. J'utilise un modèle d'analyse des sentiments pré-entraîné de hugging face (distilbert-base-uncased-finetuned-sst-2-english) servi via une application flask. L'essentiel est de garder l'image petite et d'assurer des temps de démarrage rapides pour une mise à l'échelle efficace.

Tout d'abord, je télécharge les artefacts du modèle localement dans un répertoire model/ :

# download_model.py
from transformers import pipeline

# charger un modèle d'analyse des sentiments pré-entraîné
sentiment_pipeline = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")

# enregistrer le modèle et le tokenizer
sentiment_pipeline.model.save_pretrained("model/")
sentiment_pipeline.tokenizer.save_pretrained("model/")
print("model saved to ./model/")
python download_model.py

Puis, je crée mon application flask predict.py et son dockerfile :

# predict.py
import os
from flask import flask, request, jsonify
from transformers import pipeline

app = flask(__name__)

# charger le modèle globalement pour éviter de le recharger à chaque requête
def load_model():
    model_path = os.environ.get('aip_model_dir', './model/')
    print(f"loading model from: {model_path}")
    return pipeline("sentiment-analysis", model=model_path)

sentiment_pipeline = load_model()

@app.route('/ping', methods=['get'])
def ping():
    return jsonify({'status': 'healthy'})

@app.route('/predict', methods=['post'])
def predict():
    try:
        instances = request.json['instances']
        if not isinstance(instances, list):
            return jsonify({'error': 'instances must be a list of strings'}), 400

        results = sentiment_pipeline(instances)
        return jsonify({'predictions': results})
    except exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    # utiliser gunicorn en production pour la robustesse
    app.run(host='0.0.0.0', port=os.environ.get('aip_http_port', 8080))
# dockerfile
# utiliser une image python 3.12 slim pour une taille réduite
from python:3.12-slim-bookworm as builder

# installer les dépendances de construction pour transformers
run apt-get update && apt-get install -y --no-install-recommends \n    build-essential \n    curl \n    && rm -rf /var/lib/apt/lists/*

# définir le répertoire de travail
workdir /app

# copier le fichier requirements et installer les dépendances
copy requirements.txt .
run pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt

# image finale
from python:3.12-slim-bookworm

# installer les dépendances d'exécution à partir des roues
workdir /app
copy --from=builder /app/wheels /app/wheels
copy --from=builder /usr/lib/python3.12/site-packages /usr/lib/python3.12/site-packages
run pip install --no-cache-dir --no-index --find-links=/app/wheels -r requirements.txt

# copier le code de l'application et le modèle
copy predict.py .
copy model/ ./model/

# exposer le port que vertex ai attend
env aip_http_port=8080
expose 8080

# commande pour exécuter le serveur de prédiction à l'aide de gunicorn
entrypoint ["gunicorn", "--bind", "0.0.0.0:8080", "predict:app", "--timeout", "90", "--workers", "2"]
# requirements.txt
flask==3.0.3
gunicorn==22.0.0
transformers==4.38.2
torch==2.2.1
sentencepiece==0.1.99 # Requis par certains modèles hugging face

Maintenant, je construis et pousse l'image docker vers mon référentiel artifact registry :

project_id=$(gcloud config get-value project)
region="europe-west4"
repo_name="vertex-ai-model-images"
image_name="sentiment-model-server:v1.0.0"

docker build -t ${region}-docker.pkg.dev/${project_id}/${repo_name}/${image_name} .

gcloud auth configure-docker ${region}-docker.pkg.dev
docker push ${region}-docker.pkg.dev/${project_id}/${repo_name}/${image_name}

export container_image_uri=${region}-docker.pkg.dev/${project_id}/${repo_name}/${image_name}
echo "container image pushed: ${container_image_uri}"

Résultat attendu :

the push refers to repository [europe-west4-docker.pkg.dev/your-gcp-project-id/vertex-ai-model-images/sentiment-model-server]
... (layers pushed) ...
v1.0.0: digest: sha256:... size: ...
container image pushed: europe-west4-docker.pkg.dev/your-gcp-project-id/vertex-ai-model-images/sentiment-model-server:v1.0.0

Dépannage : * denied: permission denied for repository : je m'assurerais que le compte de service ou l'utilisateur authentifié dispose du rôle artifact registry writer. * docker build fails : je vérifierais requirements.txt pour les fautes de frappe ou les dépendances manquantes et m'assurerais que build-essential est correctement installé à l'étape du constructeur.

Optimisation des builds de conteneurs pour le cloud

Alors que `from python:3.12-slim-bookworm` est un excellent point de départ pour une image légère, dans les environnements cloud de production plus importants, j'envisagerais souvent d'utiliser des images de base optimisées pour gpu (par exemple, de ngc de nvidia) ou les mécanismes de mise en cache de cloud build pour des builds plus rapides et plus reproductibles. Les commandes `apt-get install` dans le dockerfile doivent toujours être suivies de `rm -rf /var/lib/apt/lists/*` pour minimiser la taille de l'image finale en effaçant les caches de paquets, ce qui est essentiel pour les temps de démarrage à froid et les coûts.

Étape 3 : enregistrement du modèle auprès du registre de modèles vertex ai

Le registre de modèles vertex ai est mon centre centralisé pour le stockage et le versionnement des modèles ml. L'enregistrement de mon image de conteneur et des artefacts de modèle associés ici permet à vertex ai de gérer le cycle de vie du modèle et de simplifier les déploiements. Pour cet exemple, j'ai intégré les poids du modèle directement dans l'image du conteneur pour des raisons de simplicité. Pour les modèles plus volumineux, je les téléchargerais généralement sur cloud storage (gcs) et ferais en sorte que le conteneur les récupère au démarrage.

project_id=$(gcloud config get-value project)
region="europe-west4"
model_display_name="sentimentanalysismodel"

# enregistrer le modèle auprès du registre de modèles vertex ai
gcloud ai models upload \n  --project=${project_id} \n  --region=${region} \n  --display-name=${model_display_name} \n  --container-image-uri=${container_image_uri} \n  --container-command='["gunicorn", "--bind", "0.0.0.0:8080", "predict:app", "--timeout", "90", "--workers", "2"]' \n  --container-predict-route="/predict" \n  --container-health-route="/ping" \n  --container-ports=8080 \n  --description="modèle d'analyse des sentiments déployé via un conteneur personnalisé"

# l'id réel du modèle est un long nombre. j'en aurai besoin pour terraform.
# je stockerai le nom complet de la ressource (y compris le projet et l'emplacement) pour une utilisation ultérieure.
export model_resource_name=$(gcloud ai models list --project=${project_id} --region=${region} --filter="displayname=${model_display_name}" --format="value(name)")
echo "modèle enregistré avec le nom de ressource : ${model_resource_name}"

Résultat attendu :

model [projects/your_project_number/locations/europe-west4/models/your_model_id] uploaded.
... (details) ...
model registered with resource name: projects/your_project_number/locations/europe-west4/models/your_model_id

Dépannage : * 403 permission denied : je m'assurerais que le compte de service dispose de roles/aiplatform.user. * invalid image uri : je vérifierais la variable container_image_uri pour l'exactitude.

Étape 4 : déploiement d'un point de terminaison de prédiction privé avec les contrôles de service vpc

Pour assurer une sécurité maximale et prévenir l'exfiltration de données, je déploie toujours mes modèles sur un point de terminaison vertex ai au sein d'un périmètre vpc service controls. Cela isole mes données et mes ressources, les rendant inaccessibles de l'extérieur de mon périmètre défini. Le point de terminaison utilisera également une ip privée pour les requêtes d'inférence, en gardant le trafic strictement au sein de mon vpc. C'est une étape critique pour la conformité au rgpd et la sécurité globale des données dans l'ue.

J'ajouterai les ressources suivantes à mon main.tf pour définir le périmètre des contrôles de service vpc et le point de terminaison vertex ai. Le modèle lui-même est référencé par le nom complet de la ressource de l'étape 3 (var.vertex_model_resource_name) lorsque j'exécute gcloud ai endpoints deploy-model après que terraform ait créé le point de terminaison.

# main.tf (ajouter au fichier terraform précédent)
#
# le fournisseur hashicorp google inclut google_vertex_ai_endpoint et les contrôles de service vpc,
# mais il n'y a pas de source de données nommée google_ai_models et pas de ressource google_vertex_ai_endpoint_model.
# après que terraform ait créé le point de terminaison, déployez le modèle de l'étape 3 avec gcloud (bloc shell ci-dessous).

resource "google_access_context_manager_service_perimeter" "vertex_ai_perimeter" {
  name        = "accesspolicies/${var.access_policy_number}/serviceperimeters/vertex_ai_perimeter_v1"
  title       = "vertex-ai-perimeter-v1"
  description = "périmètre des contrôles de service vpc pour vertex ai"
  perimeter_type = "regular"

  status {
    restricted_services = [
      "aiplatform.googleapis.com",
      "artifactregistry.googleapis.com",
      "storage.googleapis.com",
      "cloudbuild.googleapis.com" # Requis si cloud build est utilisé dans le périmètre
    ]
    vpc_accessible_services {
      enable_restriction = true
      allowed_services   = [
        "restricted_services"
      ]
    }
  }

  # les politiques d'entrée/sortie peuvent être définies ici pour un contrôle précis
  # par exemple, pour autoriser des comptes de service spécifiques ou des plages d'ip à interagir avec les ressources à l'intérieur du périmètre.
  # policy_data {
  #   ingress_policies {
  #     ingress_from {
  #       sources {
  #         resource = "projects/${var.project_id}"
  #       }
  #       identities = [
  #         "serviceaccount:${google_service_account.vertex_sa.email}"
  #       ]
  #     }
  #     ingress_to {
  #       resources = [
  #         "projects/${var.project_id}"
  #       ]
  #       operations {
  #         service_name = "aiplatform.googleapis.com"
  #         method_selectors {
  #           method = "*"
  #         }
  #       }
  #     }
  #   }
  # }

  depends_on = [
    google_project_service.api_services["accesscontextmanager.googleapis.com"]
  ]
}

resource "google_vertex_ai_endpoint" "sentiment_endpoint" {
  project         = var.project_id
  location        = var.region
  display_name    = "sentiment-analysis-endpoint"
  description     = "point de terminaison pour le modèle d'analyse des sentiments via un conteneur personnalisé"
  network         = google_compute_network.vpc_network.id # associer au réseau vpc
  service_account = google_service_account.vertex_sa.email

  depends_on = [
    google_access_context_manager_service_perimeter.vertex_ai_perimeter, # s'assurer que le périmètre existe
    google_project_iam_member.vertex_sa_permissions["roles/compute.networkuser"]
  ]
}

Après que terraform apply ait créé le point de terminaison, déployez le modèle enregistré (id numérique) sur ce point de terminaison :

project_id=$(gcloud config get-value project)
region="europe-west4"
# défini à partir de l'exportation de l'étape 3 ou de terraform.tfvars (variable vertex_model_resource_name), par exemple :
# export vertex_model_resource_name="projects/123/locations/europe-west4/models/4567890123456789012"
: "${vertex_model_resource_name:?défini sur le nom complet du modèle de l'étape 3}"

endpoint_num="$(gcloud ai endpoints list --project="${project_id}" --region="${region}" \n  --filter="displayname=sentiment-analysis-endpoint" --format="value(name)" | awk -f/ '{print $nf}')"
model_num="$(printf '%s' "${vertex_model_resource_name}" | awk -f/ '{print $nf}')"
service_account_email="vertex-ai-model-deployer@${project_id}.iam.gserviceaccount.com"

gcloud ai endpoints deploy-model "${endpoint_num}" \n  --project="${project_id}" \n  --region="${region}" \n  --model="${model_num}" \n  --display-name="sentiment-model-v1" \n  --machine-type=n1-standard-4 \n  --min-replica-count=1 \n  --max-replica-count=2 \n  --traffic-split=0=100 \n  --service-account="${service_account_email}"

Définissez vertex_model_resource_name sur var.vertex_model_resource_name (à partir de terraform.tfvars) ou sur le model_resource_name que vous avez capturé à l'étape 3.

Avant d'exécuter terraform, assurez-vous que le modèle de l'étape 3 a été téléchargé avec succès. Ensuite, j'applique ces modifications :

terraform apply --auto-approve

Résultat attendu :

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
... (sortie montrant la création du point de terminaison) ...

Dépannage : * 403 permission denied by vpc service controls : je m'assurerais que mon compte de service est soit dans le périmètre, soit qu'il a des règles d'entrée/sortie explicites autorisant l'accès. Je vérifierais également que tous les services pertinents (aiplatform.googleapis.com, storage.googleapis.com, artifactregistry.googleapis.com) sont restreints dans le périmètre. * invalid network configuration : je vérifierais que google_vertex_ai_endpoint.sentiment_endpoint.network référence correctement l'id de mon réseau vpc. * endpoint does not exist ou model not found : cela signifie généralement que l'id du point de terminaison ou du modèle utilisé avec gcloud ai endpoints deploy-model était incorrect, ou que gcloud ai models upload à l'étape 3 n'a pas été terminé avant le déploiement.

Naviguer dans la complexité des contrôles de service vpc

Les contrôles de service vpc améliorent considérablement la sécurité, mais ils ajoutent une couche de complexité. Le débogage des problèmes d'accès peut être difficile. Je recommande de commencer par un ensemble minimal de services restreints et d'en ajouter progressivement. Testez toujours minutieusement les modèles d'accès de votre application après avoir implémenté vpc sc, car les services externes ou même les commandes `gcloud` peuvent être affectés s'ils ne sont pas correctement configurés avec des niveaux d'accès.

Étape 5 : configuration de l'autoscaling et de la gestion du trafic

La gestion du trafic et la mise à l'échelle efficace sont essentielles pour tout déploiement en production. L'autoscaling et la répartition du trafic de vertex ai sont configurés sur le modèle déployé (via gcloud ou l'api rest), et non via une ressource terraform google_vertex_ai_endpoint_model – ce type de ressource ne fait pas partie du fournisseur google de hashicorp. Après le déploiement, j'ajuste les répliques (et éventuellement les cibles métriques d'autoscaling) avec gcloud ai endpoints mutate-deployed-model, et j'ajuste la répartition du trafic lorsque j'ajoute un deuxième déploiement au même point de terminaison.

project_id=$(gcloud config get-value project)
region="europe-west4"
endpoint_num="$(gcloud ai endpoints list --project="${project_id}" --region="${region}" \n  --filter="displayname=sentiment-analysis-endpoint" --format="value(name)" | awk -f/ '{print $nf}')"
deployed_model_id="$(gcloud ai endpoints describe "${endpoint_num}" --project="${project_id}" --region="${region}" \n  --format="value(deployedmodels[0].id)")"

gcloud ai endpoints mutate-deployed-model "${endpoint_num}" \n  --project="${project_id}" \n  --region="${region}" \n  --deployed-model-id="${deployed_model_id}" \n  --min-replica-count=1 \n  --max-replica-count=10

Pour les déploiements canary, je déploie une autre version du modèle sur le même point de terminaison, puis je définis la carte de trafic du point de terminaison (par exemple 90 % / 10 %) à l'aide de gcloud ai endpoints update ou de l'api — voir la documentation de vertex ai pour la répartition du trafic sur les points de terminaison à déploiements multiples. Les métriques d'autoscaling de prédiction en ligne utilisent des noms comme aiplatform.googleapis.com/prediction/online/cpu/utilization (voir la référence d'autoscaling de google).

Résultat attendu : les nombres de répliques se mettent à jour sans terraform ; vérifiez dans la console cloud ou avec gcloud ai endpoints describe.

Étape 6 : implémentation d'une surveillance et d'une journalisation complètes

Une surveillance et une journalisation robustes sont non négociables pour l'excellence opérationnelle, et encore plus pour la conformité au rgpd. Je configurerai cloud logging pour capturer toutes les requêtes et réponses de prédiction, en dirigeant ces journaux vers un récepteur régional. De plus, j'activerai la surveillance des modèles vertex ai pour détecter la dérive des données, la dérive des concepts et la dérive d'attribution, garantissant que mon modèle reste précis et fonctionne comme prévu au fil du temps. Pour le rgpd, il est vital que mes journaux soient conservés dans les régions de l'ue avec des politiques appropriées.

# main.tf (ajouter au fichier terraform précédent)
# les tâches de surveillance des modèles sont créées via la console, gcloud ou l'api vertex ai. le fournisseur hashicorp
# google ne définit pas google_vertex_ai_model_monitoring_job. ci-dessous : bucket de journaux ue + récepteur.

resource "google_logging_project_sink" "vertex_ai_log_sink" {
  project = var.project_id
  name    = "vertex-ai-audit-log-sink"
  # je dirige les journaux vers un bucket gcs, en m'assurant qu'il se trouve dans une région ue.
  destination = "storage.googleapis.com/${google_storage_bucket.log_bucket.name}"
  filter      = "resource.type=("aiplatform.googleapis.com/endpoint" or "aiplatform.googleapis.com/model")"

  depends_on = [
    google_project_service.api_services["logging.googleapis.com"],
    google_project_service.api_services["storage.googleapis.com"]
  ]
}

resource "google_storage_bucket" "log_bucket" {
  project       = var.project_id
  name          = "vertex-ai-log-bucket-${var.project_id}"
  location      = upper(var.region) # par exemple, europe-west4
  force_destroy = false
  uniform_bucket_level_access = true

  # je définis une politique de rétention pour la conformité au rgpd, par exemple, 365 jours.
  retention_policy {
    is_locked        = false
    retention_period = 31536000 # 365 jours en secondes
  }
}

data "google_project" "project" {
  project_id = var.project_id
}

# accorder la permission au compte de service de journalisation d'écrire dans le bucket
resource "google_storage_bucket_iam_member" "log_bucket_iam" {
  bucket = google_storage_bucket.log_bucket.name
  role   = "roles/storage.objectcreator"
  member = "serviceaccount:service-${data.google_project.project.number}@gcp-sa-logging.iam.gserviceaccount.com"
}

Surveillance des modèles : je crée une tâche de surveillance des modèles dans la console google cloud (vertex ai → points de terminaison → surveillance) ou avec gcloud ai model-monitoring-jobs create, en utilisant des données de base et un schéma dans des buckets gcs ue. Je transmets l'id du modèle déployé à partir de gcloud ai endpoints describe. Le bloc terraform supprimé utilisait un type de ressource qui n'existe pas dans le fournisseur hashicorp.

Remarque sur les schémas et les références : la surveillance compare le trafic en direct à un ensemble de données de référence et à un schéma. Gardez les deux dans un bucket ue pour la résidence ; ne vous fiez pas aux uri d'échantillon uniquement américains pour les références de production.

Maintenant, j'exécute terraform à nouveau :

terraform apply --auto-approve

Résultat attendu :

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Dépannage : * model monitoring job failed : je vérifierais que le gcs_path pour le schéma et les données de base est correct et accessible par le compte de service vertex ai. Je m'assurerais également que le deployed_model_id correspond à un déploiement actif sur le point de terminaison. * permission denied for logging sink : je m'assurerais que le compte de service cloud logging (service-project_number@gcp-sa-logging.iam.gserviceaccount.com) dispose des autorisations storage object creator sur le bucket de destination.

Étape 7 : validation de la résidence des données ue et de la conformité

Pour toute organisation basée dans l'ue, assurer la résidence des données est crucial pour la conformité au rgpd et l'adhésion à des initiatives comme l'eu chips act. L'eu chips act met l'accent sur le renforcement de l'écosystème des semi-conducteurs de l'ue, ce qui a un impact sur la façon dont les organisations pourraient envisager l'inférence sur site par rapport à l'inférence cloud pour les données sensibles. En déployant des ressources exclusivement dans les régions de l'ue, je garde le contrôle sur l'emplacement des données. J'ai tout configuré dans europe-west4, mais europe-west1 fonctionnerait également. Je vérifierai rapidement les emplacements à l'aide des commandes gcloud :

project_id=$(gcloud config get-value project)
region="europe-west4"

echo "vérification de l'emplacement de artifact registry..."
gcloud artifacts repositories describe vertex-ai-model-images --location=${region} --project=${project_id} --format="value(location)"

echo "vérification de l'emplacement du point de terminaison vertex ai..."
gcloud ai endpoints describe sentiment-analysis-endpoint --region=${region} --project=${project_id} --format="value(location)"

echo "vérification de l'emplacement du bucket de journaux..."
gcloud storage buckets describe gs://vertex-ai-log-bucket-${project_id} --format="value(location)"

echo "vérification de l'emplacement du connecteur d'accès vpc..."
gcloud vpc-access connectors describe vertex-ai-connector --region=${region} --project=${project_id} --format="value(location)"

Résultat attendu :

verifying artifact registry location...
europe-west4
verifying vertex ai endpoint location...
europe-west4
verifying log bucket location...
europe-west4
verifying vpc access connector location...
europe-west4

Cette vérification confirme que mon infrastructure respecte les exigences de résidence des données de l'ue, ce qui positionne mes déploiements ml pour la conformité au rgpd.

Étape 8 : effectuer une prédiction et observer les résultats

Le modèle étant déployé et la surveillance configurée, il est temps de lancer une requête de prédiction d'échantillon pour tester le point de terminaison et observer les résultats dans cloud logging. Cela démontre le flux d'inférence de bout en bout.

# predict_client.py
import os
from google.cloud import aiplatform

project_id = os.environ.get('project_id')
region = os.environ.get('region', 'europe-west4')
endpoint_name = os.environ.get('endpoint_name', 'sentiment-analysis-endpoint')

def predict_text_sentiment(project: str, location: str, endpoint_name: str, text_instances: list):
    aiplatform.init(project=project, location=location)

    # je filtre par display_name pour m'assurer d'obtenir le bon point de terminaison
    endpoints = aiplatform.endpoint.list(filter=f"display_name="{endpoint_name}"")
    if not endpoints:
        raise valueerror(f"endpoint with display_name {endpoint_name} not found.")
    endpoint = endpoints[0]

    # le format de la requête dépend de l'implémentation de la route /predict de mon conteneur
    # pour mon application flask, elle attend {'instances': ["texte1", "texte2"]}
    instances_payload = [{"instances": text_instances}]

    response = endpoint.predict(instances=instances_payload)

    print("réponse de prédiction:")
    for prediction in response.predictions:
        print(prediction)

if __name__ == '__main__':
    # exemples de phrases pour l'analyse des sentiments
    sample_texts = [
        "c'est un produit incroyable, je l'adore !",
        "le service était terrible et je suis très déçu.",
        "c'était une expérience correcte, ni bonne ni mauvaise."
    ]

    print(f"envoi d'une requête de prédiction à {endpoint_name} dans {region} pour le projet {project_id}")
    predict_text_sentiment(project_id, region, endpoint_name, sample_texts)

Je vais exécuter le script de prédiction :

project_id=$(gcloud config get-value project)
region="europe-west4"
endpoint_name="sentiment-analysis-endpoint"

export project_id
export region
export endpoint_name

python predict_client.py

Résultat attendu :

réponse de prédiction:
{'label': 'positive', 'score': 0.9998...}
{'label': 'negative', 'score': 0.9996...}
{'label': 'positive', 'score': 0.8876...} # (neutre pourrait être classé comme légèrement positif ou négatif selon le modèle)

Après avoir exécuté la prédiction, je navigue vers cloud logging dans ma console gcp. Je filtre les journaux par resource.type="aiplatform.googleapis.com/endpoint" et resource.labels.endpoint_id="votre_endpoint_id_depuis_la_sortie_terraform" pour voir mes requêtes et réponses de prédiction. Cela vérifie que mon récepteur de journalisation capture activement les données d'inférence.

Dépannage : * 403 permission denied : je m'assurerais que le compte de service exécutant predict_client.py (mon compte utilisateur si j'utilise gcloud auth application-default login) dispose de roles/aiplatform.user et de l'accès réseau nécessaire s'il n'est pas exécuté au sein du vpc. * valueerror: endpoint with display_name... not found. : je vérifierais les variables endpoint_name et region et m'assurerais que mon point de terminaison a été déployé avec succès.

Tester ma mise en œuvre

Au-delà d'une simple prédiction, je teste toujours minutieusement mon déploiement pour assurer la stabilité, la performance et l'évolutivité.

  1. Test de charge : j'utilise des outils comme apachebench (ab), locust ou jmeter pour simuler des utilisateurs concurrents et vérifier le comportement d'autoscaling. Je surveille toujours l'utilisation du cpu et le nombre de répliques dans cloud monitoring.
# exemple avec apachebench
# installation : sudo apt-get install apache2-utils
# remarque : nécessite un accès externe ou un client au sein de votre vpc pour atteindre le point de terminaison privé.
# pour les points de terminaison privés, cela serait généralement exécuté à partir d'une vm à l'intérieur du même vpc.
# l'url ci-dessous est pour les points de terminaison publics. pour les privés, vous l'adresseriez via son ip interne.
# si vous l'exposez via un équilibreur de charge ou similaire, cette url serait utilisée.
# pour des tests directs à partir d'une vm au sein du vpc, vous utiliseriez une approche différente pour la découverte du point de terminaison.
# pour cet exemple, je suppose un accès externe temporaire pour la démonstration, ou des tests depuis l'intérieur du vpc.
# remplacez endpoint_id par l'id de votre point de terminaison vertex ai.
# vous pouvez obtenir le dns public du point de terminaison si vous n'avez pas restreint l'accès externe :
# gcloud ai endpoints describe sentiment-analysis-endpoint --region=europe-west4 --format="value(publicendpoint.dnsname)"
endpoint_id="$(gcloud ai endpoints list --project=${project_id} --region=${region} --filter="display_name=sentiment-analysis-endpoint" --format="value(endpoints[0].id)")"
endpoint_url="https://europe-west4-aiplatform.googleapis.com/v1/projects/${project_id}/locations/${region}/endpoints/${endpoint_id}:predict"
payload='{"instances": ["c'est une phrase de test."]}'

# exemple : 100 requêtes, 10 concurrentes.
# remarque : cela nécessite que le point de terminaison soit accessible publiquement ou accédé depuis un environnement connecté au vpc.
# si vpc sc restreint l'accès externe, cette commande `ab` échouerait probablement, sauf si elle est exécutée depuis l'intérieur du périmètre.
ab -n 100 -c 10 -t 'application/json' -p <(echo "${payload}") -h "authorization: bearer $(gcloud auth print-access-token)" "${endpoint_url}"
  1. Vérification du déploiement canary : si j'introduis une nouvelle version de modèle avec une petite répartition du trafic, je m'assure que seul le pourcentage spécifié de requêtes est acheminé vers la nouvelle version. J'observe généralement cela en journalisant des identifiants uniques de chaque version de modèle dans mon predict.py ou en examinant les résultats de prédiction si les modèles produisent des résultats distincts.

  2. Alertes de surveillance : je déclenche intentionnellement des conditions pour ma surveillance des modèles vertex ai (par exemple, en envoyant des données qui provoqueraient une dérive) et je confirme que les alertes par e-mail ou pub/sub sont reçues comme configuré.

  3. Examen des journaux : j'inspecte régulièrement cloud logging pour les erreurs, les pics de latence et les résultats de prédiction corrects. Je m'assure que les données sensibles sont traitées conformément à mes politiques rgpd et que la configuration de la journalisation filtre ou masque correctement ce qui est nécessaire.

Considérations de production

Le déploiement en production implique plus que la simple exécution du code. Voici quelques domaines clés sur lesquels je me concentre toujours :

Meilleures pratiques de sécurité

  • contrôles de service vpc : comme je l'ai démontré, utilisez toujours les contrôles de service vpc pour les charges de travail sensibles afin de prévenir l'exfiltration de données. Cela crée un périmètre de sécurité solide autour de vos ressources vertex ai.
  • moindre privilège : accordez au compte de service vertex ai uniquement les rôles iam absolument nécessaires. J'évite roles/editor ou roles/owner pour les déploiements en production.
  • gestion des secrets : stockez les clés api, les informations d'identification ou les paramètres de modèle sensibles dans secret manager, et non directement dans votre image de conteneur ou votre code.
  • sécurité des conteneurs : analysez régulièrement vos images docker pour détecter les vulnérabilités à l'aide d'artifact analysis ou d'outils tiers. Utilisez des images de base minimales comme python:3.12-slim pour réduire la surface d'attaque.
  • gouvernance des modèles : implémentez la signature des modèles (par exemple, en utilisant sigstore/cosign) pour vérifier l'intégrité et l'origine de vos artefacts de modèle. Assurez-vous que l'audit logging complet est activé à toutes les étapes du cycle de vie ml.

Optimisation des performances

  • types de machines : sélectionnez les types de machines appropriés (n1-standard, a2-highgpu, etc.) pour votre charge de travail. Les instances gpu accélèrent considérablement l'inférence pour les grands modèles d'apprentissage profond.
  • optimisation des conteneurs : optimisez votre dockerfile pour la taille et les performances de démarrage à froid. Utilisez des builds multi-étapes, nettoyez les fichiers inutiles et préchargez les modèles en mémoire.
  • traitement par lots : pour les scénarios à haut débit, implémentez le traitement par lots des requêtes dans votre predict.py pour traiter plusieurs inférences en un seul appel, réduisant ainsi la surcharge.
  • mise à l'échelle horizontale : configurez min_replica_count et max_replica_count avec des autoscaling_metric_specs agressifs pour gérer efficacement les fluctuations de trafic.

Considérations d'évolutivité

  • déploiement régional : déployez des modèles dans des régions géographiquement proches de vos utilisateurs pour minimiser la latence, en particulier dans europe-west1 ou europe-west4 pour les utilisateurs de l'ue.
  • service géré : vertex ai est un service géré, gérant la mise à l'échelle de l'infrastructure sous-jacente. Mon objectif passe de la gestion des clusters kubernetes à l'optimisation de mon conteneur et de mon modèle pour l'efficacité.
  • gestion des quotas : je suis toujours conscient des quotas vertex ai et compute engine. Je demande de manière proactive des augmentations si j'anticipe des volumes de trafic très élevés.

Recommandations de surveillance

  • tableaux de bord : je crée des tableaux de bord personnalisés dans cloud monitoring pour visualiser les métriques clés telles que la latence des requêtes, les taux d'erreur, l'utilisation du cpu/gpu et le nombre de répliques.
  • politiques d'alerte : je configure des politiques d'alerte granulaires pour les seuils critiques (par exemple, la latence p99 dépassant 500 ms, le taux d'erreur supérieur à 1 %).
  • analyse des journaux : j'utilise cloud logging avec des exportations bigquery pour une analyse et un audit avancés des journaux.
  • surveillance des modèles : l'utilisation continue de la surveillance des modèles vertex ai pour détecter la dérive des données, la dérive des concepts et la dégradation de la qualité des prédictions est essentielle. Une surveillance proactive des modèles peut réduire le temps moyen de détection de la dégradation des modèles de 70 %, ce qui représente un gain opérationnel important.

Questions fréquentes

q : comment puis-je mettre à jour mon modèle déployé sans interruption de service ?

A : j'y parviens en utilisant la répartition du trafic sur mon point de terminaison vertex ai. Je déploie la nouvelle version du modèle (par exemple, la version 1) sur le même point de terminaison avec 0 % de trafic. Une fois vérifié, je déplace progressivement le trafic (par exemple, 5 %, puis 25 %, puis 100 %) vers la nouvelle version. Cela permet des déploiements canary et une annulation facile en cas de problèmes.

q : quel est le coût de déploiement d'un modèle personnalisé sur vertex ai ?

A : la tarification de vertex ai pour les modèles de conteneurs personnalisés est principalement basée sur le type de machine, l'utilisation de l'accélérateur et le nombre de répliques. Par exemple, un type de machine n1-standard-4 sans gpu coûte environ 0,15 €/heure (0,16 $/heure) en europe-west4. La surveillance des modèles entraîne des coûts supplémentaires, environ 0,01 €/1000 requêtes de prédiction (0,01 $/1000) échantillonnées. Avec un taux de conversion de 1 $ ≈ 0,92 €, un petit point de terminaison n1-standard-4 fonctionnant 24h/24 et 7j/7 avec 1 réplique coûterait environ 109,50 €/mois (119,00 $/mois) pour l'instance, plus les coûts des requêtes. Je me réfère toujours à la page de tarification de vertex ai pour les chiffres les plus récents et les variations régionales spécifiques.

q : puis-je utiliser des gpu avec mon modèle de conteneur personnalisé ?

A : oui, vertex ai prend en charge les types de machines compatibles gpu. Je spécifierais accelerator_type (par exemple, nvidia_tesla_t4) et accelerator_count dans ma machine_spec dans le bloc dedicated_resources de ma ressource terraform google_vertex_ai_endpoint_model. Il est crucial que mon image docker contienne les pilotes gpu et les bibliothèques nécessaires (par exemple, cuda, cudnn, nvidia container toolkit).

q : comment gérer les artefacts de modèles volumineux qui ne rentrent pas dans l'image du conteneur ?

A : pour les modèles de plus de quelques go, je stocke les artefacts de modèles dans un bucket gcs. Mon conteneur personnalisé predict.py télécharge ensuite ces artefacts de gcs vers le répertoire /tmp du conteneur pendant le démarrage du conteneur. Vertex ai fournira automatiquement des informations d'identification pour le compte de service du modèle déployé afin d'accéder à gcs, ce qui simplifie la gestion des accès.

q : quel est l'impact des contrôles de service vpc sur le déploiement et l'accès aux modèles ?

A : les contrôles de service vpc créent un périmètre de sécurité qui restreint le mouvement des données. Les ressources à l'intérieur du périmètre (comme mon point de terminaison vertex ai et mes buckets gcs) ne peuvent communiquer qu'avec d'autres ressources à l'intérieur du même périmètre ou des services explicitement autorisés. Cela signifie que les clients accédant au point de terminaison doivent soit être à l'intérieur du périmètre (par exemple, une vm dans mon vpc), soit bénéficier d'un accès entrant explicitement accordé via un niveau d'accès. Cela améliore considérablement la sécurité des données en empêchant l'accès non autorisé et l'exfiltration de données.

q : quelles sont les implications de l'eu chips act sur les déploiements ml dans le cloud ?

A : l'eu chips act vise à renforcer l'industrie des semi-conducteurs de l'ue. Bien qu'il se concentre principalement sur la fabrication, il a des implications pour le traitement des données et la résilience de la chaîne d'approvisionnement. Pour mes déploiements ml, il m'encourage à considérer où se déroule mon traitement d'inférence. L'utilisation de régions cloud au sein de l'ue, telles que europe-west1 ou europe-west4, garantit que les données restent sous la juridiction de l'ue, ce qui est avantageux pour la conformité et la réduction des risques géopolitiques associés aux emplacements de traitement des données, même si les puces sous-jacentes proviennent du monde entier. Cela renforce la nécessité de stratégies claires de résidence des données dans les opérations cloud.

q : quelle est la version python recommandée pour les conteneurs personnalisés sur vertex ai en 2026 ?

A : début 2026, python 3.12+ est la version recommandée pour les nouveaux développements. Elle offre des améliorations de performances et de nouvelles fonctionnalités qui contribuent à un service de modèle plus efficace. Je vise toujours à utiliser la dernière version stable de python prise en charge par mes bibliothèques ml principales (pytorch, tensorflow, transformers) pour bénéficier des dernières optimisations et correctifs de sécurité.

Conclusion

Le déploiement de modèles d'apprentissage automatique personnalisés en production, en particulier dans le cadre réglementaire strict de l'ue, est un défi à multiples facettes. Tout au long de ce guide, je vous ai expliqué mon processus de création d'un déploiement vertex ai sécurisé, évolutif et conforme à l'aide de l'infrastructure en tant que code. La combinaison d'artifact registry pour la gestion des conteneurs, du registre de modèles vertex ai pour le versionnement, des points de terminaison de prédiction privés avec les contrôles de service vpc pour l'isolement des données, et d'une surveillance robuste avec cloud logging et la surveillance des modèles vertex ai crée une base solide pour toute charge de travail ml en production.

Un compromis important à considérer est la complexité initiale introduite par les contrôles de service vpc. Bien qu'incroyablement puissants pour la sécurité, ils nécessitent une planification minutieuse et peuvent compliquer le débogage. Ma recommandation est d'investir du temps dès le départ pour concevoir correctement votre réseau et vos politiques d'accès, car une adaptation ultérieure peut être beaucoup plus douloureuse. Pour les finops, gardez toujours un œil attentif sur le nombre de vos répliques et les types de machines ; les instances gpu inactives, en particulier, peuvent entraîner des coûts inattendus si l'autoscaling n'est pas correctement réglé.

Ma prochaine étape concrète après la mise en place d'un tel pipeline est toujours d'affiner la surveillance du modèle. Je priorise l'établissement d'un ensemble de données de référence robuste et d'un schéma détaillé qui reflète fidèlement les entrées et les sorties du modèle. Cette approche proactive me permet de détecter rapidement la dérive des données ou la dégradation des performances, garantissant que mes modèles continuent à apporter de la valeur en production, et pas seulement en développement.

Last updated:

This article was produced using an AI-assisted research and writing pipeline. Learn how we create content →