יצירת קובצי אימג' מותאמים אישית של Windows Server

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

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

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

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

  • אם עדיין לא עשיתם זאת, מגדירים אימות. אימות הוא התהליך שבו הזהות שלכם מאומתת כדי לקבל גישה ל Trusted Cloud by S3NS שירותים ולממשקי API. כדי להריץ קוד או דוגמאות מסביבת פיתוח מקומית, אפשר לבצע אימות ל-Compute Engine על ידי בחירה באחת מהאפשרויות הבאות:

    Select the tab for how you plan to use the samples on this page:

    Console

    When you use the Trusted Cloud console to access Trusted Cloud by S3NS services and APIs, you don't need to set up authentication.

    gcloud

    1. After installing the Google Cloud CLI, sign in to the gcloud CLI with your federated identity and then initialize it by running the following command:

      gcloud init
    2. Set a default region and zone.
    3. Go

      כדי להשתמש בדוגמאות של Go שבדף הזה בסביבת פיתוח מקומית, מתקינים ומפעילים את ה-CLI של gcloud, ואז מגדירים את Application Default Credentials באמצעות פרטי הכניסה של המשתמש.

      1. Install the Google Cloud CLI.

      2. Configure the gcloud CLI to use your federated identity.

        For more information, see Sign in to the gcloud CLI with your federated identity.

      3. To initialize the gcloud CLI, run the following command:

        gcloud init
      4. Create local authentication credentials for your user account:

        gcloud auth application-default login

        If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

      5. למידע נוסף, ראו Set up authentication for a local development environment.

      Java

      כדי להשתמש בדוגמאות של Java שבדף הזה בסביבת פיתוח מקומית, מתקינים ומפעילים את ה-CLI של gcloud, ואז מגדירים את Application Default Credentials באמצעות פרטי הכניסה של המשתמש.

      1. Install the Google Cloud CLI.

      2. Configure the gcloud CLI to use your federated identity.

        For more information, see Sign in to the gcloud CLI with your federated identity.

      3. To initialize the gcloud CLI, run the following command:

        gcloud init
      4. Create local authentication credentials for your user account:

        gcloud auth application-default login

        If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

      5. למידע נוסף, ראו Set up authentication for a local development environment.

      Node.js

      כדי להשתמש בדוגמאות של Node.js שבדף הזה בסביבת פיתוח מקומית, מתקינים ומפעילים את ה-CLI של gcloud, ואז מגדירים את Application Default Credentials באמצעות פרטי הכניסה של המשתמש.

      1. Install the Google Cloud CLI.

      2. Configure the gcloud CLI to use your federated identity.

        For more information, see Sign in to the gcloud CLI with your federated identity.

      3. To initialize the gcloud CLI, run the following command:

        gcloud init
      4. Create local authentication credentials for your user account:

        gcloud auth application-default login

        If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

      5. למידע נוסף, ראו Set up authentication for a local development environment.

      Python

      כדי להשתמש בדוגמאות של Python שבדף הזה בסביבת פיתוח מקומית, מתקינים ומפעילים את ה-CLI של gcloud, ואז מגדירים את Application Default Credentials באמצעות פרטי הכניסה של המשתמש.

      1. Install the Google Cloud CLI.

      2. Configure the gcloud CLI to use your federated identity.

        For more information, see Sign in to the gcloud CLI with your federated identity.

      3. To initialize the gcloud CLI, run the following command:

        gcloud init
      4. Create local authentication credentials for your user account:

        gcloud auth application-default login

        If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

      5. למידע נוסף, ראו Set up authentication for a local development environment.

      REST

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

        After installing the Google Cloud CLI, sign in to the gcloud CLI with your federated identity and then initialize it by running the following command:

        gcloud init

      למידע נוסף, ראו אימות לשימוש ב-REST במסמכי העזרה בנושא Trusted Cloud אימות.

הכנה ליצירת קובץ אימג' של 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 OS Config.
  10. מכבה את המכונה.

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

איך יוצרים קובץ אימג' של Compute Engine באמצעות GCESysprep:

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

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

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

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

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

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

יצירת קובץ אימג' של Windows

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

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

המסוף

  1. במסוף Trusted Cloud , עוברים לדף Create a new image.

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

  2. מציינים את השם של התמונה.
  3. בוחרים דיסק מקור עם מערכת הפעלה של Windows שממנו רוצים ליצור קובץ אימג'.
  4. מציינים את המיקום שבו רוצים לשמור את התמונה. בוחרים מיקום תמונה מהתפריט הנפתח Based on source disk location (default). לדוגמה, מציינים us כדי לאחסן את התמונה במיקום us במספר אזורים, או us-central1 כדי לאחסן אותה באזור us-central1. אם לא תבחרו אזור, המערכת של Compute Engine תשמור את התמונה באזור ה-multi-region הקרוב ביותר למיקום המקור של התמונה.
  5. מציינים את המאפיינים של התמונה. לדוגמה, אפשר לציין שם של משפחת תמונות לתמונה כדי לארגן אותה כחלק ממשפחת תמונות.
  6. לוחצים על יצירה.

gcloud

משתמשים ב-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 תשמור את התמונה באזור ה-multi-region הקרוב ביותר למיקום המקור של התמונה.
  • --force הוא דגל אופציונלי שיוצר את התמונה גם אם הדיסק מחובר למכונה שעדיין פועלת. האפשרות הזו עלולה לפגוע באיכות התמונה. אם אפשר, כדאי להפסיק את המכונה לפני יצירת התמונה.

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

gcloud compute images list

Go

לפני שמנסים את הדוגמה הזו, צריך לפעול לפי הוראות ההגדרה של 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.
      Image image = Image.newBuilder()
          .setName(imageName)
          .setSourceDisk(String.format("/zones/%s/disks/%s", zone, sourceDiskName))
          .addStorageLocations(storageLocation.isEmpty() ? "" : storageLocation)
          .build();

      InsertImageRequest insertImageRequest = InsertImageRequest.newBuilder()
          .setProject(project)
          .setForceCreate(forceCreate)
          .setImageResource(image)
          .build();

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

      if (response.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 compute.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 לשיטה 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 תשמור את התמונה באזור ה-multi-region הקרוב ביותר למיקום המקור של התמונה.

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

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

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

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

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