הקצאת סוכנים באמצעות Terraform

אתם יכולים להשתמש ב-Terraform כדי להקצות ולנהל מופעים של Agent Runtime באופן הצהרתי. כשפורסים סוכנים באמצעות Terraform, מנהלים את המשאב google_vertex_ai_reasoning_engine באמצעות ספק Terraform הרשמי ( Google Cloud ספק GA או ספק בטא).

ההוראות בדף הזה מתאימות להטמעה לדוגמה של סוכן מבוסס-קונטיינר שמתוארת ב-Codelab בנושא פריסת סוכן מבוסס-קונטיינר באמצעות Agent Runtime.

דרישות מוקדמות

לפני שמשתמשים ב-Terraform כדי לפרוס סוכן, צריך לוודא שהשלמתם את ההגדרה הבאה:

  1. מתקינים את Terraform (גרסה 1.5.0 ואילך) ומעיינים במסמכי התיעוד הרשמיים של HashiCorp Terraform Registry בנושא משאב google_vertex_ai_reasoning_engine (ספק GA וספק בטא).
  2. מגדירים את Google Cloud הסביבה ומפעילים את Vertex AI API‏ (aiplatform.googleapis.com), Artifact Registry API‏ (artifactregistry.googleapis.com) ו-Cloud Build API‏ (cloudbuild.googleapis.com).
  3. מאמתים את הסביבה המקומית באמצעות פרטי הכניסה של Google Cloud :

    gcloud auth application-default login
  4. כדי לשמור על הפרדה בין קוד האפליקציה לבין ניהול התשתית, כדאי לארגן את סביבת העבודה של הסוכן בספריות ייעודיות לאפליקציה ול-Terraform:

    weather-agent-byoc/
    ├── main.py                # Python ADK agent entrypoint
    ├── requirements.txt       # Python dependencies
    ├── Dockerfile             # Container build definition
    └── terraform/             # Terraform configuration directory
        ├── main.tf            # Agent Runtime resources and specifications
        ├── variables.tf       # Project, region, and container variables
        └── outputs.tf         # Resource name outputs
    
    • קבצים של האפליקציה (main.py,‏ requirements.txt,‏ Dockerfile): מכילים את הלוגיקה של הסוכן, את העטיפה של מסגרת האינטרנט (כמו FastAPI או ADK App), את התלות ב-Python ואת הוראות הבנייה של הקונטיינר.

    • ספריית Terraform (terraform/): מכילה את כל קובצי התצורה של Terraform שמשמשים להקצאת משאבים:

      • variables.tf: הצהרה על משתני קלט כמו project_id,‏ location,‏ repository_name ו-image_tag.
      • main.tf: הצהרה על הגדרות ספק, משתנים מקומיים, קישורי תפקידי IAM ומפרטי משאבים של google_vertex_ai_reasoning_engine.
      • outputs.tf: מייצא מאפיינים של משאבים שהוקצו, כמו מזהה Agent Runtime ושם המשאב המלא, אחרי הפריסה.
  5. נותנים את התפקידים המתאימים ב-IAM בהתאם למי שמבצע את הפריסה:

    • חשבון שירות של מפתח אנושי או של שירות CI/CD שמריץ את הפקודות terraform apply ופקודות build מקומיות.

    • סוכן שירות של Agent Runtime שמנוהל על ידי המערכת (service-<var>PROJECT_NUMBER</var>@gcp-sa-aiplatform-re.iam.gserviceaccount.com).

הכנה לפריסה

‫Terraform תומך בנתיבי הפריסה הבאים של Agent Runtime:

  • פריסה מקובץ אימג' של קונטיינר שנבנה מראש: יוצרים קובץ אימג' של קונטיינר ומעבירים אותו בדחיפה ל-Artifact Registry ‏ ({region}-docker.pkg.dev/...) ופורסים אותו באמצעות container_spec. כדאי להשתמש בשיטה הזו אם אתם רוצים שליטה מלאה בתהליך build של הקונטיינר, בתמונות בסיס מותאמות אישית או בזמן אחזור קצר יותר של הפריסה.
  • פריסה מקובצי מקור או מ-Dockerfile: פריסת הסוכן ישירות מקובצי מקור מקומיים או מ-Dockerfile. ה-Agent Runtime יוצר ומקצה את קובץ האימג' של הקונטיינר באופן אוטומטי, בלי צורך בניהול ידני של התמונה.
  • פריסה באמצעות מפרטים של חבילות Python פריסה באמצעות (package_spec) שמוצג ב-Cloud Storage. ה-Agent Runtime יוצר ומקצה את קובץ האימג' של הקונטיינר באופן אוטומטי, בלי צורך בניהול ידני של התמונה.

פריסה מקובץ אימג' של קונטיינר מוכן מראש

אם אתם יוצרים מראש קובצי אימג' של קונטיינרים ושולחים אותם אל Artifact Registry (לדוגמה, כדי לכלול ספריות מערכת בהתאמה אישית, לבצע אופטימיזציה של ביצועי הפעלה ראשונית או לאכוף אמצעי בקרה ארגוניים ליצירת קובצי אימג'), אתם יכולים לבצע פריסה באמצעות container_spec. פרטים על הדרישות בנוגע לתמונות מופיעים במאמר פריסה מתמונת מאגר.

קובצי אימג' של קונטיינרים צריכים להיות מאוחסנים ב-Artifact Registry‏ ({LOCATION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}:{TAG}), להאזין ליציאה 8080 (או ליציאה מותאמת אישית שצוינה ב-container_spec) ולפעול בהתאם לחוזה זמן הריצה.

  1. מפתחים גרסת build מקומית של קובץ האימג' בקונטיינר ומעבירים אותו בדחיפה למאגר ב-Artifact Registry:

    # 1. Authenticate Docker with your Artifact Registry region
    gcloud auth configure-docker us-central1-docker.pkg.dev
    # 2. Build the container image from your application root directory
    cd weather-agent-byoc
    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/agents-repo/weather-agent-image:latest .
    # 3. Push the container image to Artifact Registry
    docker push us-central1-docker.pkg.dev/PROJECT_ID/agents-repo/weather-agent-image:latest
  2. מגדירים את קובץ אימג' של קונטיינר שנבנה מראש לפריסת Terraform. ההגדרה הבאה מדגימה פריסה של קובץ אימג' של קונטיינר שנבנה מראש ומתארח ב-Artifact Registry, על ידי יצירת הקבצים variables.tf, main.tf ו-outputs.tf בתיקייה terraform/:

    משתני קלט (terraform/variables.tf)

    variable "project_id" {
      type        = string
      description = "The Google Cloud Project ID"
    }
    
    variable "project_number" {
      type        = string
      description = "The Google Cloud Project Number"
    }
    
    variable "location" {
      type        = string
      default     = "us-central1"
      description = "The region to deploy Agent Runtime"
    }
    
    variable "repository_name" {
      type        = string
      default     = "agents-repo"
      description = "The Artifact Registry repository name"
    }
    
    variable "image_tag" {
      type        = string
      default     = "latest"
      description = "The tag of the container image to deploy"
    }
    

    מפרטי משאבים (terraform/main.tf)

    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = ">= 5.28.0"
        }
      }
    }
    
    provider "google" {
      project = var.project_id
      region  = var.location
    }
    
    locals {
      class_methods = [
        { "name" = "get_session", "api_mode" = "" },
        { "name" = "list_sessions", "api_mode" = "" },
        { "name" = "create_session", "api_mode" = "" },
        { "name" = "delete_session", "api_mode" = "" },
        { "name" = "async_get_session", "api_mode" = "async" },
        { "name" = "async_list_sessions", "api_mode" = "async" },
        { "name" = "async_create_session", "api_mode" = "async" },
        { "name" = "async_delete_session", "api_mode" = "async" },
        { "name" = "async_add_session_to_memory", "api_mode" = "async" },
        { "name" = "async_search_memory", "api_mode" = "async" },
        { "name" = "stream_query", "api_mode" = "stream" },
        { "name" = "async_stream_query", "api_mode" = "async_stream" },
        { "name" = "streaming_agent_run_with_events", "api_mode" = "async_stream" }
      ]
    }
    
    # Grant Artifact Registry Reader permission to the Agent Runtime Service Agent
    resource "google_project_iam_member" "re_service_agent_ar_reader" {
      project = var.project_id
      role    = "roles/artifactregistry.reader"
      member  = "serviceAccount:service-${var.project_number}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
    }
    
    # Define the Agent Runtime resource with BYOC container configuration
    resource "google_vertex_ai_reasoning_engine" "byoc_weather_agent" {
      display_name = "byoc_weather_agent_tf"
      description  = "BYOC weather agent deployed using Terraform"
      project      = var.project_id
      location     = var.location
    
      spec {
        agent_framework = "google-adk"
    
        container_spec {
          image_uri = "${var.location}-docker.pkg.dev/${var.project_id}/${var.repository_name}/weather-agent-image:${var.image_tag}"
        }
    
        class_methods = jsonencode(local.class_methods)
      }
    
      # Ensure service agent permission exists before provisioning to prevent IMAGE_PULL_BACKOFF
      depends_on = [google_project_iam_member.re_service_agent_ar_reader]
    }
    

    פלט של משאבים (terraform/outputs.tf)

    output "reasoning_engine_id" {
      value       = google_vertex_ai_reasoning_engine.byoc_weather_agent.id
      description = "The ID of the deployed Agent Runtime instance"
    }
    
    output "reasoning_engine_resource_name" {
      value       = google_vertex_ai_reasoning_engine.byoc_weather_agent.name
      description = "The resource name of the deployed Agent Runtime instance"
    }
    

פריסה מקובץ Dockerfile או ממאגר קוד מקור

כשפורסים מקובץ Docker, צריך לציין את ארכיון המקור ב-source_code_spec ולהגדיר בלוק image_spec {} ריק כדי להנחות את Agent Runtime ליצור את קובץ האימג' של הקונטיינר באמצעות קובץ Docker. הקונטיינר שנבנה מקובץ ה-Dockerfile חייב לעמוד בתנאי הסכם זמן הריצה.

לפרטים נוספים על אופן הפריסה, אפשר לעיין במאמרים פריסה מקובץ Docker או פריסה מקובצי מקור.

  1. דוחסים את קוד האפליקציה (main.py), את מניפסט התלות של Python (requirements.txt) ואת הוראות בניית המאגר (Dockerfile) לארכיון מסוג tar.gz.

  2. מריצים את הפקודה הבאה מתיקיית השורש של האפליקציה (בדוגמה נעשה שימוש בתיקיית השורש weather-agent-byoc/ ובארכיון קובץ ה-tar‏ weather_agent_source.tar.gz):

    cd weather-agent-byoc
    tar -czvf terraform/weather_agent_source.tar.gz main.py requirements.txt Dockerfile
  3. יוצרים את הקבצים variables.tf, main.tf ו-outputs.tf בספרייה terraform/:

    משתני קלט (terraform/variables.tf)
    variable "project_id" {
      type        = string
      description = "The Google Cloud Project ID"
    }
    
    variable "location" {
      type        = string
      default     = "us-central1"
      description = "The region to deploy Agent Runtime"
    }
    

    מפרטי משאבים (terraform/main.tf)

    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = ">= 5.28.0"
        }
      }
    }
    
    provider "google" {
      project = var.project_id
      region  = var.location
    }
    
    resource "google_vertex_ai_reasoning_engine" "dockerfile_agent" {
      display_name = "dockerfile_weather_agent_tf"
      description  = "BYOC weather agent deployed using Dockerfile"
      project      = var.project_id
      location     = var.location
    
      spec {
        agent_framework = "google-adk"
    
        source_code_spec {
          inline_source {
            source_archive = filebase64("weather_agent_source.tar.gz")
          }
    
          # Empty image_spec instructs the runtime to build using the Dockerfile
          image_spec {}
        }
    
        class_methods = jsonencode([
          { "name" = "get_session", "api_mode" = "" },
          { "name" = "list_sessions", "api_mode" = "" },
          { "name" = "create_session", "api_mode" = "" },
          { "name" = "delete_session", "api_mode" = "" },
          { "name" = "async_get_session", "api_mode" = "async" },
          { "name" = "async_list_sessions", "api_mode" = "async" },
          { "name" = "async_create_session", "api_mode" = "async" },
          { "name" = "async_delete_session", "api_mode" = "async" },
          { "name" = "async_add_session_to_memory", "api_mode" = "async" },
          { "name" = "async_search_memory", "api_mode" = "async" },
          { "name" = "stream_query", "api_mode" = "stream" },
          { "name" = "async_stream_query", "api_mode" = "async_stream" },
          { "name" = "streaming_agent_run_with_events", "api_mode" = "async_stream" }
        ])
      }
    }
    

    פלט של משאבים (terraform/outputs.tf)

    output "dockerfile_agent_id" {
      value       = google_vertex_ai_reasoning_engine.dockerfile_agent.id
      description = "Resource ID of the deployed Dockerfile agent"
    }
    

פריסה באמצעות מפרט חבילת Python

אם הסוכן שלכם נוצר באמצעות אובייקטים של Python SDK או אפליקציות pickled (כמו ADK,‏ LangChain או סוכני Python בהתאמה אישית), אתם יכולים להכין את הסוכן הסדרתי (.pkl) ואת הגדרות התלות (requirements.txt) בקטגוריה של Cloud Storage ולהפנות אליהם באמצעות package_spec.

פרטים נוספים על תהליך הפריסה זמינים במאמר פריסה מאובייקט Python.

  1. מריצים את סקריפט Python הבא כדי לבצע סריאליזציה של הסוכן ולהכין את פריטי הפריסה ב-Cloud Storage:

    import cloudpickle
    from google.adk.agents import Agent
    from google.cloud import storage
    from vertexai.agent_engines import AdkApp
    PROJECT_ID = "PROJECT_ID"
    BUCKET_NAME = "BUCKET_NAME"
    GCS_DIR = "agents/weather_agent"
    
    # 1. Define agent logic
    root_agent = Agent(
        model="gemini-3.1-flash-lite",
        name="weather_agent",
        description="Agent deployed using Terraform package_spec.",
    )
    local_app = AdkApp(agent=root_agent)
    
    # 2. Upload pickle to Cloud Storage
    storage_client = storage.Client(project=PROJECT_ID)
    bucket = storage_client.bucket(BUCKET_NAME)
    
    pkl_blob = bucket.blob(f"{GCS_DIR}/agent.pkl")
    with pkl_blob.open("wb") as f:
        cloudpickle.dump(local_app, f)
    
    # 3. Upload requirements.txt
    requirements_content = """google-cloud-aiplatform[agent_engines,adk]>=1.144
    cloudpickle==3.0.0
    """
    req_blob = bucket.blob(f"{GCS_DIR}/requirements.txt")
    req_blob.upload_from_string(requirements_content)
    
    print(f"Artifacts uploaded to gs://{BUCKET_NAME}/{GCS_DIR}/")
    
  2. יוצרים את הקבצים variables.tf, main.tf ו-outputs.tf בספרייה terraform/, עם הפניה ל-URI של Cloud Storage שהועברו להמתנה:

    משתני קלט (terraform/variables.tf)
    variable "project_id" {
      type        = string
      description = "The Google Cloud Project ID"
    }
    
    variable "location" {
      type        = string
      default     = "us-central1"
      description = "The region to deploy Agent Runtime"
    }
    
    variable "bucket_name" {
      type        = string
      description = "Cloud Storage bucket name containing agent artifacts"
    }
    
    מפרטי משאבים (terraform/main.tf)
    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = ">= 5.28.0"
        }
      }
    }
    
    provider "google" {
      project = var.project_id
      region  = var.location
    }
    
    resource "google_vertex_ai_reasoning_engine" "package_agent" {
      display_name = "weather_agent_package_tf"
      description  = "Agent Runtime instance deployed using package_spec"
      project      = var.project_id
      location     = var.location
    
      spec {
        agent_framework = "google-adk"
        package_spec {
          python_version        = "3.11"
          pickle_object_gcs_uri = "gs://${var.bucket_name}/agents/weather_agent/agent.pkl"
          requirements_gcs_uri  = "gs://${var.bucket_name}/agents/weather_agent/requirements.txt"
        }
      }
    }
    
    פלט של משאבים (terraform/outputs.tf)
    output "package_agent_id" {
      value       = google_vertex_ai_reasoning_engine.package_agent.id
      description = "Resource ID of the deployed package agent"
    }
    

הגדרת משתני סביבה וסודות

לפני הפריסה, אפשר לצרף לחשבון של הסוכן חשבון שירות מותאם אישית של זמן ריצה ולהעביר משתני סביבה (env) או הפניות ל-Secret Manager (secret_env).

בדוגמה הבאה מוגדרים משתני סביבה (LOCATION, ‏MODEL, ‏MODEL_REGION) ומפתח API מועבר בצורה מאובטחת מ-Secret Manager לחשבון השירות של זמן הריצה דרך הקובץ terraform/main.tf:

# 1. Dedicated Runtime Service Account
resource "google_service_account" "agent_runtime_sa" {
  account_id   = "agent-runtime-sa"
  display_name = "Agent Runtime Identity"
  project      = var.project_id
}

# 2. Secret Manager Secret for Agent Credentials
resource "google_secret_manager_secret" "api_key_secret" {
  secret_id = "agent-api-key"
  project   = var.project_id

  replication {
    auto {}
  }
}

resource "google_secret_manager_secret_version" "api_key_version" {
  secret      = google_secret_manager_secret.api_key_secret.id
  secret_data = var.api_key_value
}

# Grant Secret Accessor role to Runtime Service Account
resource "google_secret_manager_secret_iam_member" "secret_accessor" {
  secret_id = google_secret_manager_secret.api_key_secret.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.agent_runtime_sa.email}"
}

# Grant Artifact Registry Reader permission to the Agent Runtime Service Agent
resource "google_project_iam_member" "re_service_agent_ar_reader" {
  project = var.project_id
  role    = "roles/artifactregistry.reader"
  member  = "serviceAccount:service-${var.project_number}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
}

# 3. Agent Runtime Resource with Environment Variables and Secret References
resource "google_vertex_ai_reasoning_engine" "advanced_weather_agent" {
  display_name = "byoc_weather_agent_advanced_tf"
  description  = "BYOC weather agent with custom service account and secrets"
  project      = var.project_id
  location     = var.location

  spec {
    agent_framework = "google-adk"
    service_account = google_service_account.agent_runtime_sa.email

    container_spec {
      image_uri = "${var.location}-docker.pkg.dev/${var.project_id}/${var.repository_name}/weather-agent-image:${var.image_tag}"
    }

    deployment_spec {
      env {
        name  = "LOCATION"
        value = var.location
      }
      env {
        name  = "MODEL"
        value = "gemini-3.1-flash-lite"
      }
      env {
        name  = "MODEL_REGION"
        value = "global"
      }

      secret_env {
        name = "API_KEY"
        secret_ref {
          secret  = google_secret_manager_secret.api_key_secret.secret_id
          version = "latest"
        }
      }
    }

    class_methods = jsonencode([
      { "name" = "get_session", "api_mode" = "" },
      { "name" = "create_session", "api_mode" = "" },
      { "name" = "stream_query", "api_mode" = "stream" },
      { "name" = "async_stream_query", "api_mode" = "async_stream" }
    ])
  }

  depends_on = [
    google_secret_manager_secret_iam_member.secret_accessor,
    google_project_iam_member.re_service_agent_ar_reader
  ]
}

ביצוע ומחזור חיים

מריצים את מחזור החיים הרגיל של Terraform כדי לתכנן, לפרוס, להפעיל ולהשמיד את משאבי הסוכן.

שימוש בתצורה של Terraform

פורסים את הסוכן על ידי החלת ההגדרות של Terraform:

  1. עוברים לספריית Terraform (לדוגמה, cd weather-agent-byoc/terraform):

    cd weather-agent-byoc/terraform
  2. מאתחלים את ספריית העבודה:

    terraform init
  3. תצוגה מקדימה של תוכנית הפריסה:

    terraform plan -var="project_id=PROJECT_ID" -var="project_number=PROJECT_NUMBER"
  4. מחילים את ההגדרה כדי להקצות את הסוכן:

    terraform apply -var="project_id=PROJECT_ID" -var="project_number=PROJECT_NUMBER"

שליחת שאילתה לסוכן הפעיל

אחרי ש-Terraform מקצה את משאב google_vertex_ai_reasoning_engine, שולחים בקשת HTTP POST לנקודת הקצה :streamQuery?alt=sse כדי להזרים אירועי תגובה בזמן אמת באמצעות Server-Sent Events ‏ (SSE):

LOCATION="LOCATION"
PROJECT_ID="PROJECT_ID"
REASONING_ENGINE_ID="REASONING_ENGINE_ID"
curl -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{
    "class_method": "async_stream_query",
    "input": {
      "user_id": "terraform_test_user",
      "message": "What is the temperature in Seattle?"
    }
  }' \
  "https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/reasoningEngines/${REASONING_ENGINE_ID}:streamQuery?alt=sse"
  • OAuth Access Token: Authorization: Bearer $(gcloud auth print-access-token) יוצר אסימון גישה מסוג OAuth 2.0 עם תוקף קצר באמצעות פרטי הכניסה המקומיים שלכם. Google Cloud
  • מעטפת JSON input: תוכן הבקשה צריך להיות מטען ייעודי (payload) של JSON שמכיל אובייקט input. כשמפעילים שיטות של מחלקה מפורשת (כמו async_stream_query), צריך לכלול את הפרמטר "class_method" לצד "input".
  • המטען הייעודי של התגובה: התגובות מועברות באופן רציף כנתונים של data: { ... } אירועים שנשלחים מהשרת (SSE).

השמדת משאבים של סוכנים

כדי למחוק משאבים ולמנוע חיובים לא צפויים, עוברים לספרייה terraform/ (לדוגמה, cd weather-agent-byoc/terraform) ומריצים את הפקודה terraform destroy:

cd weather-agent-byoc/terraform
terraform destroy -var="project_id=PROJECT_ID" -var="project_number=PROJECT_NUMBER"

המאמרים הבאים