יצירה של מכונות וירטואליות מסוג Spot ושימוש בהן

בדף הזה מוסבר איך ליצור ולנהל מכונות וירטואליות מסוג Spot, כולל:

  • איך יוצרים, מפעילים ומזהים מכונות וירטואליות מסוג Spot
  • איך לזהות, לטפל ולבדוק את ההפסקות של מכונות וירטואליות מסוג Spot
  • שיטות מומלצות לשימוש במכונות וירטואליות מסוג Spot

מכונות וירטואליות במודל Spot הן מכונות וירטואליות (VM) עם מודל הקצאת משאבים במחיר Spot. ‫ Spot VMs זמינות בהנחה של עד 60% ממחיר השימוש לפי דרישה במכונות וירטואליות רגילות.

מידע נוסף זמין בדף התמחור. עם זאת, יכול להיות ש-Compute Engine יחזיר את המשאבים על ידי הפסקת השימוש במכונות וירטואליות מסוג Spot בכל שלב. מומלץ להשתמש במכונות וירטואליות מסוג Spot רק לעומסי עבודה סובלניים לשגיאות שיכולים לעמוד בדחיקה של מכונות וירטואליות. לפני שיוצרים מכונות וירטואליות מסוג Spot, צריך לוודא שעומס העבודה יכול לנהל את ההפקעה.

אם אתם רוצים ליצור ולנהל מכונות וירטואליות מסוג Spot עם TPU, כדאי לעיין במקום זאת ב מסמכי התיעוד של Cloud TPU בנושא מכונות וירטואליות מסוג Spot.

לפני שמתחילים

יצירת VM במודל Spot

לפני שיוצרים VM במודל Spot, כדאי לבדוק את הזמינות של סוג המכונה שרוצים שה-VM במודל Spot ישתמשו בו. בדיקת הזמינות של משאבים עוזרת לצמצם את הסיכוי להיתקל בשגיאות שקשורות לזמינות של משאבים כשיוצרים מכונות וירטואליות. הוראות מפורטות מופיעות במאמר בנושא צפייה בזמינות של מכונות Spot VM.

VM במודל Spot היא כל מכונה וירטואלית שמגדירים בה שימוש במודל הקצאת המשאבים מסוג Spot:

  • VM provisioning model מוגדר ל-Spot במסוף Cloud de Confiance
  • --provisioning-model=SPOT ב-CLI של gcloud
  • "provisioningModel": "SPOT" ב-Compute Engine API

כדי ללמוד איך ליצור VM במודל Spot, בוחרים באחת מהשיטות הבאות בהתאם לאופן שבו רוצים לטפל בהפסקה זמנית:

לחלופין, כדי ליצור כמה מכונות VM במודל Spot עם אותם מאפיינים, אפשר ליצור תבנית של הגדרות מכונה ולהשתמש בתבנית כדי ליצור קבוצת מופעי מכונה מנוהלים (MIG). מידע נוסף זמין במאמר בנושא שיטות מומלצות.

יצירת מכונה וירטואלית (VM) מסוג Spot עם 120 שניות לטיפול בהפסקת פעולה

לפני שיוצרים VM במודל Spot עם הודעת קדימה של 120 שניות על הפסקת השימוש, חשוב לוודא שמטפלים בהפסקת השימוש בעומס העבודה.

gcloud

כדי ליצור מכונת Spot וירטואלית עם משך הודעה על הפסקת השימוש של 120 שניות מ-CLI של gcloud, משתמשים בפקודה gcloud beta compute instances create וכוללים את הדגל --preemption-notice-duration=120s. כדי ליצור מכונות וירטואליות (VM) זמניות מסוג Spot, צריך לכלול את הדגל --provisioning-model=SPOT. אפשר גם לציין פעולת סיום למכונות וירטואליות מסוג Spot על ידי הוספת הדגל --instance-termination-action.

gcloud beta compute instances create VM_NAME \
    --provisioning-model=SPOT \
    --preemption-notice-duration=120s \
    --instance-termination-action=TERMINATION_ACTION

מחליפים את מה שכתוב בשדות הבאים:

  • VM_NAME: name של המכונה הווירטואלית החדשה.
  • TERMINATION_ACTION: אופציונלי: מציינים איזו פעולת סיום תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, או STOP (התנהגות ברירת המחדל) או DELETE.

מידע נוסף על האפשרויות שאפשר לציין כשיוצרים מכונת VM זמין במאמר אפשרויות הגדרה במהלך יצירת מכונה. לדוגמה, כדי ליצור מכונות וירטואליות מסוג Spot עם סוג מכונה ותמונה שצוינו, משתמשים בפקודה הבאה:

gcloud beta compute instances create VM_NAME \
    --provisioning-model=SPOT \
    --preemption-notice-duration=120s \
    [--image=IMAGE | --image-family=IMAGE_FAMILY] \
    --image-project=IMAGE_PROJECT \
    --machine-type=MACHINE_TYPE \
    --instance-termination-action=TERMINATION_ACTION

מחליפים את מה שכתוב בשדות הבאים:

  • VM_NAME: name של המכונה הווירטואלית החדשה.
  • IMAGE: מציינים אחת מהאפשרויות הבאות:
    • IMAGE: גרסה ספציפית של תמונה ציבורית או של משפחת התמונות. לדוגמה, תמונה ספציפית היא --image=debian-10-buster-v20200309.
    • משפחת תמונות. כך נוצרת מכונת ה-VM מתמונת מערכת ההפעלה העדכנית ביותר שלא הוצאה משימוש. לדוגמה, אם מציינים --image-family=debian-10,‏ Compute Engine יוצר מכונה וירטואלית מהגרסה העדכנית של תמונת מערכת ההפעלה במשפחת תמונות Debian 10.
  • IMAGE_PROJECT: הפרויקט שמכיל את התמונה. לדוגמה, אם מציינים את debian-10 כמשפחת התמונות, מציינים את debian-cloud כפרויקט התמונות.
  • MACHINE_TYPE: סוג המכונה המוגדר מראש או המותאם אישית של המכונה הווירטואלית החדשה.

    כדי לקבל רשימה של סוגי המכונות שזמינים באזור מסוים, משתמשים בפקודה gcloud compute machine-types list עם הדגל --zones.

  • TERMINATION_ACTION: אופציונלי: מציינים איזו פעולת סיום תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, או STOP (התנהגות ברירת המחדל) או DELETE.

REST

כדי ליצור VM במודל Spot עם משך הודעת קדימות של 120 שניות מ-Compute Engine API, משתמשים בשיטה beta instances.insert וכוללים את השדה "preemptionNoticeDuration": { "seconds": 120 }. צריך לציין את סוג המכונה ואת השם של המכונה הווירטואלית. אפשר גם לציין תמונה לדיסק האתחול.

כדי ליצור מכונות וירטואליות מסוג Spot, צריך לכלול את השדה "provisioningModel": spot. אפשר גם לציין פעולת סיום למכונות וירטואליות מסוג Spot על ידי הוספת השדה "instanceTerminationAction".

POST https://compute.s3nsapis.fr/compute/beta/projects/PROJECT_ID/zones/ZONE/instances
{
 "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
 "name": "VM_NAME",
 "disks": [
   {
     "initializeParams": {
       "sourceImage": "projects/IMAGE_PROJECT/global/images/IMAGE"
     },
     "boot": true
   }
 ],
 "scheduling":
 {
     "provisioningModel": "SPOT",
     "preemptionNoticeDuration": { "seconds": 120 },
     "instanceTerminationAction": "TERMINATION_ACTION"
 }
}

מחליפים את מה שכתוב בשדות הבאים:

  • PROJECT_ID: מזהה הפרויקט שבו רוצים ליצור את המכונה הווירטואלית.
  • ZONE: האזור שבו רוצים ליצור את המכונה הווירטואלית. בנוסף, האזור צריך לתמוך בסוג המכונה שבה רוצים להשתמש עבור המכונה הווירטואלית החדשה.
  • MACHINE_TYPE: סוג המכונה המוגדר מראש או המותאם אישית של המכונה הווירטואלית החדשה.
  • VM_NAME: השם של המכונה הווירטואלית החדשה.
  • IMAGE_PROJECT: הפרויקט שמכיל את התמונה. לדוגמה, אם מציינים את family/debian-10 כמשפחת התמונות, מציינים את debian-cloud כפרויקט התמונות.
  • IMAGE: מציינים אחת מהאפשרויות הבאות:
    • גרסה ספציפית של תמונה ציבורית. לדוגמה, תמונה ספציפית היא "sourceImage": "projects/debian-cloud/global/images/debian-10-buster-v20200309", כאשר debian-cloud הוא IMAGE_PROJECT.
    • משפחת תמונות. כך נוצרת מכונת ה-VM מתמונת מערכת ההפעלה העדכנית ביותר שלא הוצאה משימוש. לדוגמה, אם מציינים "sourceImage": "projects/debian-cloud/global/images/family/debian-10", כאשר debian-cloud הוא IMAGE_PROJECT,‏ Compute Engine יוצר מכונה וירטואלית מהגרסה העדכנית של תמונת מערכת ההפעלה במשפחת תמונות Debian 10.
  • TERMINATION_ACTION: אופציונלי: מציינים איזו פעולת סיום תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, או STOP (התנהגות ברירת המחדל) או DELETE.

מידע נוסף על האפשרויות שאפשר לציין כשיוצרים מכונת VM זמין במאמר אפשרויות הגדרה במהלך יצירת מכונה.

יצירת VM במודל Spot עם עד 30 שניות לטיפול בהפסקה זמנית (ברירת מחדל)

כברירת מחדל, מכונת VM מסוג Spot מקבלת הודעה על הפסקת השימוש בתחילת תקופת ההשבתה של 30 שניות, ואתם צריכים לטפל בהפסקת השימוש באמצעות סקריפט השבתה.

המסוף

  1. נכנסים לדף Create an instance במסוף Cloud de Confiance .

    כניסה לדף Create an instance

  2. בחלונית Machine configuration (הגדרת המכונה), שפתוחה כברירת מחדל, מבצעים את השלבים הבאים:

    1. בקטע Provisioning model בוחרים באפשרות Spot מהרשימה VM provisioning model.
    2. אופציונלי: כדי לבחור את פעולת הסיום שמתבצעת כש-Compute Engine מבצעת דחיקה של מכונת ה-VM, מבצעים את השלבים הבאים:

      1. מרחיבים את הקטע VM provisioning model advanced settings.
      2. ברשימה On VM termination בוחרים באחת מהאפשרויות הבאות:
        • כדי לעצור את המכונה הווירטואלית במהלך הפסקת הפעולה לפני הזמן, בוחרים באפשרות Stop (ברירת מחדל).
        • כדי למחוק את המכונה הווירטואלית במהלך ההפסקה לפני הזמן, בוחרים באפשרות מחיקה.
  3. בתפריט הניווט, לוחצים על מתקדם. בחלונית Advanced שמופיעה, מבצעים את הפעולות הבאות:

    1. בקטע מטא נתונים, לוחצים על הוספת פריט.
    2. בשדה מפתח, מזינים shutdown-script כמפתח המטא-נתונים.
    3. בשדה Value, מוסיפים את התוכן של סקריפט כיבוי שמטפל בהפסקת הפעולה. סקריפט לדוגמה לכיבוי מופיע בקטע טיפול בהפסקת פעולה במסמך הזה.
  4. אופציונלי: מציינים אפשרויות הגדרה אחרות. מידע נוסף מופיע במאמר אפשרויות הגדרה במהלך יצירת מכונה.

  5. כדי ליצור את המכונה הווירטואלית ולהפעיל אותה, לוחצים על Create.

gcloud

כדי ליצור מכונה וירטואלית באמצעות ה-CLI של gcloud, משתמשים בפקודה gcloud compute instances create. כדי ליצור מכונות וירטואליות (VM) זמניות מסוג Spot, צריך לכלול את הדגל --provisioning-model=SPOT. כדי לטפל בהפקעה, צריך לכלול את הדגל --metadata shutdown-script כדי לציין סקריפט כיבוי. אפשר גם לציין פעולת סיום למכונות וירטואליות מסוג Spot על ידי הוספת הדגל --instance-termination-action.

gcloud compute instances create VM_NAME \
    --provisioning-model=SPOT \
    --metadata shutdown-script=SHUTDOWN_SCRIPT \
    --instance-termination-action=TERMINATION_ACTION

מחליפים את מה שכתוב בשדות הבאים:

  • VM_NAME: name של המכונה הווירטואלית החדשה.
  • SHUTDOWN_SCRIPT: סקריפט כיבוי, שאפשר לעצב אותו כמו שמוסבר במאמר הרצת סקריפטים של כיבוי. סקריפט לדוגמה לכיבוי מופיע בקטע טיפול בהפסקת פעולה במסמך הזה.
  • TERMINATION_ACTION: אופציונלי: מציינים איזו פעולת סיום תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, או STOP (התנהגות ברירת המחדל) או DELETE.

מידע נוסף על האפשרויות שאפשר לציין כשיוצרים מכונת VM זמין במאמר אפשרויות הגדרה במהלך יצירת מכונה. לדוגמה, כדי ליצור מכונות וירטואליות מסוג Spot עם סוג מכונה ותמונה שצוינו, משתמשים בפקודה הבאה:

gcloud compute instances create VM_NAME \
    --provisioning-model=SPOT \
    --metadata shutdown-script=SHUTDOWN_SCRIPT \
    [--image=IMAGE | --image-family=IMAGE_FAMILY] \
    --image-project=IMAGE_PROJECT \
    --machine-type=MACHINE_TYPE \
    --instance-termination-action=TERMINATION_ACTION \

מחליפים את מה שכתוב בשדות הבאים:

  • VM_NAME: name של המכונה הווירטואלית החדשה.
  • SHUTDOWN_SCRIPT: סקריפט כיבוי שמטפל בהפקעה. מידע נוסף על הפורמט של סקריפט כיבוי ועל הגדרתו זמין במאמר הרצת סקריפטים של כיבוי. סקריפט לדוגמה לכיבוי מופיע בקטע טיפול בהפסקת פעולה במסמך הזה.
  • IMAGE: מציינים אחת מהאפשרויות הבאות:
    • IMAGE: גרסה ספציפית של תמונה ציבורית או של משפחת התמונות. לדוגמה, תמונה ספציפית היא --image=debian-10-buster-v20200309.
    • משפחת תמונות. כך נוצרת מכונת ה-VM מתמונת מערכת ההפעלה העדכנית ביותר שלא הוצאה משימוש. לדוגמה, אם מציינים --image-family=debian-10,‏ Compute Engine יוצר מכונה וירטואלית מהגרסה העדכנית של תמונת מערכת ההפעלה במשפחת תמונות Debian 10.
  • IMAGE_PROJECT: הפרויקט שמכיל את התמונה. לדוגמה, אם מציינים את debian-10 כמשפחת התמונות, מציינים את debian-cloud כפרויקט התמונות.
  • MACHINE_TYPE: סוג המכונה המוגדר מראש או המותאם אישית של המכונה הווירטואלית החדשה.

    כדי לקבל רשימה של סוגי המכונות שזמינים באזור מסוים, משתמשים בפקודה gcloud compute machine-types list עם הדגל --zones.

  • TERMINATION_ACTION: אופציונלי: מציינים איזו פעולת סיום תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, או STOP (התנהגות ברירת המחדל) או DELETE.

Terraform

אפשר להשתמש במשאב של Terraform כדי ליצור VM במודל Spot באמצעות הבלוק scheduling, כמו בדוגמה הבאה.

כדי להוסיף סקריפט כיבוי לטיפול בהפקעה, מוסיפים גם metadata בלוק כמו שמוצג במאמר הרצת סקריפטים של כיבוי. סקריפט לדוגמה לכיבוי מופיע בקטע טיפול בהפסקת פעולה במסמך הזה.


resource "google_compute_instance" "spot_vm_instance" {
  name         = "spot-instance-name"
  machine_type = "f1-micro"
  zone         = "us-central1-c"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  scheduling {
    preemptible                 = true
    automatic_restart           = false
    provisioning_model          = "SPOT"
    instance_termination_action = "STOP"
  }

  network_interface {
    # A default network is created for all GCP projects
    network = "default"
    access_config {
    }
  }
}

כדי ללמוד איך להחיל הגדרות ב-Terraform או להסיר אותן, ראו פקודות בסיסיות ב-Terraform.

REST

כדי ליצור מכונה וירטואלית באמצעות Compute Engine API, משתמשים ב-method ‏instances.insert. צריך לציין את סוג המכונה ואת השם של המכונה הווירטואלית. אפשר גם לציין תמונה לדיסק האתחול.

כדי ליצור מכונות וירטואליות מסוג Spot, צריך לכלול את השדה "provisioningModel": spot. כדי לטפל בהפקעה, צריך לכלול גם את השדה "metadata" ולציין סקריפט כיבוי. אפשר גם לציין פעולת סיום למכונות וירטואליות מסוג Spot על ידי הוספת השדה "instanceTerminationAction".

POST https://compute.s3nsapis.fr/compute/v1/projects/PROJECT_ID/zones/ZONE/instances
{
  "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
  "name": "VM_NAME",
  "disks": [
    {
      "initializeParams": {
      "sourceImage": "projects/IMAGE_PROJECT/global/images/IMAGE"
      },
      "boot": true
    }
  ],
  "scheduling":
  {
      "provisioningModel": "SPOT",
      "instanceTerminationAction": "TERMINATION_ACTION"
  },
  "metadata": {
    "items": [
      {
        "key": "shutdown-script",
        "value": "SHUTDOWN_SCRIPT"
      }
    ]
  }
}

מחליפים את מה שכתוב בשדות הבאים:

  • PROJECT_ID: מזהה הפרויקט שבו רוצים ליצור את המכונה הווירטואלית.
  • ZONE: האזור שבו רוצים ליצור את המכונה הווירטואלית. בנוסף, האזור צריך לתמוך בסוג המכונה שבה רוצים להשתמש עבור המכונה הווירטואלית החדשה.
  • MACHINE_TYPE: סוג המכונה המוגדר מראש או המותאם אישית של המכונה הווירטואלית החדשה.
  • VM_NAME: השם של המכונה הווירטואלית החדשה.
  • IMAGE_PROJECT: הפרויקט שמכיל את התמונה. לדוגמה, אם מציינים את family/debian-10 כמשפחת התמונות, מציינים את debian-cloud כפרויקט התמונות.
  • IMAGE: מציינים אחת מהאפשרויות הבאות:
    • גרסה ספציפית של תמונה ציבורית. לדוגמה, תמונה ספציפית היא "sourceImage": "projects/debian-cloud/global/images/debian-10-buster-v20200309", כאשר debian-cloud הוא IMAGE_PROJECT.
    • משפחת תמונות. כך נוצרת מכונת ה-VM מתמונת מערכת ההפעלה העדכנית ביותר שלא הוצאה משימוש. לדוגמה, אם מציינים "sourceImage": "projects/debian-cloud/global/images/family/debian-10", כאשר debian-cloud הוא IMAGE_PROJECT,‏ Compute Engine יוצר מכונה וירטואלית מהגרסה העדכנית ביותר של תמונת מערכת ההפעלה במשפחת תמונות Debian 10.
  • TERMINATION_ACTION: אופציונלי: מציינים איזו פעולת סיום תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, או STOP (התנהגות ברירת המחדל) או DELETE.
  • SHUTDOWN_SCRIPT: סקריפט כיבוי שמטפל בהפקעה. מידע נוסף על הפורמט של סקריפט כיבוי ועל הגדרתו זמין במאמר הרצת סקריפטים של כיבוי. סקריפט לדוגמה לכיבוי מופיע בקטע טיפול בהפסקת פעולה במסמך הזה.

מידע נוסף על האפשרויות שאפשר לציין כשיוצרים מכונת VM זמין במאמר אפשרויות הגדרה במהלך יצירת מכונה.

המשך

בדוגמה הבאה נוצרת מכונה וירטואלית (VM) במודל Spot ללא סקריפט כיבוי לטיפול בהפסקה זמנית. מידע נוסף על הגדרת סקריפט כיבוי למכונה וירטואלית חדשה או קיימת זמין במאמר הרצת סקריפטים של כיבוי. דוגמה לסקריפט כיבוי מופיעה בקטע טיפול בדחיקה במסמך הזה.


import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	"cloud.google.com/go/compute/apiv1/computepb"
	"google.golang.org/protobuf/proto"
)

// createSpotInstance creates a new Spot VM instance with Debian 10 operating system.
func createSpotInstance(w io.Writer, projectID, zone, instanceName string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"

	ctx := context.Background()
	imagesClient, err := compute.NewImagesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewImagesRESTClient: %w", err)
	}
	defer imagesClient.Close()

	instancesClient, err := compute.NewInstancesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewInstancesRESTClient: %w", err)
	}
	defer instancesClient.Close()

	req := &computepb.GetFromFamilyImageRequest{
		Project: "debian-cloud",
		Family:  "debian-11",
	}

	image, err := imagesClient.GetFromFamily(ctx, req)
	if err != nil {
		return fmt.Errorf("getImageFromFamily: %w", err)
	}

	diskType := fmt.Sprintf("zones/%s/diskTypes/pd-standard", zone)
	disks := []*computepb.AttachedDisk{
		{
			AutoDelete: proto.Bool(true),
			Boot:       proto.Bool(true),
			InitializeParams: &computepb.AttachedDiskInitializeParams{
				DiskSizeGb:  proto.Int64(10),
				DiskType:    proto.String(diskType),
				SourceImage: proto.String(image.GetSelfLink()),
			},
			Type: proto.String(computepb.AttachedDisk_PERSISTENT.String()),
		},
	}

	req2 := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name:        proto.String(instanceName),
			Disks:       disks,
			MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/%s", zone, "n1-standard-1")),
			NetworkInterfaces: []*computepb.NetworkInterface{
				{
					Name: proto.String("global/networks/default"),
				},
			},
			Scheduling: &computepb.Scheduling{
				ProvisioningModel: proto.String(computepb.Scheduling_SPOT.String()),
			},
		},
	}
	op, err := instancesClient.Insert(ctx, req2)
	if err != nil {
		return fmt.Errorf("insert: %w", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	instance, err := instancesClient.Get(ctx, &computepb.GetInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
	})

	if err != nil {
		return fmt.Errorf("createInstance: %w", err)
	}

	fmt.Fprintf(w, "Instance created: %v\n", instance)
	return nil
}

Java

בדוגמה הבאה נוצרת מכונה וירטואלית (VM) במודל Spot ללא סקריפט כיבוי לטיפול בהפסקה זמנית. מידע נוסף על הגדרת סקריפט כיבוי למכונה וירטואלית חדשה או קיימת זמין במאמר הרצת סקריפטים של כיבוי. דוגמה לסקריפט כיבוי מופיעה בקטע טיפול בדחיקה במסמך הזה.


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Address.NetworkTier;
import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.ImagesClient;
import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import com.google.cloud.compute.v1.Scheduling;
import com.google.cloud.compute.v1.Scheduling.ProvisioningModel;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateSpotVm {
  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Name of the virtual machine to check.
    String instanceName = "your-instance-name";
    // Name of the zone you want to use. For example: "us-west3-b"
    String zone = "your-zone";

    createSpotInstance(projectId, instanceName, zone);
  }

  // Create a new Spot VM instance with Debian 11 operating system.
  public static Instance createSpotInstance(String projectId, String instanceName, String zone)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    String image;
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (ImagesClient imagesClient = ImagesClient.create()) {
      image = imagesClient.getFromFamily("debian-cloud", "debian-11").getSelfLink();
    }
    AttachedDisk attachedDisk = buildAttachedDisk(image, zone);
    String machineTypes = String.format("zones/%s/machineTypes/%s", zone, "n1-standard-1");

    // Send an instance creation request to the Compute Engine API and wait for it to complete.
    Instance instance =
            createInstance(projectId, zone, instanceName, attachedDisk, true, machineTypes, false);

    System.out.printf("Spot instance '%s' has been created successfully", instance.getName());

    return instance;
  }

  // disks: a list of compute_v1.AttachedDisk objects describing the disks
  //     you want to attach to your new instance.
  // machine_type: machine type of the VM being created. This value uses the
  //     following format: "zones/{zone}/machineTypes/{type_name}".
  //     For example: "zones/europe-west3-c/machineTypes/f1-micro"
  // external_access: boolean flag indicating if the instance should have an external IPv4
  //     address assigned.
  // spot: boolean value indicating if the new instance should be a Spot VM or not.
  private static Instance createInstance(String projectId, String zone, String instanceName,
                                         AttachedDisk disk, boolean isSpot, String machineType,
                                         boolean externalAccess)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (InstancesClient client = InstancesClient.create()) {
      Instance instanceResource =
              buildInstanceResource(instanceName, disk, machineType, externalAccess, isSpot);

      InsertInstanceRequest build = InsertInstanceRequest.newBuilder()
              .setProject(projectId)
              .setRequestId(UUID.randomUUID().toString())
              .setZone(zone)
              .setInstanceResource(instanceResource)
              .build();
      client.insertCallable().futureCall(build).get(60, TimeUnit.SECONDS);

      return client.get(projectId, zone, instanceName);
    }
  }

  private static Instance buildInstanceResource(String instanceName, AttachedDisk disk,
                                                String machineType, boolean externalAccess,
                                                boolean isSpot) {
    NetworkInterface networkInterface =
            networkInterface(externalAccess);
    Instance.Builder builder = Instance.newBuilder()
            .setName(instanceName)
            .addDisks(disk)
            .setMachineType(machineType)
            .addNetworkInterfaces(networkInterface);

    if (isSpot) {
      // Set the Spot VM setting
      Scheduling.Builder scheduling = builder.getScheduling()
              .toBuilder()
              .setProvisioningModel(ProvisioningModel.SPOT.name())
              .setInstanceTerminationAction("STOP");
      builder.setScheduling(scheduling);
    }

    return builder.build();
  }

  private static NetworkInterface networkInterface(boolean externalAccess) {
    NetworkInterface.Builder build = NetworkInterface.newBuilder()
            .setNetwork("global/networks/default");

    if (externalAccess) {
      AccessConfig.Builder accessConfig = AccessConfig.newBuilder()
              .setType(Type.ONE_TO_ONE_NAT.name())
              .setName("External NAT")
              .setNetworkTier(NetworkTier.PREMIUM.name());
      build.addAccessConfigs(accessConfig.build());
    }

    return build.build();
  }

  private static AttachedDisk buildAttachedDisk(String sourceImage, String zone) {
    AttachedDiskInitializeParams initializeParams = AttachedDiskInitializeParams.newBuilder()
            .setSourceImage(sourceImage)
            .setDiskSizeGb(10)
            .setDiskType(String.format("zones/%s/diskTypes/pd-standard", zone))
            .build();
    return AttachedDisk.newBuilder()
            .setInitializeParams(initializeParams)
            // Remember to set auto_delete to True if you want the disk to be deleted
            // when you delete your VM instance.
            .setAutoDelete(true)
            .setBoot(true)
            .build();
  }
}

Python

בדוגמה הבאה נוצרת מכונה וירטואלית (VM) במודל Spot ללא סקריפט כיבוי לטיפול בהפסקה זמנית. מידע נוסף על הגדרת סקריפט כיבוי למכונה וירטואלית חדשה או קיימת זמין במאמר הרצת סקריפטים של כיבוי. דוגמה לסקריפט כיבוי מופיעה בקטע טיפול בדחיקה במסמך הזה.

from __future__ import annotations

import re
import sys
from typing import Any
import warnings

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1


def get_image_from_family(project: str, family: str) -> compute_v1.Image:
    """
    Retrieve the newest image that is part of a given family in a project.

    Args:
        project: project ID or project number of the Cloud project you want to get image from.
        family: name of the image family you want to get image from.

    Returns:
        An Image object.
    """
    image_client = compute_v1.ImagesClient()
    # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details
    newest_image = image_client.get_from_family(project=project, family=family)
    return newest_image


def disk_from_image(
    disk_type: str,
    disk_size_gb: int,
    boot: bool,
    source_image: str,
    auto_delete: bool = True,
) -> compute_v1.AttachedDisk:
    """
    Create an AttachedDisk object to be used in VM instance creation. Uses an image as the
    source for the new disk.

    Args:
         disk_type: the type of disk you want to create. This value uses the following format:
            "zones/{zone}/diskTypes/(pd-standard|pd-ssd|pd-balanced|pd-extreme)".
            For example: "zones/us-west3-b/diskTypes/pd-ssd"
        disk_size_gb: size of the new disk in gigabytes
        boot: boolean flag indicating whether this disk should be used as a boot disk of an instance
        source_image: source image to use when creating this disk. You must have read access to this disk. This can be one
            of the publicly available images or an image from one of your projects.
            This value uses the following format: "projects/{project_name}/global/images/{image_name}"
        auto_delete: boolean flag indicating whether this disk should be deleted with the VM that uses it

    Returns:
        AttachedDisk object configured to be created using the specified image.
    """
    boot_disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = source_image
    initialize_params.disk_size_gb = disk_size_gb
    initialize_params.disk_type = disk_type
    boot_disk.initialize_params = initialize_params
    # Remember to set auto_delete to True if you want the disk to be deleted when you delete
    # your VM instance.
    boot_disk.auto_delete = auto_delete
    boot_disk.boot = boot
    return boot_disk


def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    Waits for the extended (long-running) operation to complete.

    If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result


def create_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    disks: list[compute_v1.AttachedDisk],
    machine_type: str = "n1-standard-1",
    network_link: str = "global/networks/default",
    subnetwork_link: str = None,
    internal_ip: str = None,
    external_access: bool = False,
    external_ipv4: str = None,
    accelerators: list[compute_v1.AcceleratorConfig] = None,
    preemptible: bool = False,
    spot: bool = False,
    instance_termination_action: str = "STOP",
    custom_hostname: str = None,
    delete_protection: bool = False,
) -> compute_v1.Instance:
    """
    Send an instance creation request to the Compute Engine API and wait for it to complete.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone to create the instance in. For example: "us-west3-b"
        instance_name: name of the new virtual machine (VM) instance.
        disks: a list of compute_v1.AttachedDisk objects describing the disks
            you want to attach to your new instance.
        machine_type: machine type of the VM being created. This value uses the
            following format: "zones/{zone}/machineTypes/{type_name}".
            For example: "zones/europe-west3-c/machineTypes/f1-micro"
        network_link: name of the network you want the new instance to use.
            For example: "global/networks/default" represents the network
            named "default", which is created automatically for each project.
        subnetwork_link: name of the subnetwork you want the new instance to use.
            This value uses the following format:
            "regions/{region}/subnetworks/{subnetwork_name}"
        internal_ip: internal IP address you want to assign to the new instance.
            By default, a free address from the pool of available internal IP addresses of
            used subnet will be used.
        external_access: boolean flag indicating if the instance should have an external IPv4
            address assigned.
        external_ipv4: external IPv4 address to be assigned to this instance. If you specify
            an external IP address, it must live in the same region as the zone of the instance.
            This setting requires `external_access` to be set to True to work.
        accelerators: a list of AcceleratorConfig objects describing the accelerators that will
            be attached to the new instance.
        preemptible: boolean value indicating if the new instance should be preemptible
            or not. Preemptible VMs have been deprecated and you should now use Spot VMs.
        spot: boolean value indicating if the new instance should be a Spot VM or not.
        instance_termination_action: What action should be taken once a Spot VM is terminated.
            Possible values: "STOP", "DELETE"
        custom_hostname: Custom hostname of the new VM instance.
            Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
        delete_protection: boolean value indicating if the new virtual machine should be
            protected against deletion or not.
    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()

    # Use the network interface provided in the network_link argument.
    network_interface = compute_v1.NetworkInterface()
    network_interface.network = network_link
    if subnetwork_link:
        network_interface.subnetwork = subnetwork_link

    if internal_ip:
        network_interface.network_i_p = internal_ip

    if external_access:
        access = compute_v1.AccessConfig()
        access.type_ = compute_v1.AccessConfig.Type.ONE_TO_ONE_NAT.name
        access.name = "External NAT"
        access.network_tier = access.NetworkTier.PREMIUM.name
        if external_ipv4:
            access.nat_i_p = external_ipv4
        network_interface.access_configs = [access]

    # Collect information into the Instance object.
    instance = compute_v1.Instance()
    instance.network_interfaces = [network_interface]
    instance.name = instance_name
    instance.disks = disks
    if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type):
        instance.machine_type = machine_type
    else:
        instance.machine_type = f"zones/{zone}/machineTypes/{machine_type}"

    instance.scheduling = compute_v1.Scheduling()
    if accelerators:
        instance.guest_accelerators = accelerators
        instance.scheduling.on_host_maintenance = (
            compute_v1.Scheduling.OnHostMaintenance.TERMINATE.name
        )

    if preemptible:
        # Set the preemptible setting
        warnings.warn(
            "Preemptible VMs are being replaced by Spot VMs.", DeprecationWarning
        )
        instance.scheduling = compute_v1.Scheduling()
        instance.scheduling.preemptible = True

    if spot:
        # Set the Spot VM setting
        instance.scheduling.provisioning_model = (
            compute_v1.Scheduling.ProvisioningModel.SPOT.name
        )
        instance.scheduling.instance_termination_action = instance_termination_action

    if custom_hostname is not None:
        # Set the custom hostname for the instance
        instance.hostname = custom_hostname

    if delete_protection:
        # Set the delete protection bit
        instance.deletion_protection = True

    # Prepare the request to insert an instance.
    request = compute_v1.InsertInstanceRequest()
    request.zone = zone
    request.project = project_id
    request.instance_resource = instance

    # Wait for the create operation to complete.
    print(f"Creating the {instance_name} instance in {zone}...")

    operation = instance_client.insert(request=request)

    wait_for_extended_operation(operation, "instance creation")

    print(f"Instance {instance_name} created.")
    return instance_client.get(project=project_id, zone=zone, instance=instance_name)


def create_spot_instance(
    project_id: str, zone: str, instance_name: str
) -> compute_v1.Instance:
    """
    Create a new Spot VM instance with Debian 10 operating system.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone to create the instance in. For example: "us-west3-b"
        instance_name: name of the new virtual machine (VM) instance.

    Returns:
        Instance object.
    """
    newest_debian = get_image_from_family(project="debian-cloud", family="debian-11")
    disk_type = f"zones/{zone}/diskTypes/pd-standard"
    disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)]
    instance = create_instance(project_id, zone, instance_name, disks, spot=True)
    return instance

הפעלת מכונות וירטואליות במודל Spot

בדומה למכונות וירטואליות אחרות, מכונות וירטואליות מסוג Spot מתחילות לפעול מיד אחרי שהן נוצרות. באופן דומה, אם מכונות וירטואליות מסוג Spot הופסקו, אפשר להפעיל אותן מחדש כדי לחזור למצב RUNNING. אתם יכולים לעצור ולהפעיל מחדש מכונות וירטואליות מסוג Spot שנפלטו כמה פעמים שתרצו, כל עוד יש קיבולת. מידע נוסף זמין במאמר בנושא מחזור החיים של מכונת VM.

אם Compute Engine מפסיק את הפעילות של מכונה וירטואלית (VM) אחת או יותר מסוג Spot בקבוצת מופעי מכונה מנוהלים (MIG) עם התאמה אוטומטית לעומס או באשכול Google Kubernetes Engine‏ (GKE), הקבוצה מפעילה מחדש את המכונות הווירטואליות כשהמשאבים הופכים שוב לזמינים.

זיהוי מודל ההקצאה ופעולת הסיום של מכונת VM

כדי לראות אם מדובר במכונה וירטואלית רגילה, בVM במודל Spot או בVM זמני, צריך לזהות את מודל הקצאת המשאבים של המכונה הווירטואלית. במקרה של VM במודל Spot, אפשר גם לזהות את פעולת הסיום. אפשר לזהות את מודל ההקצאה של מכונה וירטואלית ואת פעולת הסיום שלה באמצעות מסוףCloud de Confiance , ה-CLI של gcloud או Compute Engine API.

המסוף

  1. נכנסים לדף VM instances.

    לדף VM instances

  2. לוחצים על שם המכונה הווירטואלית שרוצים לזהות. ייפתח הדף VM instance details.

  3. עוברים לקטע ניהול בתחתית הדף. בקטע המשנה Availability policies (מדיניות זמינות), מסמנים את האפשרויות הבאות:

    • אם VM provisioning model מוגדר ל-Spot, המכונה הווירטואלית היא VM במודל Spot.
      • האפשרות On VM termination מציינת איזו פעולה לבצע כש-Compute Engine מבצעת דחיקה של המכונה הווירטואלית, כלומר Stop או Delete של המכונה הווירטואלית.
    • אחרת, אם מודל הקצאת המכונה הווירטואלית מוגדר כ-Standard או כ-:
      • אם האפשרות יכולת הפסקה לפני הזמן מוגדרת למופעל, המכונה הווירטואלית היא VM זמני.
      • אחרת, המכונה הווירטואלית היא מכונה וירטואלית רגילה.

gcloud

כדי להוסיף תיאור למכונה וירטואלית באמצעות ה-CLI של gcloud, משתמשים בפקודה gcloud compute instances describe:

gcloud compute instances describe VM_NAME

כאשר VM_NAME הוא השם של המכונה הווירטואלית שרוצים לבדוק.

בפלט, בודקים את השדה scheduling כדי לזהות את המכונה הווירטואלית:

  • אם הפלט כולל את השדה provisioningModel עם הערך SPOT, כמו בדוגמה הבאה, המכונה הווירטואלית היא VM במודל Spot.

    ...
    scheduling:
    ...
    provisioningModel: SPOT
    instanceTerminationAction: TERMINATION_ACTION
    ...
    

    הערך TERMINATION_ACTION מציין איזו פעולה תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, כלומר יפסיק (STOP) או ימחק (DELETE) את המכונה הווירטואלית. אם השדה instanceTerminationAction חסר, ערך ברירת המחדל הוא STOP.

  • אחרת, אם הפלט כולל את השדה provisioningModel עם הערך standard או אם הפלט לא כולל את השדה provisioningModel:

    • אם הפלט כולל את השדה preemptible עם הערך true, המכונה הווירטואלית היא VM זמני.
    • אחרת, המכונה הווירטואלית היא מכונה וירטואלית רגילה.

REST

כדי לתאר מכונה וירטואלית מ-Compute Engine API, משתמשים בשיטה instances.get:

GET https://compute.s3nsapis.fr/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME

מחליפים את מה שכתוב בשדות הבאים:

  • PROJECT_ID: מזהה הפרויקט שבו נמצאת המכונה הווירטואלית.
  • ZONE: האזור שבו נמצאת המכונה הווירטואלית.
  • VM_NAME: השם של המכונה הווירטואלית שרוצים לבדוק.

בפלט, בודקים את השדה scheduling כדי לזהות את המכונה הווירטואלית:

  • אם הפלט כולל את השדה provisioningModel עם הערך SPOT, כמו בדוגמה הבאה, המכונה הווירטואלית היא VM במודל Spot.

    {
      ...
      "scheduling":
      {
         ...
         "provisioningModel": "SPOT",
         "instanceTerminationAction": "TERMINATION_ACTION"
         ...
      },
      ...
    }
    

    הערך TERMINATION_ACTION מציין איזו פעולה תתבצע כש-Compute Engine יבצע דחיקה של המכונה הווירטואלית, כלומר יפסיק (STOP) או ימחק (DELETE) את המכונה הווירטואלית. אם השדה instanceTerminationAction חסר, ערך ברירת המחדל הוא STOP.

  • אחרת, אם הפלט כולל את השדה provisioningModel עם הערך standard או אם הפלט לא כולל את השדה provisioningModel:

    • אם הפלט כולל את השדה preemptible עם הערך true, המכונה הווירטואלית היא VM זמני.
    • אחרת, המכונה הווירטואלית היא מכונה וירטואלית רגילה.

המשך


import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	"cloud.google.com/go/compute/apiv1/computepb"
)

// isSpotVM checks if a given instance is a Spot VM or not.
func isSpotVM(w io.Writer, projectID, zone, instanceName string) (bool, error) {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	ctx := context.Background()
	client, err := compute.NewInstancesRESTClient(ctx)
	if err != nil {
		return false, fmt.Errorf("NewInstancesRESTClient: %w", err)
	}
	defer client.Close()

	req := &computepb.GetInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
	}

	instance, err := client.Get(ctx, req)
	if err != nil {
		return false, fmt.Errorf("GetInstance: %w", err)
	}

	isSpot := instance.GetScheduling().GetProvisioningModel() == computepb.Scheduling_SPOT.String()

	var isSpotMessage string
	if !isSpot {
		isSpotMessage = " not"
	}
	fmt.Fprintf(w, "Instance %s is%s spot\n", instanceName, isSpotMessage)

	return instance.GetScheduling().GetProvisioningModel() == computepb.Scheduling_SPOT.String(), nil
}

Java


import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.Scheduling;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

public class CheckIsSpotVm {
  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Name of the virtual machine to check.
    String instanceName = "your-route-name";
    // Name of the zone you want to use. For example: "us-west3-b"
    String zone = "your-zone";

    boolean isSpotVm = isSpotVm(projectId, instanceName, zone);
    System.out.printf("Is %s spot VM instance - %s", instanceName, isSpotVm);
  }

  // Check if a given instance is Spot VM or not.
  public static boolean isSpotVm(String projectId, String instanceName, String zone)
          throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (InstancesClient client = InstancesClient.create()) {
      Instance instance = client.get(projectId, zone, instanceName);

      return instance.getScheduling().getProvisioningModel()
              .equals(Scheduling.ProvisioningModel.SPOT.name());
    }
  }
}

Python

from google.cloud import compute_v1


def is_spot_vm(project_id: str, zone: str, instance_name: str) -> bool:
    """
    Check if a given instance is Spot VM or not.
    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone you want to use. For example: "us-west3-b"
        instance_name: name of the virtual machine to check.
    Returns:
        The Spot VM status of the instance.
    """
    instance_client = compute_v1.InstancesClient()
    instance = instance_client.get(
        project=project_id, zone=zone, instance=instance_name
    )
    return (
        instance.scheduling.provisioning_model
        == compute_v1.Scheduling.ProvisioningModel.SPOT.name
    )

ניהול של הפסקה זמנית של VM במודל Spot

כדי ללמוד איך לנהל את ההפסקה הזמנית של VM במודל Spot, אפשר לעיין בקטעים הבאים:

התמודדות עם הפסקה זמנית

כש-Compute Engine מתחיל להפסיק את הפעילות של מכונת Spot, אפשר לנסות לבצע פעולות ניקוי לפני שהמכונה הווירטואלית מסיימת את ההשבתה. הטיפול בשיבוש יכול לכלול עצירה מסודרת של תהליך שפועל והעברה של מצב עומס העבודה.

אפשר להשתמש בשיטות הבאות כדי לטפל בהפסקה זמנית של VM במודל Spot:

  • טיפול בהפקעה בעומס העבודה. אנחנו ממליצים על השיטה הזו למכונות וירטואליות מסוג Spot עם משך זמן של 120 שניות להודעה על הפסקת השימוש (גרסת Preview). באופן ספציפי, במסגרת עומס העבודה, צריך להגדיר קוד לטיפול בהפקעה כדי להמתין להפעלה עד שההפקעה תתחיל, כפי שמוסבר במאמר זיהוי הפקעה במכונה וירטואלית. לאחר מכן, הקוד לטיפול בהקדמה יפעל במהלך משך הודעת ההקדמה. (אופציונלי, במכונות הווירטואליות האלה אפשר גם לציין סקריפט כיבוי, שמופעל במהלך תקופת הכיבוי).
  • טיפול בהקדמה בסקריפט כיבוי. אנחנו ממליצים על השיטה הזו למכונות וירטואליות מסוג Spot ללא משך הודעה על הפסקת שימוש, שזו הגדרת ברירת המחדל. באופן ספציפי, צריך להגדיר את הקוד לטיפול בהקדמה בסקריפט כיבוי, כמו שמוצג בדוגמה הבאה. סקריפט ההשבתה פועל אוטומטית למשך עד 30 שניות במהלך תקופת ההשבתה של כל סוג של השבתה. לכן, כדאי להגדיר את הקוד לטיפול בהפסקת פעולה לפני הזמן כך שהוא יפעל רק אם המכונה הווירטואלית מפסיקה לפני הזמן, כמו שמוסבר במאמר זיהוי הפסקת פעולה לפני הזמן במכונה וירטואלית.

בדוגמה הבאה מוסבר איך לטפל בהפסקה זמנית על ידי העלאה של קובץ נקודת ביקורת לקטגוריה של Cloud Storage בסקריפט כיבוי, ואיך להוסיף סקריפט כיבוי בזמן יצירה או עדכון של VM במודל Spot. הסקריפט הזה מופעל כשהמכונה הווירטואלית מתחילה להיסגר, לפני שהפקודה הרגילה kill של מערכת ההפעלה מפסיקה את כל התהליכים שנותרו. אחרי עצירה מסודרת של תוכנית מסוימת, הסקריפט מבצע העלאה מקבילה של קובץ נקודת ביקורת לקטגוריה של Cloud Storage.

#!/bin/bash

MY_PROGRAM="PROGRAM_NAME" # For example, "apache2" or "nginx"
MY_USER="LOCAL_USER"
CHECKPOINT="/home/$MY_USER/checkpoint.out"
BUCKET_NAME="BUCKET_NAME" # For example, "my-checkpoint-files" (without gs://)

echo "Shutting down!  Seeing if ${MY_PROGRAM} is running."

# Find the newest copy of $MY_PROGRAM
PID="$(pgrep -n "$MY_PROGRAM")"

if [[ "$?" -ne 0 ]]; then
  echo "${MY_PROGRAM} not running, shutting down immediately."
  exit 0
fi

echo "Sending SIGINT to $PID"
kill -2 "$PID"

# Portable waitpid equivalent
while kill -0 "$PID"; do
   sleep 1
done

echo "$PID is done, copying ${CHECKPOINT} to gs://${BUCKET_NAME} as ${MY_USER}"

su "${MY_USER}" -c "gcloud storage cp $CHECKPOINT gs://${BUCKET_NAME}/"

echo "Done uploading, shutting down."

הסקריפט הזה יוצא מנקודת הנחה לגבי הדברים הבאים:

  • מכונת ה-VM נוצרה עם גישת קריאה/כתיבה לפחות ל-Cloud Storage. הוראות ליצירת מכונה וירטואלית עם היקפי ההרשאות המתאימים זמינות במסמכי התיעוד בנושא אימות.

  • יש לכם קטגוריה של Cloud Storage קיימת והרשאה לכתוב בה.

כדי להוסיף את הסקריפט הזה למכונה וירטואלית, צריך להגדיר את הסקריפט כך שיפעל עם עומס העבודה במכונה הווירטואלית ולהוסיף אותו למטא-נתונים של המכונה הווירטואלית.

  1. מעתיקים או מורידים את סקריפט הכיבוי:

    • מעתיקים את סקריפט הכיבוי הקודם אחרי שמחליפים את הערכים הבאים:

      • PROGRAM_NAME: השם של התהליך או התוכנית שרוצים לסגור. לדוגמה, apache2 או nginx.
      • LOCAL_USER: שם המשתמש שדרכו נכנסתם למכונה הווירטואלית.
      • BUCKET_NAME: השם של הקטגוריה ב-Cloud Storage שבה רוצים לשמור את קובץ נקודת הבדיקה של התוכנית. שימו לב שבמקרה הזה שם הקטגוריה לא מתחיל ב-gs://.
    • מורידים את סקריפט ההשבתה לתחנת העבודה המקומית ואז מחליפים את המשתנים הבאים בקובץ:

      • PROGRAM_NAME: השם של התהליך או התוכנית שרוצים לסגור. לדוגמה, apache2 או nginx.
      • LOCAL_USER: שם המשתמש שדרכו נכנסתם למכונה הווירטואלית.
      • BUCKET_NAME: השם של הקטגוריה ב-Cloud Storage שבה רוצים לשמור את קובץ נקודת הבדיקה של התוכנית. שימו לב שבמקרה הזה שם הקטגוריה לא מתחיל ב-gs://.
  2. מוסיפים את סקריפט הכיבוי למכונה וירטואלית חדשה או למכונה וירטואלית קיימת.

זיהוי של הפסקת שימוש במכונות וירטואליות במודל Spot

בקטעים הבאים מוסבר על השיטות שבהן אפשר להשתמש כדי לזהות את ההפסקות של מכונות וירטואליות מסוג Spot.

זיהוי של הפסקת פעולה במכונה וירטואלית

כדי לזהות אם מתבצעת הפסקה של מכונה וירטואלית מתוך המכונה הווירטואלית עצמה, בודקים את הערך preempted במטא-נתוני ברירת המחדל של המכונה הווירטואלית בשרת המטא-נתונים. לדוגמה, אפשר להשתמש בשיטות הבאות:

  • כדאי לבדוק את הערך הנוכחי של preempted. אפשר להריץ את הפקודה הבאה של curl מתוך מכונת ה-VM כדי לקבל את הערך הנוכחי של preempted:

    curl "http://metadata.google.internal/computeMetadata/v1/instance/preempted" -H "Metadata-Flavor: Google"
    TRUE
    

    אם הערך הוא TRUE, המכונה הווירטואלית נדחקה על ידי Compute Engine, אחרת הערך הוא FALSE. לדוגמה, אפשר להשתמש בפקודה הזו בסקריפט של כיבוי כדי לבדוק אם הכיבוי נגרם כתוצאה מקדימות או לא.

  • מחכים עד שpreempted יהיה TRUE. כדי להמתין עד ש-preempted יהיה TRUE, אפשר להוסיף את המחרוזת ?wait_for_change=true לכתובת ה-URL של הפקודה הקודמת. הפקודה הזו מבצעת בקשת HTTP GET תלויה שמוחזרת רק כשהמטא-נתונים השתנו והמכונה הווירטואלית נדחקה.

    curl "http://metadata.google.internal/computeMetadata/v1/instance/preempted?wait_for_change=true" -H "Metadata-Flavor: Google"
    TRUE
    

    הפקודה הזו שימושית כשרוצים להפעיל טיפול בהקדמה מחוץ לסקריפט כיבוי. לדוגמה, אפשר להשתמש בשיטה הזו כדי להפעיל טיפול בהפסקת פעולה של מכונות וירטואליות מסוג Spot עם משך הודעה של 120 שניות על הפסקת פעולה (גרסת Preview).

הצגת פעולות של קדימות

אפשר לראות את פעולות ההפקעה מ-Compute Engine באמצעותCloud de Confiance console,‏ ה-CLI של gcloud או Compute Engine API.

המסוף

כדי לבדוק אם מכונה וירטואלית נדחקה, אפשר לעיין ביומני פעילות המערכת.

  1. נכנסים לדף Logs במסוף Cloud de Confiance .

    כניסה לדף Logs

  2. בוחרים פרויקט ולוחצים על המשך.

  3. מוסיפים compute.instances.preempted לשדה סינון לפי תווית או חיפוש טקסט.

  4. אופציונלי, אפשר גם להזין שם של מכונה וירטואלית אם רוצים לראות פעולות של קדימות למכונה וירטואלית ספציפית.

  5. מקישים על Enter כדי להחיל את המסננים שצוינו. במסוף Cloud de Confiance מתעדכנת רשימת היומנים ומוצגות רק הפעולות שבהן בוצעה קדימה למכונה וירטואלית.

  6. בוחרים פעולה ברשימה כדי לראות פרטים על המכונה הווירטואלית שנפסקה.

gcloud

משתמשים בפקודה gcloud compute operations list עם פרמטר filter כדי לקבל רשימה של אירועי קדימות בפרויקט.

gcloud compute operations list \
    --filter="operationType=compute.instances.preempted"

אם רוצים, אפשר להשתמש בפרמטרים נוספים של מסננים כדי לצמצם עוד יותר את היקף התוצאות. לדוגמה, כדי לראות אירועי הפסקה זמנית רק עבור מכונות בקבוצת מופעי מכונה מנוהלים, משתמשים בפקודה הבאה:

gcloud compute operations list \
    --filter="operationType=compute.instances.preempted AND targetLink:instances/BASE_INSTANCE_NAME"

כאשר BASE_INSTANCE_NAME הוא שם הבסיס שצוין כתחילית לשמות של כל מכונות ה-VM בקבוצת מופעי מכונה מנוהלים זו.

הפלט אמור להיראות כך:

NAME                  TYPE                         TARGET                                        HTTP_STATUS STATUS TIMESTAMP
systemevent-yyyyyyyy  compute.instances.preempted  us-central1-f/instances/example-instance-yyy  200         DONE   2015-04-02T12:12:10.881-07:00

סוג הפעולה compute.instances.preempted מציין שבוצעה קדימה למכונה הווירטואלית. אפשר להשתמש בפקודה gcloud compute operations describe כדי לקבל מידע נוסף על פעולת קדימות ספציפית.

gcloud compute operations describe SYSTEM_EVENT \
    --zone=ZONE

מחליפים את מה שכתוב בשדות הבאים:

  • SYSTEM_EVENT: אירוע המערכת מהפלט של הפקודה gcloud compute operations list. לדוגמה: systemevent-yyyyyyyy.
  • ZONE: האזור של אירוע המערכת, לדוגמה: us-central1-f.

הפלט אמור להיראות כך:

...
operationType: compute.instances.preempted
progress: 100
selfLink: https://compute.s3nsapis.fr/compute/v1/projects/my-project/zones/us-central1-f/operations/systemevent-yyyyyyyy
startTime: '2015-04-02T12:12:10.881-07:00'
status: DONE
statusMessage: Instance was preempted.
...

REST

כדי לקבל רשימה של פעולות מערכת מהזמן האחרון בפרויקט ובאזור ספציפיים, משתמשים בשיטה zoneOperations.get.

GET https://compute.s3nsapis.fr/compute/v1/projects/PROJECT_ID/zones/ZONE/operations

מחליפים את מה שכתוב בשדות הבאים:

אפשר גם להוסיף מסנן לבקשת ה-API כדי לצמצם את היקף התגובה ולהציג רק פעולות של קדימות:

operationType="compute.instances.preempted"

לחלופין, כדי לראות פעולות של קדימות למכונה וירטואלית ספציפית, מוסיפים פרמטר targetLink למסנן:

operationType="compute.instances.preempted" AND
targetLink="https://www.s3nsapis.fr/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME

מחליפים את הערכים הבאים: + PROJECT_ID: מזהה הפרויקט. ‫+ ZONE: האזור. ‫+ VM_NAME: השם של מכונה וירטואלית ספציפית באזור ובפרויקט הזה.

התגובה מכילה רשימה של פעולות מהזמן האחרון. לדוגמה, דחיקה תיראה כך:

{
  "kind": "compute#operation",
  "id": "15041793718812375371",
  "name": "systemevent-yyyyyyyy",
  "zone": "https://www.s3nsapis.fr/compute/v1/projects/my-project/zones/us-central1-f",
  "operationType": "compute.instances.preempted",
  "targetLink": "https://www.s3nsapis.fr/compute/v1/projects/my-project/zones/us-central1-f/instances/example-instance",
  "targetId": "12820389800990687210",
  "status": "DONE",
  "statusMessage": "Instance was preempted.",
  ...
}

בדיקת הגדרות הקדימות

אתם יכולים להריץ סימולציות של אירועי תחזוקה במכונות וירטואליות מסוג Spot כדי לכפות עליהן את הפסקת הפעולה. אתם יכולים להשתמש בתכונה הזו כדי לבדוק איך עומסי העבודה שלכם מזהים ומטפלים בהפסקת פעולה. במאמר סימולציה של אירוע תחזוקה במארח מוסבר איך לבדוק אירועי תחזוקה במכונות.

שיטות מומלצות

כדי להפיק את המקסימום משימוש במכונות וירטואליות מסוג Spot, כדאי לפעול לפי השיטות המומלצות הבאות.

  • איך בודקים את הזמינות של משאבים לפני שיוצרים מכונות וירטואליות מסוג Spot, או אם מנסים ליצור מכונות וירטואליות מסוג Spot אבל נתקלים שוב ושוב בשגיאות שקשורות לזמינות משאבים, אפשר לראות את הזמינות של סוג מכונה באזור או בתחום ספציפיים. בדיקת הזמינות של משאבים עוזרת להגדיל את הסיכויים ליצור מכונות וירטואליות מסוג Spot בהצלחה. הוראות מפורטות זמינות במאמר בנושא צפייה בזמינות של מכונות VM מסוג Spot.

  • איך רואים את הנתונים ההיסטוריים לפני שיוצרים מכונות וירטואליות מסוג Spot, אפשר לראות את שיעור ההפקעה ההיסטורי ואת התמחור ההיסטורי של סוגי המכונות שבהן רוצים להשתמש במכונות הווירטואליות מסוג Spot. המידע הזה עוזר לכם להשוות בין סוגי המכונות ולבחור את הסוג שהכי מתאים לעומס העבודה ולצרכים שלכם מבחינת עלויות. הוראות מפורטות במאמר איך צופים בשיעור ההפקעה ובמחירים של מכונות Spot VM.

  • שימוש בתבניות של מכונות וירטואליות במקום ליצור מכונות וירטואליות (VM) זמניות מסוג Spot אחת בכל פעם, אתם יכולים להשתמש בתבניות של מכונות כדי ליצור כמה מכונות וירטואליות זמניות מסוג Spot עם אותם מאפיינים. כדי להשתמש ב-MIGs, צריך תבניות של הגדרות מכונה. אפשרות אחרת היא ליצור כמה מכונות וירטואליות מסוג Spot באמצעות ה-API ליצירת מכונות וירטואליות בכמות גדולה.

  • שימוש בקבוצות של מכונות וירטואליות לשיפור הזמינות של המשאבים ויצירה מחדש אוטומטית של מכונות וירטואליות מסוג Spot. כדאי להשתמש בקבוצות של מכונות מנוהלות (MIG) כדי להפוך את עומסי העבודה במכונות Spot VM לגמישים ועמידים יותר. לדוגמה, כדי למנוע שגיאות שקשורות לזמינות משאבים, אפשר להגדיל את הגמישות של עומס העבודה על ידי מתן אפשרות לפעולות הבאות:

    בנוסף, קבוצות MIG יכולות לתקן מכונות וירטואליות מסוג Spot שנפסקו על ידי יצירה מחדש שלהן באופן אוטומטי.

  • בוחרים סוגי מכונות קטנים יותר. המשאבים למכונות וירטואליות מסוג Spot מגיעים מקיבולת עודפת ומגיבוי Cloud de Confiance by S3NS . בדרך כלל קל יותר להשיג קיבולת למכונות וירטואליות מסוג Spot עבור סוגי מכונות קטנים יותר, כלומר סוגי מכונות עם פחות משאבים כמו vCPU וזיכרון. יכול להיות שתמצאו יותר קיבולת למכונות וירטואליות מסוג Spot אם תבחרו סוג מכונה קטן יותר בהתאמה אישית, אבל סביר יותר שתמצאו קיבולת אם תבחרו סוג מכונה קטן יותר מוגדר מראש. לדוגמה, בהשוואה לקיבולת של מכונה עם קונפיגורציה מוגדרת (predefined) n2-standard-32, סביר יותר שתהיה קיבולת לסוג המכונה n2-custom-24-96 שמוגדר בהתאמה אישית, אבל סביר עוד יותר שתהיה קיבולת למכונה עם קונפיגורציה מוגדרת (predefined) n2-standard-16.

  • הפעלת אשכולות גדולים של מכונות וירטואליות מסוג Spot בשעות שבהן העומס נמוך. העומס על Cloud de Confiance by S3NS מרכזי הנתונים משתנה בהתאם למיקום ולשעה ביום, אבל בדרך כלל הוא הכי נמוך בלילות ובסופי שבוע. לכן, הלילות וסופי השבוע הם הזמנים הכי טובים להפעלת אשכולות גדולים של מכונות וירטואליות מסוג Spot.

  • תכנון עומסי עבודה (workloads) כך שיהיו עמידים בפני כשלים ושיבושים. חשוב להיות מוכנים לעובדה שיש שינויים בדפוסי הקדימות בנקודות זמן שונות. לדוגמה, אם יש הפסקת חשמל חלקית באזור מסוים, יכול להיות שיהיה צורך לבצע פרימפשן למספר גדול של מכונות וירטואליות זמניות מסוג Spot כדי לפנות מקום למכונות וירטואליות רגילות שצריך להעביר כחלק מהשחזור. בחלון הזמן הקצר הזה, שיעור הקדימות ייראה שונה מאוד ממה שהוא בדרך כלל. אם העומס שלכם מניח שדחיקות תמיד מתבצעות בקבוצות קטנות, יכול להיות שלא תהיו מוכנים לאירוע כזה.

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

  • שימוש בסקריפטים לכיבוי. אפשר לנהל את ההודעות על כיבוי והקצאה מראש באמצעות סקריפט כיבוי שיכול לשמור את ההתקדמות של עבודה מסוימת, כך שהיא תוכל להמשיך מהמקום שבו היא הפסיקה, במקום להתחיל מחדש.

מה השלב הבא?