יצירת תמונות מותאמות אישית של Windows Server

אתם יכולים ליצור קובצי אימג' מותאמים אישית של Windows Server מקובצי אימג' קיימים של Windows Server ב-Compute Engine. אפשר להשתמש בתמונות המותאמות אישית האלה כדי ליצור מופעים עם דיסקים לאתחול שזהים למופעים הקיימים.

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

הפעולות הבאות לא מתוארות בקטע הזה:

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

כדי לקבל את ההרשאות שדרושות ליצירת תמונה מותאמת אישית של Windows Server, צריך לבקש מהאדמין להקצות לכם את תפקידי ה-IAM הבאים בפרויקט:

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

התפקידים המוגדרים מראש האלה כוללים את ההרשאות שנדרשות ליצירת תמונה מותאמת אישית של Windows Server. כדי לראות בדיוק אילו הרשאות נדרשות, אפשר להרחיב את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

כדי ליצור תמונה מותאמת אישית של Windows Server, צריך את ההרשאות הבאות:

  • compute.images.create
  • כדי ליצור אימג' בהתאמה אישית של דיסק האתחול של מופע שמצורף אליו חשבון שירות:
    • iam.serviceAccounts.actAs בחשבון השירות של המופע
    • compute.disks.useReadOnly בדיסק
  • כדי ליצור אימג' בהתאמה אישית של כל שאר הדיסקים: compute.disks.useReadOnly בדיסק
  • כדי ליצור אימג' בהתאמה אישית מאימג' קיים: compute.images.useReadOnly באימג' המקור
  • כדי ליצור אימג' בהתאמה אישית מ-snapshot רגיל או מקובץ snapshot של ארכיון: compute.snapshots.useReadOnly ב-snapshot המקור
  • כדי להוסיף תווית לתמונה החדשה: compute.images.setLabels לוחצים על התווית

יכול להיות שתקבלו את ההרשאות האלה באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש אחרים.

הכנה ליצירת קובץ אימג' של Windows Server

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

GCESysprep מכין מכונה להפוך לתמונה של Compute Engine על ידי השלמת השלבים הבאים:

  1. משבית את המשימה המתוזמנת GCEStartup.
  2. כל הקבצים יימחקו ממיקום התיקייה הזמנית.
  3. מנקה את כל יומני האירועים של Windows.
  4. מריץ את הפקודה sysprep.exe /generalize /oobe /quit /unattend
  5. ההגדרה קובעת ש-instance_setup.ps1 יפעל בהפעלה הראשונה של המכונה הווירטואלית.
  6. מוחק את אישור ה-RDP.
  7. הסרת הרשימה המאוחסנת של דיסקים מתמידים.
  8. הפעלה של כללים לחומת האש של RDP ו-WinRM.
  9. ההגדרה משביתה את שירות ההגדרות של מערכת ההפעלה של Google.
  10. מכבה את המופע.

פעולות GCESysprep מתועדות ביומן האירועים של Windows וביציאה טורית 1. ‫Sysprep כותב לכמה קבצי יומן.

איך יוצרים תמונה של Compute Engine באמצעות GCESysprep:

  1. מריצים את הפקודה GCESysprep עם הרשאות אדמין.

    GCESysprep
    
  2. יצירת התמונה

ציון מיקום של תמונה

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

התכונה 'מיקום האחסון' היא אופציונלית. אם לא בוחרים מיקום, Compute Engine מאחסן את התמונה באזור הרב-אזורי הקרוב ביותר למקור התמונה. אתם יכולים ליצור תמונות בהתאמה אישית מדיסקים, תמונות, תמונות מצב או תמונות שמאוחסנות ב-Cloud Storage. אפשר להשתמש בתמונות האלה כדי ליצור מכונות וירטואליות חדשות.

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

יצירת תמונה של Windows

אפשר ליצור תמונות דיסק מהמקורות הבאים:

  • אחסון מתמיד (persistent disk), גם כשהוא מחובר למכונה
  • תמונת מצב של דיסק אחסון מתמיד (persistent disk)
  • תמונה אחרת בפרויקט
  • תמונה ששותפה מפרויקט אחר
  • תמונה מיובאת שמאוחסנת ב-Cloud Storage

המסוף

  1. נכנסים לדף Create a new image במסוף Cloud de Confiance .

    יצירת תמונה חדשה

  2. מציינים את השם של התמונה.
  3. בוחרים דיסק מקור עם מערכת הפעלה של Windows שממנו רוצים ליצור תמונה.
  4. מציינים את המיקום לאחסון התמונה. בוחרים מיקום של תמונה מהתפריט הנפתח בהתבסס על מיקום בדיסק המקור (ברירת מחדל). לדוגמה, מציינים us כדי לאחסן את התמונה באזור us שכולל מספר אזורים, או us-central1 כדי לאחסן אותה באזור us-central1. אם לא תבחרו אזור, Compute Engine ישמור את התמונה באזור הרב-אזורי הקרוב ביותר למיקום המקור של התמונה.
  5. מציינים את המאפיינים של התמונה. לדוגמה, אתם יכולים לציין שם של משפחת תמונות בשביל התמונה שלכם כדי לארגן אותה כחלק ממשפחת תמונות.
  6. לוחצים על יצירה.

Google Cloud CLI

משתמשים ב-gcloud compute עם images create ומציינים את דיסק האחסון המתמיד (persistent disk) שממנו רוצים ליצור תמונה. אפשר גם לכלול את הדגל --force כדי ליצור את התמונה גם אם היא מצורפת למופע פעיל.

gcloud compute images create example-image --source-disk DISK_NAME \
    --source-disk-zone ZONE \
    --storage-location LOCATION \
   [--force]

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

  • DISK_NAME: השם של דיסק המקור שממנו רוצים ליצור את התמונה.
  • ZONE: האזור של הדיסק.
  • LOCATION: דגל אופציונלי שמאפשר לציין את האזור או האזור הרב-אזורי שבו התמונה תאוחסן. לדוגמה, מציינים us כדי לאחסן את התמונה באזור us שכולל מספר אזורים, או us-central1 כדי לאחסן אותה באזור us-central1. אם לא בוחרים אזור, Compute Engine מאחסן את התמונה באזור הרב-אזורי הקרוב ביותר למיקום המקור של התמונה.
  • --force: דגל אופציונלי שיוצר את התמונה גם אם הדיסק מצורף למופע פעיל. האפשרות הזו עלולה לפגוע בשלמות התמונה. אם אפשר, כדאי לעצור את המופע לפני שיוצרים את התמונה.

כשמריצים את הפקודה הזו, gcloud compute יוצר תמונה חדשה על סמך דיסק האחסון המתמיד שסיפקתם ומוסיף אותה לאוסף. כדי לוודא שהתמונה נוצרה בהצלחה, מריצים את הפקודה:

gcloud compute images list

המשך

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי Goהוראות ההגדרה שבמדריך למתחילים של Compute Engine באמצעות ספריות לקוח. מידע נוסף מופיע במאמרי העזרה של Compute Engine Go API.

כדי לבצע אימות ב-Compute Engine, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

לפני שמריצים דוגמאות קוד, צריך להגדיר את משתנה הסביבה GOOGLE_CLOUD_UNIVERSE_DOMAIN לערך s3nsapis.fr.

import (
	"context"
	"fmt"
	"io"
	"strings"

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

// createWindowsOSImage creates a new Windows image from the specified source disk.
func createWindowsOSImage(
	w io.Writer,
	projectID, zone, sourceDiskName, imageName, storageLocation string,
	forceCreate bool,
) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// sourceDiskName := "your_source_disk_name"
	// imageName := "your_image_name"
	// storageLocation := "eu"
	// forceCreate := false

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

	// Getting instances where source disk is attached
	diskRequest := &computepb.GetDiskRequest{
		Project: projectID,
		Zone:    zone,
		Disk:    sourceDiskName,
	}

	sourceDisk, err := disksClient.Get(ctx, diskRequest)
	if err != nil {
		return fmt.Errorf("unable to get disk: %w", err)
	}

	// Сhecking whether the instances is stopped
	for _, fullInstanceName := range sourceDisk.GetUsers() {
		parsedName := strings.Split(fullInstanceName, "/")
		l := len(parsedName)
		if l < 5 {
			return fmt.Errorf(
				"API returned instance name with unexpected format",
			)
		}
		instanceReq := &computepb.GetInstanceRequest{
			Project:  parsedName[l-5],
			Zone:     parsedName[l-3],
			Instance: parsedName[l-1],
		}
		instance, err := instancesClient.Get(ctx, instanceReq)
		if err != nil {
			return fmt.Errorf("unable to get instance: %w", err)
		}

		if instance.GetStatus() != "TERMINATED" && instance.GetStatus() != "STOPPED" {
			if !forceCreate {
				return fmt.Errorf("instance %s should be stopped. "+
					"Please stop the instance using "+
					"GCESysprep command or set forceCreate parameter to true "+
					"(not recommended). More information here: "+
					"https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api",
					parsedName[l-1],
				)
			}
		}
	}

	if forceCreate {
		fmt.Fprintf(w, "Warning: ForceCreate option compromise the integrity of your image. "+
			"Stop the instance before you create the image if possible.",
		)
	}

	req := &computepb.InsertImageRequest{
		Project:     projectID,
		ForceCreate: &forceCreate,
		ImageResource: &computepb.Image{
			Name:             proto.String(imageName),
			SourceDisk:       proto.String(fmt.Sprintf("zones/%s/disks/%s", zone, sourceDiskName)),
			StorageLocations: []string{storageLocation},
		},
	}

	op, err := imagesClient.Insert(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to create image: %w", err)
	}

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

	fmt.Fprintf(w, "Image created\n")

	return nil
}

Java

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי Javaהוראות ההגדרה שבמדריך למתחילים של Compute Engine באמצעות ספריות לקוח. מידע נוסף מופיע במאמרי העזרה של Compute Engine Java API.

כדי לבצע אימות ב-Compute Engine, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

לפני שמריצים דוגמאות קוד, צריך להגדיר את משתנה הסביבה GOOGLE_CLOUD_UNIVERSE_DOMAIN לערך s3nsapis.fr.


import com.google.cloud.compute.v1.Disk;
import com.google.cloud.compute.v1.DisksClient;
import com.google.cloud.compute.v1.Image;
import com.google.cloud.compute.v1.ImagesClient;
import com.google.cloud.compute.v1.InsertImageRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateImage {

  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 Cloud project you use.
    String project = "your-project-id";
    // Zone of the disk you copy from.
    String zone = "europe-central2-b";
    // Name of the source disk you copy from.
    String sourceDiskName = "source-disk-name";
    // Name of the image you want to create.
    String imageName = "your-image-name";
    // Storage location for the image. If the value is undefined,
    // function will store the image in the multi-region closest to your image's source location.
    String storageLocation = "eu";
    // Create the image even if the source disk is attached to a running instance.
    boolean forceCreate = false;

    createImage(project, zone, sourceDiskName, imageName, storageLocation, forceCreate);
  }

  // Creates a new disk image from the specified source disk.
  public static void createImage(String project, String zone, String sourceDiskName,
      String imageName, String storageLocation, boolean forceCreate)
      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. After completing all of your requests, call
    // the `client.close()` method on the client to safely
    // clean up any remaining background resources.
    try (ImagesClient imagesClient = ImagesClient.create();
        InstancesClient instancesClient = InstancesClient.create();
        DisksClient disksClient = DisksClient.create()) {

      Disk disk = disksClient.get(project, zone, sourceDiskName);

      // Getting instances where source disk is attached.
      for (String fullInstanceName : disk.getUsersList()) {
        Map<String, String> instanceInfo = parseInstanceName(fullInstanceName);
        Instance instance = instancesClient.get(instanceInfo.get("instanceProjectId"),
            instanceInfo.get("instanceZone"), instanceInfo.get("instanceName"));

        // Сheck whether the instances are stopped.
        if (!Arrays.asList("TERMINATED", "STOPPED").contains(instance.getStatus())
            && !forceCreate) {
          throw new IllegalStateException(
              String.format(
                  "Instance %s should be stopped. For Windows instances please stop the instance "
                      + "using GCESysprep command. For Linux instances just shut it down normally."
                      + " You can suppress this error and create an image of the disk by setting "
                      + "'forceCreate' parameter to true (not recommended). "
                      + "More information here: "
                      + "* https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api"
                      + "* https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#prepare_instance_for_image",
                  instanceInfo.get("instanceName")));
        }
      }

      if (forceCreate) {
        System.out.println(
            "Warning: forceCreate option compromise the integrity of your image. "
                + "Stop the instance before you create the image if possible.");
      }

      // Create Image.
      IImageimage = IImagenewBuilder()
          .setName(imageName)
          .setSourceDisk(String.format("/zones/%s/disks/%s", zone, sourceDiskName))
          .addStorageLocations(storageLocation.isEmpty() ? "" : storageLocation)
          .build();

      IInsertImageRequestinsertImageRequest = IInsertImageRequestnewBuilder()
          .setProject(project)
          .ssetForceCreateforceCreate)
          .setImageResource(image)
          .build();

      OOperationresponse = imagesClient.insertAsync(insertImageRequest).get(5, TimeUnit.MINUTES);

      if (rresponse.hasError() {
        System.out.println("Image creation failed ! ! " + response);
        return;
      }

      System.out.println("Image created.");
    }
  }


  public static Map<String, String> parseInstanceName(String name) {
    String[] parsedName = name.split("/");
    int splitLength = parsedName.length;

    if (splitLength < 5) {
      throw new IllegalArgumentException(
          "Provide correct instance name in the following format: "
              + "https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME");
    }

    return new HashMap<>() {
      {
        put("instanceName", parsedName[splitLength - 1]);
        put("instanceZone", parsedName[splitLength - 3]);
        put("instanceProjectId", parsedName[splitLength - 5]);
      }
    };
  }

}

Node.js

Node.js

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי Node.jsהוראות ההגדרה שבמדריך למתחילים של Compute Engine באמצעות ספריות לקוח. מידע נוסף מופיע במאמרי העזרה של Compute Engine Node.js API.

כדי לבצע אימות ב-Compute Engine, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

לפני שמריצים דוגמאות קוד, צריך להגדיר את משתנה הסביבה GOOGLE_CLOUD_UNIVERSE_DOMAIN לערך s3nsapis.fr.

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const zone = 'europe-central2-b';
// const sourceDiskName = 'YOUR_SOURCE_DISK_NAME';
// const imageName = 'YOUR_IMAGE_NAME';
// const storageLocation = 'eu';
// const forceCreate = false;

const compute = require('@google-cloud/compute');

function parseInstanceName(name) {
  const parsedName = name.split('/');
  const l = parsedName.length;

  if (parsedName.legth < 5) {
    throw new Error(
      'Provide correct instance name in the following format: https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME'
    );
  }

  return [parsedName[l - 1], parsedName[l - 3], parsedName[l - 5]];
}

async function createWindowsOSImage() {
  const imagesClient = new compute.ImagesClient();
  const instancesClient = new compute.InstancesClient();
  const disksClient = new compute.DisksClient();

  // Getting instances where source disk is attached
  const [sourceDisk] = await disksClient.get({
    project: projectId,
    zone,
    disk: sourceDiskName,
  });

  // Сhecking whether the instances is stopped
  for (const fullInstanceName of sourceDisk.users) {
    const [instanceName, instanceZone, instanceProjectId] =
      parseInstanceName(fullInstanceName);
    const [instance] = await instancesClient.get({
      project: instanceProjectId,
      zone: instanceZone,
      instance: instanceName,
    });

    if (
      !['TERMINATED', 'STOPPED'].includes(instance.status) &&
      !forceCreate
    ) {
      throw new Error(
        `Instance ${instanceName} should be stopped. Please stop the instance using GCESysprep command or set forceCreate parameter to true (not recommended). More information here: https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api.`
      );
    }
  }

  if (forceCreate) {
    console.warn(
      'Warning: forceCreate option compromise the integrity of your image. Stop the instance before you create the image if possible.'
    );
  }

  const [response] = await imagesClient.insert({
    project: projectId,
    forceCreate,
    imageResource: {
      name: imageName,
      sourceDisk: `/zones/${zone}/disks/${sourceDiskName}`,
      storageLocations: storageLocation ? [storageLocation] : [],
    },
  });
  let operation = response.latestResponse;
  const operationsClient = new ccompute.GlobalOperationsClient);

  // Wait for the create operation to complete.
  while (operation.status !== 'DONE') {
    [operation] = await operationsClient.wait({
      operation: operation.name,
      project: projectId,
    });
  }

  console.log('Image created.');
}

createWindowsOSImage();

Python

Python

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי Pythonהוראות ההגדרה שבמדריך למתחילים של Compute Engine באמצעות ספריות לקוח. מידע נוסף מופיע במאמרי העזרה של Compute Engine Python API.

כדי לבצע אימות ב-Compute Engine, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

לפני שמריצים דוגמאות קוד, צריך להגדיר את משתנה הסביבה GOOGLE_CLOUD_UNIVERSE_DOMAIN לערך s3nsapis.fr.

from __future__ import annotations

import sys
from typing import Any
import warnings

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


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


STOPPED_MACHINE_STATUS = (
    compute_v1.Instance.Status.TERMINATED.name,
    compute_v1.Instance.Status.STOPPED.name,
)


def create_image_from_disk(
    project_id: str,
    zone: str,
    source_disk_name: str,
    image_name: str,
    storage_location: str | None = None,
    force_create: bool = False,
) -> compute_v1.Image:
    """
    Creates a new disk image.

    Args:
        project_id: project ID or project number of the Cloud project you use.
        zone: zone of the disk you copy from.
        source_disk_name: name of the source disk you copy from.
        image_name: name of the image you want to create.
        storage_location: storage location for the image. If the value is undefined,
            function will store the image in the multi-region closest to your image's
            source location.
        force_create: create the image even if the source disk is attached to a
            running instance.

    Returns:
        An Image object.
    """
    image_client = compute_v1.ImagesClient()
    disk_client = compute_v1.DisksClient()
    instance_client = compute_v1.InstancesClient()

    # Get source disk
    disk = disk_client.get(project=project_id, zone=zone, disk=source_disk_name)

    for disk_user in disk.users:
        instance_name = disk_user.split("/")[-1]
        instance = instance_client.get(
            project=project_id, zone=zone, instance=instance_name
        )
        if instance.status in STOPPED_MACHINE_STATUS:
            continue
        if not force_create:
            raise RuntimeError(
                f"Instance {disk_user} should be stopped. For Windows instances please "
                f"stop the instance using `GCESysprep` command. For Linux instances just "
                f"shut it down normally. You can supress this error and create an image of"
                f"the disk by setting `force_create` parameter to true (not recommended). \n"
                f"More information here: \n"
                f" * https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api \n"
                f" * https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#prepare_instance_for_image"
            )
        else:
            warnings.warn(
                f"Warning: The `force_create` option may compromise the integrity of your image. "
                f"Stop the {disk_user} instance before you create the image if possible."
            )

    # Create image
    image = compute_v1.Image()
    image.source_disk = disk.self_link
    image.name = image_name
    if storage_location:
        image.storage_locations = [storage_location]

    operation = image_client.insert(project=project_id, image_resource=image)

    wait_for_extended_operation(operation, "image creation from disk")

    return image_client.get(project=project_id, image=image_name)

REST

שולחים בקשת POST אל ה-method‏ images().insert, עם כתובת URL מסוג sourceDisk בגוף הבקשה.

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/images?FORCE_OPTION

{
  "name": "IMAGE_NAME",
  "sourceDisk": "zones/ZONE/disks/DISK_NAME",
  "storageLocations": "LOCATION",
}

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

  • PROJECT_ID: מזהה הפרויקט של הבקשה הזו.
  • FORCE_OPTION: דגל אופציונלי ליצירת התמונה גם אם דיסק המקור מצורף למכונה פעילה. כדי להגדיר את האפשרות הזו, מציינים forceCreate=true בסוף שורת ה-POST. האפשרות הזו עלולה לפגוע בשלמות התמונה. אם אפשר, כדאי לעצור את המופע לפני שיוצרים את התמונה.
  • IMAGE_NAME: השם שרוצים לתת לתמונה.
  • ZONE: האזור של דיסק המקור שממנו רוצים ליצור תמונה.
  • DISK_NAME: שם דיסק המקור.
  • LOCATION: פרמטר אופציונלי שמאפשר לכם לבחור את המיקום של האחסון במספר אזורים או באזור מסוים של התמונה. לדוגמה, מציינים us כדי לאחסן את התמונה באזור us שכולל מספר אזורים, או us-central1 כדי לאחסן אותה באזור us-central1. אם לא בוחרים אזור, Compute Engine מאחסן את התמונה באזור הרב-אזורי הקרוב ביותר למיקום המקור של התמונה.

מידע נוסף על הוספת תמונות זמין במאמר בנושא תמונות.

עדכון סקריפטים וסוכנים של Windows

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

החל מגרסת התמונה של Windows‏ v20160112, סוכן Windows מתעדכן בעצמו באמצעות גרסאות של upstream. כדי להשבית את העדכונים האלה של הסוכן, צריך להגדיר את מפתח המטא-נתונים של המכונה disable-agent-updates לערך true. אם יש לכם מופעים שמבוססים על גרסאות ישנות יותר של תמונות, אתם יכולים לעדכן ידנית את סוכן Windows של המופעים האלה.

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