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


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

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

תמחור

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

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

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

    Console

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

    gcloud

    1. After installing the Google Cloud CLI, initialize it by running the following command:

      gcloud init

      If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

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

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

      1. Install the Google Cloud CLI.

      2. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

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

        gcloud init
      4. If you're using a local shell, then create local authentication credentials for your user account:

        gcloud auth application-default login

        You don't need to do this if you're using Cloud Shell.

        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. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

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

        gcloud init
      4. If you're using a local shell, then create local authentication credentials for your user account:

        gcloud auth application-default login

        You don't need to do this if you're using Cloud Shell.

        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. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

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

        gcloud init
      4. If you're using a local shell, then create local authentication credentials for your user account:

        gcloud auth application-default login

        You don't need to do this if you're using Cloud Shell.

        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. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

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

        gcloud init
      4. If you're using a local shell, then create local authentication credentials for your user account:

        gcloud auth application-default login

        You don't need to do this if you're using Cloud Shell.

        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, initialize it by running the following command:

        gcloud init

        If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

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

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

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

אם אתם צריכים יותר משתי סשנים של Remote Desktop בו-זמנית, תצטרכו לרכוש רישיונות גישה ללקוח (CAL) של Remote Desktop Session ‏ (RDS). מידע נוסף זמין במאמר רישוי הפריסה של RDS באמצעות רישיונות גישה ללקוח (CAL).

עבודה עם Microsoft Active Directory

אם אתם מתכננים להשתמש ב-Microsoft Active Directory‏ (AD) במכונה החדשה, חשוב לוודא שאורך השם של המכונה לא עולה על 15 תווים, כדי לעמוד בהגבלות האורך המקסימלי של השם במערכת.

AD משתמש בשמות NetBIOS של מכונות, שנוצרים כשם המכונה נקטע ל-15 תווים. כתוצאה מכך, יכול להיות שתופיע הודעת השגיאה הבאה כשתנסו להיכנס כמשתמשי דומיין: The Security Database on the Server does not have a Computer Account for this Workstation Trust Relationship.

יצירת מכונה של Windows Server שמשתמשת בכתובת IP חיצונית כדי להפעיל

בקטע הזה מוסבר איך ליצור מכונה של Windows Server עם כתובת IP חיצונית. רשת ה-VPC צריכה להיות מוגדרת כך שתאפשר גישה ל-kms.windows.googlecloud.com.

המסוף

כדי ליצור מכונה וירטואלית בסיסית של Windows:

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

    כניסה לדף Create an instance

  2. בשדה Boot disk, בוחרים באפשרות Change (שינוי) ומבצעים את הפעולות הבאות:

    1. בכרטיסייה Public images בוחרים מערכת הפעלה של Windows Server.
    2. לוחצים על בחירה.
  3. כדי ליצור את המכונה הווירטואלית (VM), לוחצים על האפשרות Create.

כדי ליצור מכונה וירטואלית (VM) של Windows עם מגן:

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

    כניסה לדף Create an instance

  2. בשדה Boot disk, בוחרים באפשרות Change (שינוי) ומבצעים את הפעולות הבאות:

    1. בכרטיסייה Public images בוחרים מערכת הפעלה של Windows Server.
    2. כדי לשמור את ההגדרות של דיסק האתחול, לוחצים על Select.
  3. לחלופין, כדי לשנות את ההגדרות של המכונה הווירטואלית המוגנת, מרחיבים את הקטע Advanced options. לאחר מכן, מבצעים את הפעולות הבאות:

    1. מרחיבים את הקטע Security.
    2. אם רוצים להשבית את Secure Boot, מבטלים את הסימון בתיבה Turn on Secure Boot. הפעלה מאובטחת עוזרת להגן על המכונות הווירטואליות מפני תוכנות זדוניות ברמת האתחול וברמת הליבה ותוכנות rootkit. מידע נוסף זמין במאמר Secure Boot.
    3. אם רוצים להשבית את מודול הפלטפורמה המהימנה הווירטואלי (vTPM), מבטלים את הסימון בתיבה הפעלת vTPM. ה-vTPM מאפשר אתחול מדוד, שמאמת את התקינות של המכונה הווירטואלית לפני האתחול ואת התקינות של האתחול. למידע נוסף, ראו מודול פלטפורמה מהימן וירטואלי (vTPM).

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

  4. כדי ליצור את המכונה הווירטואלית (VM), לוחצים על האפשרות Create.

gcloud

משתמשים בפקודה compute images list כדי לראות רשימה של קובצי אימג' של Windows Server שזמינים:

gcloud compute images list --project windows-cloud --no-standard-images

כדי לבדוק אם תמונה תומכת בתכונות של מכונות וירטואליות מוגנות, מריצים את הפקודה הבאה ובודקים אם הערך UEFI_COMPATIBLE מופיע בפלט:

gcloud compute images describe IMAGE_NAME --project windows-cloud

מחליפים את IMAGE_NAME בשם של קובץ האימג' כדי לבדוק את התמיכה בתכונות של מכונות וירטואליות מוגנות.

משתמשים בפקודה compute instances create כדי ליצור מכונה חדשה ולציין את משפחת התמונות של אחת מהתמונות הציבוריות של Windows Server.

gcloud compute instances create INSTANCE_NAME \
    --image-project windows-cloud \
    --image-family IMAGE_FAMILY \
    --machine-type MACHINE_TYPE \
    --boot-disk-size BOOT_DISK_SIZE \
    --boot-disk-type BOOT_DISK_TYPE

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

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

  • --no-shielded-secure-boot: משביתים את ההפעלה המאובטחת. הפעלה מאובטחת עוזרת להגן על המכונות הווירטואליות מפני תוכנות זדוניות ברמת האתחול וברמת הליבה, וגם מפני רוטקיטים. מידע נוסף זמין במאמר Secure Boot.
  • --no-shielded-vtpm: השבתת מודול הפלטפורמה המהימנה הווירטואלי (vTPM). ה-vTPM מאפשר אתחול מדוד, שמאמת את התקינות של המכונה הווירטואלית לפני האתחול ואת התקינות של האתחול. מידע נוסף זמין במאמר מודול פלטפורמה מהימן וירטואלי (vTPM).

  • --no-shielded-integrity-monitoring: השבתת מעקב אחרי תקינות. בעזרת ניטור התקינות תוכלו לעקוב אחרי התקינות של אתחול המכונות הווירטואליות המוגנות באמצעות Cloud Monitoring. מידע נוסף זמין במאמר מעקב אחרי תקינות.

בדוגמה הבאה נוצרת מכונה וירטואלית מוגנת של Windows 2022 עם Secure Boot מושבת:

gcloud compute instances create my-instance \
    --image-family windows-2022 --image-project windows-cloud \
    --no-shielded-secure-boot

Go

import (
	"context"
	"fmt"
	"io"

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

// createWndowsServerInstanceExternalIP creates a new Windows Server instance
// that has an external IP address.
func createWndowsServerInstanceExternalIP(
	w io.Writer,
	projectID, zone, instanceName, machineType, sourceImageFamily string,
) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// machineType := "n1-standard-1"
	// sourceImageFamily := "windows-2022"

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

	disk := &computepb.AttachedDisk{
		// Describe the size and source image of the boot disk to attach to the instance.
		InitializeParams: &computepb.AttachedDiskInitializeParams{
			DiskSizeGb: proto.Int64(64),
			SourceImage: proto.String(
				fmt.Sprintf(
					"projects/windows-cloud/global/images/family/%s",
					sourceImageFamily,
				),
			),
		},
		AutoDelete: proto.Bool(true),
		Boot:       proto.Bool(true),
	}

	network := &computepb.NetworkInterface{
		// If you are using a custom VPC network it must be configured
		// to allow access to kms.windows.googlecloud.com.
		// https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server.
		Name: proto.String("global/networks/default"),
		AccessConfigs: []*computepb.AccessConfig{
			{
				Type: proto.String("ONE_TO_ONE_NAT"),
				Name: proto.String("External NAT"),
			},
		},
	}

	inst := &computepb.Instance{
		Name: proto.String(instanceName),
		Disks: []*computepb.AttachedDisk{
			disk,
		},
		MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/%s", zone, machineType)),
		NetworkInterfaces: []*computepb.NetworkInterface{
			network,
		},
		// If you chose an image that supports Shielded VM,
		// you can optionally change the instance's Shielded VM settings.
		// ShieldedInstanceConfig: &computepb.ShieldedInstanceConfig{
		// 	EnableSecureBoot: proto.Bool(true),
		// 	EnableVtpm: proto.Bool(true),
		// 	EnableIntegrityMonitoring: proto.Bool(true),
		// },
	}

	req := &computepb.InsertInstanceRequest{
		Project:          projectID,
		Zone:             zone,
		InstanceResource: inst,
	}

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

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

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

	return nil
}

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
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.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateWindowsServerInstanceExternalIp {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // projectId - ID or number of the project you want to use.
    String projectId = "your-google-cloud-project-id";

    // zone - Name of the zone you want to use, for example: us-west3-b
    String zone = "europe-central2-b";

    // instanceName - Name of the new machine.
    String instanceName = "instance-name";

    createWindowsServerInstanceExternalIp(projectId, zone, instanceName);
  }

  // Creates a new Windows Server instance that has an external IP address.
  public static void createWindowsServerInstanceExternalIp(String projectId, String zone,
      String instanceName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    // machineType - Machine type you want to create in following format:
    //  *    "zones/{zone}/machineTypes/{type_name}". For example:
    //  *    "zones/europe-west3-c/machineTypes/f1-micro"
    //  *    You can find the list of available machine types using:
    //  *    https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
    String machineType = "n1-standard-1";
    // sourceImageFamily - Name of the public image family for Windows Server or SQL Server images.
    //  *    https://cloud.google.com/compute/docs/images#os-compute-support
    String sourceImageFamily = "windows-2022";

    // Instantiates a client.
    try (InstancesClient instancesClient = InstancesClient.create()) {

      AttachedDisk attachedDisk = AttachedDisk.newBuilder()
          // Describe the size and source image of the boot disk to attach to the instance.
          .setInitializeParams(AttachedDiskInitializeParams.newBuilder()
              .setDiskSizeGb(64)
              .setSourceImage(
                  String.format("projects/windows-cloud/global/images/family/%s",
                      sourceImageFamily))
              .build())
          .setAutoDelete(true)
          .setBoot(true)
          .setType(AttachedDisk.Type.PERSISTENT.toString())
          .build();

      Instance instance = Instance.newBuilder()
          .setName(instanceName)
          .setMachineType(String.format("zones/%s/machineTypes/%s", zone, machineType))
          .addDisks(attachedDisk)
          .addNetworkInterfaces(NetworkInterface.newBuilder()
              .addAccessConfigs(AccessConfig.newBuilder()
                  .setType("ONE_TO_ONE_NAT")
                  .setName("External NAT")
                  .build())
              // If you're going to use a custom VPC network, it must be configured
              // to allow access to kms.windows.googlecloud.com.
              // https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server.
              .setName("global/networks/default")
              .build())
          // If you chose an image that supports Shielded VM, you can optionally change the
          // instance's Shielded VM settings.
          // .setShieldedInstanceConfig(ShieldedInstanceConfig.newBuilder()
          //    .setEnableSecureBoot(true)
          //    .setEnableVtpm(true)
          //    .setEnableIntegrityMonitoring(true)
          //    .build())
          .build();

      InsertInstanceRequest request = InsertInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstanceResource(instance)
          .build();

      // Wait for the operation to complete.
      Operation operation = instancesClient.insertAsync(request).get(5, TimeUnit.MINUTES);

      if (operation.hasError()) {
        System.out.printf("Error in creating instance %s", operation.getError());
        return;
      }

      System.out.printf("Instance created %s", instanceName);
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const zone = 'europe-central2-b';
// const instanceName = 'YOUR_INSTANCE_NAME';
// const machineType = 'n1-standard-1';
// const sourceImageFamily = 'windows-2022';

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

async function createWindowsServerInstanceExpernalIP() {
  const instancesClient = new compute.InstancesClient();

  const [response] = await instancesClient.insert({
    instanceResource: {
      name: instanceName,
      disks: [
        {
          // Describe the size and source image of the boot disk to attach to the instance.
          initializeParams: {
            diskSizeGb: '64',
            sourceImage: `projects/windows-cloud/global/images/family/${sourceImageFamily}/`,
          },
          autoDelete: true,
          boot: true,
          type: 'PERSISTENT',
        },
      ],
      machineType: `zones/${zone}/machineTypes/${machineType}`,
      networkInterfaces: [
        {
          accessConfigs: [
            {
              type: 'ONE_TO_ONE_NAT',
              name: 'External NAT',
            },
          ],
          // If you are using a custom VPC network it must be configured to allow access to kms.windows.googlecloud.com.
          // https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server.
          name: 'global/networks/default',
        },
      ],
      // If you chose an image that supports Shielded VM, you can optionally change the instance's Shielded VM settings.
      // "shieldedInstanceConfig": {
      //   "enableSecureBoot": true,
      //   "enableVtpm": true,
      //   "enableIntegrityMonitoring": true
      // },
    },
    project: projectId,
    zone,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

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

createWindowsServerInstanceExpernalIP();

Python

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_windows_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    machine_type: str,
    source_image_family: str = "windows-2022",
    network_link: str = "global/networks/default",
    subnetwork_link: str | None = None,
) -> compute_v1.Instance:
    """
    Creates a new Windows Server instance that has only an internal IP address.

    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.
        machine_type: machine type you want to create in following format:
            "zones/{zone}/machineTypes/{type_name}". For example:
            "zones/europe-west3-c/machineTypes/f1-micro"
            You can find the list of available machine types using:
            https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
        source_image_family: name of the public image family for Windows Server or SQL Server images.
            https://cloud.google.com/compute/docs/images#os-compute-support
        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}"

    Returns:
        Instance object.
    """
    if subnetwork_link is None:
        subnetwork_link = f"regions/{zone}/subnetworks/default"

    base_image = get_image_from_family(
        project="windows-cloud", family=source_image_family
    )
    disk_type = f"zones/{zone}/diskTypes/pd-standard"
    disks = [disk_from_image(disk_type, 100, True, base_image.self_link, True)]

    # You must verify or configure routes and firewall rules in your VPC network
    # to allow access to kms.windows.googlecloud.com.
    # More information about access to kms.windows.googlecloud.com: https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server

    # Additionally, you must enable Private Google Access for subnets in your VPC network
    # that contain Windows instances with only internal IP addresses.
    # More information about Private Google Access: https://cloud.google.com/vpc/docs/configure-private-google-access#enabling

    instance = create_instance(
        project_id,
        zone,
        instance_name,
        disks,
        machine_type=machine_type,
        network_link=network_link,
        subnetwork_link=subnetwork_link,
        external_access=True,  # Set this to False to disable external IP for your instance
    )
    return instance

REST

כדי ליצור מכונה באמצעות ה-API, צריך לכלול את הנכס initializeParams בבקשה ליצירת המכונה ולציין קובץ אימג' של Windows. לדוגמה, גוף הבקשה יכול להיראות כך:

instance = {
  "name": "INSTANCE_NAME",
  "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
  "disks": [{
      "boot": "true",
      "type": "PERSISTENT",
      "initializeParams": {
         "diskName": "DISK_NAME",
         "sourceImage": "https://www.googleapis.com/compute/v1/projects/windows-cloud/global/images/family/IMAGE_FAMILY",
         "diskSizeGb": "BOOT_DISK_SIZE",
         "diskType": "BOOT_DISK_TYPE",
       }
    }],
  "networkInterfaces": [{
    "accessConfigs": [{
      "type": "ONE_TO_ONE_NAT",
      "name": "External NAT"
     }],
    "network": "global/networks/default"
  }],
  "serviceAccounts": [{
       "email": DEFAULT_SERVICE_EMAIL,
       "scopes": DEFAULT_SCOPES
  }]
}

מחליפים את ה-placeholders הבאים בערכים חוקיים:

אם בחרתם תמונה שתומכת ב-Shielded VM, תוכלו לשנות את ההגדרות של Shielded VM במכונה באמצעות הפריטים הבוליאניים הבאים בגוף הבקשה:

  • enableSecureBoot: הפעלה או השבתה של הפעלה מאובטחת. הפעלה מאובטחת עוזרת להגן על המכונות הווירטואליות מפני תוכנות זדוניות ברמת האתחול וברמת הליבה, וגם מפני רוטקיטים. מידע נוסף זמין במאמר Secure Boot.
  • enableVtpm: הפעלה או השבתה של מודול הפלטפורמה המהימנה הווירטואלי (vTPM). ה-vTPM מאפשר אתחול מדוד, שמאמת את התקינות של המכונה הווירטואלית לפני האתחול ואת התקינות של האתחול. מידע נוסף זמין במאמר מודול פלטפורמה מהימן וירטואלי (vTPM).

  • enableIntegrityMonitoring: הפעלה או השבתה של מעקב אחרי תקינות. ניטור התקינות מאפשר לכם לעקוב אחרי התקינות של אתחול בסביבת זמן ריצה של מכונות וירטואליות מוגנות ולאמת אותה באמצעות דוחות של Cloud Monitoring. מידע נוסף זמין במאמר מעקב אחרי תקינות.

מידע נוסף על יצירת מכונה זמין במסמכי התיעוד של השיטה instances.insert().

אחרי שיוצרים מכונה של Windows או של שרת SQL, צריך להגדיר את הסיסמה הראשונית של המכונה כדי שתוכלו להתחבר למכונה דרך RDP.

בנוסף, אפשר לצרף את המכונה הווירטואלית לדומיין Managed Microsoft AD במהלך יצירת המכונה הווירטואלית או אחרי יצירת המכונה הווירטואלית. מידע נוסף זמין במאמר הצטרפות אוטומטית של מכונה וירטואלית של Windows לדומיין.

יצירת מכונה של Windows Server שמשתמשת בכתובת IP פנימית כדי להפעיל

כדי ליצור מכונה של Windows Server עם כתובת IP פנימית בלבד, צריך לאמת או להגדיר מסלולים וכללי חומת אש ברשת ה-VPC כדי לאפשר גישה ל-kms.windows.googlecloud.com. בנוסף, צריך להפעיל את Private Google Access ברשתות משנה ברשת ה-VPC שמכילות מכונות Windows עם כתובות IP פנימיות בלבד.

gcloud

כשיוצרים מכונה חדשה באמצעות ה-CLI של gcloud, אפשר להשתמש בדגל --no-address כדי לוודא שלא תוקצה לה כתובת IP חיצונית:

gcloud compute instances create INSTANCE_NAME --network NETWORK_NAME \
 --subnet SUBNET_NAME \
 --no-address \
 --zone ZONE \
 --image-project windows-cloud \
 --image-family IMAGE_FAMILY \
 --machine-type MACHINE_TYPE \
 --boot-disk-size BOOT_DISK_SIZE \
 --boot-disk-type BOOT_DISK_TYPE

מחליפים את ה-placeholders הבאים בערכים חוקיים:

  • INSTANCE_NAME: שם למכונה החדשה.
  • SUBNET_NAME: השם של תת-הרשת ברשת ה-VPC שבה תשתמש המכונה. תת-הרשת חייבת להיות באותו אזור שבו נמצא האזור שבחרתם למכונה.
  • IMAGE_FAMILY: אחת מחבילות התמונות הציבוריות של קובצי אימג' של Windows Server.
  • MACHINE_TYPE: אחד מסוגי המכונות הזמינים.
  • BOOT_DISK_SIZE: הגודל של דיסק האתחול ב-GiB. לדיסקים גדולים יותר יש תפוקת נתונים גבוהה יותר.
  • BOOT_DISK_TYPE: הסוג של דיסק האתחול של המכונה. לדוגמה, hyperdisk-balanced או pd-ssd.

Go

import (
	"context"
	"fmt"
	"io"

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

// createWndowsServerInstanceInternalIP creates a new Windows Server instance
// that has only an internal IP address.
func createWndowsServerInstanceInternalIP(
	w io.Writer,
	projectID, zone, instanceName, machineType, sourceImageFamily, networkLink, subnetworkLink string,
) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// machineType := "n1-standard-1"
	// sourceImageFamily := "windows-2022"
	// networkLink := "global/networks/default"
	// subnetworkLink := "regions/europe-central2/subnetworks/default"

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

	disk := &computepb.AttachedDisk{
		// Describe the size and source image of the boot disk to attach to the instance.
		InitializeParams: &computepb.AttachedDiskInitializeParams{
			DiskSizeGb: proto.Int64(64),
			SourceImage: proto.String(
				fmt.Sprintf(
					"projects/windows-cloud/global/images/family/%s",
					sourceImageFamily,
				),
			),
		},
		AutoDelete: proto.Bool(true),
		Boot:       proto.Bool(true),
	}

	network := &computepb.NetworkInterface{
		// You must verify or configure routes and firewall rules in your VPC network
		// to allow access to kms.windows.googlecloud.com.
		// More information about access to kms.windows.googlecloud.com:
		// https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server

		// Additionally, you must enable Private Google Access for subnets in your VPC network
		// that contain Windows instances with only internal IP addresses.
		// More information about Private Google Access:
		// https://cloud.google.com/vpc/docs/configure-private-google-access#enabling
		Name:       proto.String(networkLink),
		Subnetwork: proto.String(subnetworkLink),
	}

	inst := &computepb.Instance{
		Name: proto.String(instanceName),
		Disks: []*computepb.AttachedDisk{
			disk,
		},
		MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/%s", zone, machineType)),
		NetworkInterfaces: []*computepb.NetworkInterface{
			network,
		},
		// If you chose an image that supports Shielded VM,
		// you can optionally change the instance's Shielded VM settings.
		// ShieldedInstanceConfig: &computepb.ShieldedInstanceConfig{
		// 	EnableSecureBoot: proto.Bool(true),
		// 	EnableVtpm: proto.Bool(true),
		// 	EnableIntegrityMonitoring: proto.Bool(true),
		// },
	}

	req := &computepb.InsertInstanceRequest{
		Project:          projectID,
		Zone:             zone,
		InstanceResource: inst,
	}

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

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

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

	return nil
}

Java


import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
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.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateWindowsServerInstanceInternalIp {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // projectId - ID or number of the project you want to use.
    String projectId = "your-google-cloud-project-id";

    // zone - Name of the zone you want to use, for example: us-west3-b
    String zone = "europe-central2-b";

    // instanceName - Name of the new machine.
    String instanceName = "instance-name";

    // networkLink - 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.
    String networkLink = "global/networks/default";

    // subnetworkLink - Name of the subnetwork you want the new instance to use.
    //  *   This value uses the following format:
    //  *   "regions/{region}/subnetworks/{subnetwork_name}"
    String subnetworkLink = "regions/europe-central2/subnetworks/default";

    createWindowsServerInstanceInternalIp(projectId, zone, instanceName, networkLink,
        subnetworkLink);
  }

  // Creates a new Windows Server instance that has only an internal IP address.
  public static void createWindowsServerInstanceInternalIp(String projectId, String zone,
      String instanceName, String networkLink, String subnetworkLink)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    // machineType - Machine type you want to create in following format:
    //  *    "zones/{zone}/machineTypes/{type_name}". For example:
    //  *    "zones/europe-west3-c/machineTypes/f1-micro"
    //  *    You can find the list of available machine types using:
    //  *    https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
    String machineType = "n1-standard-1";
    // sourceImageFamily - Name of the public image family for Windows Server or SQL Server images.
    //  *    https://cloud.google.com/compute/docs/images#os-compute-support
    String sourceImageFamily = "windows-2022";

    // Instantiates a client.
    try (InstancesClient instancesClient = InstancesClient.create()) {

      AttachedDisk attachedDisk = AttachedDisk.newBuilder()
          // Describe the size and source image of the boot disk to attach to the instance.
          .setInitializeParams(AttachedDiskInitializeParams.newBuilder()
              .setDiskSizeGb(64)
              .setSourceImage(
                  String.format("projects/windows-cloud/global/images/family/%s",
                      sourceImageFamily))
              .build())
          .setAutoDelete(true)
          .setBoot(true)
          .setType(AttachedDisk.Type.PERSISTENT.toString())
          .build();

      Instance instance = Instance.newBuilder()
          .setName(instanceName)
          .setMachineType(String.format("zones/%s/machineTypes/%s", zone, machineType))
          .addDisks(attachedDisk)
          .addNetworkInterfaces(NetworkInterface.newBuilder()
              // You must verify or configure routes and firewall rules in your VPC network
              // to allow access to kms.windows.googlecloud.com.
              // More information about access to kms.windows.googlecloud.com: https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server

              // Additionally, you must enable Private Google Access for subnets in your VPC network
              // that contain Windows instances with only internal IP addresses.
              // More information about Private Google Access: https://cloud.google.com/vpc/docs/configure-private-google-access#enabling
              .setName(networkLink)
              .setSubnetwork(subnetworkLink)
              .build())
          // If you chose an image that supports Shielded VM, you can optionally change the
          // instance's Shielded VM settings.
          // .setShieldedInstanceConfig(ShieldedInstanceConfig.newBuilder()
          //    .setEnableSecureBoot(true)
          //    .setEnableVtpm(true)
          //    .setEnableIntegrityMonitoring(true)
          //    .build())
          .build();

      InsertInstanceRequest request = InsertInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstanceResource(instance)
          .build();

      // Wait for the operation to complete.
      Operation operation = instancesClient.insertAsync(request).get(5, TimeUnit.MINUTES);

      if (operation.hasError()) {
        System.out.printf("Error in creating instance %s", operation.getError());
        return;
      }

      System.out.printf("Instance created %s", instanceName);
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const zone = 'europe-central2-b';
// const instanceName = 'YOUR_INSTANCE_NAME';
// const machineType = 'n1-standard-1';
// const sourceImageFamily = 'windows-2022';
// const networkLink = 'global/networks/default';
// const subnetworkLink = 'regions/europe-central2/subnetworks/default';

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

async function createWindowsServerInstanceInternalIP() {
  const instancesClient = new compute.InstancesClient();

  const [response] = await instancesClient.insert({
    instanceResource: {
      name: instanceName,
      disks: [
        {
          // Describe the size and source image of the boot disk to attach to the instance.
          initializeParams: {
            diskSizeGb: '64',
            sourceImage: `projects/windows-cloud/global/images/family/${sourceImageFamily}/`,
          },
          autoDelete: true,
          boot: true,
          type: 'PERSISTENT',
        },
      ],
      machineType: `zones/${zone}/machineTypes/${machineType}`,
      networkInterfaces: [
        {
          // You must verify or configure routes and firewall rules in your VPC network
          // to allow access to kms.windows.googlecloud.com.
          // More information about access to kms.windows.googlecloud.com: https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server

          // Additionally, you must enable Private Google Access for subnets in your VPC network
          // that contain Windows instances with only internal IP addresses.
          // More information about Private Google Access: https://cloud.google.com/vpc/docs/configure-private-google-access#enabling
          name: networkLink,
          subnetwork: subnetworkLink,
        },
      ],
      // If you chose an image that supports Shielded VM, you can optionally change the instance's Shielded VM settings.
      // "shieldedInstanceConfig": {
      //   "enableSecureBoot": true,
      //   "enableVtpm": true,
      //   "enableIntegrityMonitoring": true
      // },
    },
    project: projectId,
    zone,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

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

createWindowsServerInstanceInternalIP();

Python

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_windows_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    machine_type: str,
    source_image_family: str = "windows-2022",
    network_link: str = "global/networks/default",
    subnetwork_link: str | None = None,
) -> compute_v1.Instance:
    """
    Creates a new Windows Server instance that has only an internal IP address.

    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.
        machine_type: machine type you want to create in following format:
            "zones/{zone}/machineTypes/{type_name}". For example:
            "zones/europe-west3-c/machineTypes/f1-micro"
            You can find the list of available machine types using:
            https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list
        source_image_family: name of the public image family for Windows Server or SQL Server images.
            https://cloud.google.com/compute/docs/images#os-compute-support
        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}"

    Returns:
        Instance object.
    """
    if subnetwork_link is None:
        subnetwork_link = f"regions/{zone}/subnetworks/default"

    base_image = get_image_from_family(
        project="windows-cloud", family=source_image_family
    )
    disk_type = f"zones/{zone}/diskTypes/pd-standard"
    disks = [disk_from_image(disk_type, 100, True, base_image.self_link, True)]

    # You must verify or configure routes and firewall rules in your VPC network
    # to allow access to kms.windows.googlecloud.com.
    # More information about access to kms.windows.googlecloud.com: https://cloud.google.com/compute/docs/instances/windows/creating-managing-windows-instances#kms-server

    # Additionally, you must enable Private Google Access for subnets in your VPC network
    # that contain Windows instances with only internal IP addresses.
    # More information about Private Google Access: https://cloud.google.com/vpc/docs/configure-private-google-access#enabling

    instance = create_instance(
        project_id,
        zone,
        instance_name,
        disks,
        machine_type=machine_type,
        network_link=network_link,
        subnetwork_link=subnetwork_link,
        external_access=True,  # Set this to False to disable external IP for your instance
    )
    return instance

למכונה הזו אין כתובת IP חיצונית, ולכן אי אפשר להתחבר אליה ישירות דרך האינטרנט. אפשר להתחבר מרשת אחרת שמחוברת לרשת ה-VPC באמצעות Cloud Interconnect או Cloud VPN, או להתחבר קודם למכונה מבוצרת דרך RDP ואז להתחבר למכונה שיש לה רק כתובת IP פנימית.

בנוסף, אפשר לצרף את המכונה הווירטואלית לדומיין Managed Microsoft AD במהלך יצירת המכונה הווירטואלית או אחרי יצירת המכונה הווירטואלית. מידע נוסף זמין במאמר הצטרפות אוטומטית של מכונה וירטואלית של Windows לדומיין.

הגדרת גישה לכתובת kms.windows.googlecloud.com

כדי להפעיל ולחדש את Windows, רשת ה-VPC שלכם צריכה לעמוד בדרישות הבאות לגבי ניתוב וכללי חומת אש.

דרישות לניתוב

מכונות Windows צריכות להיות מסוגלות להגיע אל kms.windows.googlecloud.com (35.190.247.13 או 2001:4860:4802:32::86) דרך מסלול שהקפיצה הבאה שלו היא שער האינטרנט שמוגדר כברירת מחדל. אי אפשר להפעיל מכונות Windows באמצעות שער NAT מבוסס-מכונה או Cloud NAT, כי kms.windows.googlecloud.com דוחה בקשות הפעלה מכתובות IP שלא אומתו כמכונות Compute Engine.

אפשר להשתמש בנתיב ברירת המחדל ברשת ה-VPC כדי לנתב את התנועה ישירות אל kms.windows.googlecloud.com. אם מסירים את הנתיב הזה, או אם מתכננים לעשות זאת בעתיד, צריך ליצור נתיב סטטי מותאם אישית עם היעד 35.190.247.13 או 2001:4860:4802:32::86, ולהגדיר את הצעד הבא בתור default Internet gateway, באופן הבא:

IPv4 בלבד

gcloud compute routes create mskms-ipv4-route-ipv4-network \
    --destination-range=35.190.247.13/32 \
    --network=ipv4-network \
    --next-hop-gateway=default-internet-gateway

סטאק כפול

gcloud compute routes create mskms-ipv4-route-ipv4-network \
    --destination-range=35.190.247.13/32 \
    --network=ipv4-network \
    --next-hop-gateway=default-internet-gateway
gcloud compute routes create mskms-ipv6-route-ipv6-network \
    --destination-range=2001:4860:4802:32::86/128 \
    --network=ipv6-network \
    --next-hop-gateway=default-internet-gateway

IPv6 בלבד

gcloud compute routes create mskms-ipv6-route-ipv6-network \
    --destination-range=2001:4860:4802:32::86/128 \
    --network=ipv6-network \
    --next-hop-gateway=default-internet-gateway

מחליפים את ipv4-network או ipv6-network בשם של רשת ה-VPC.

נתיב ברירת המחדל או נתיב סטטי מותאם אישית מאפשרים למכונות עם כתובות IP חיצוניות להגיע אל kms.windows.googlecloud.com. אם יש לכם מכונות Windows ללא כתובות IP חיצוניות או שמשתמשות ב-Cloud NAT, עליכם גם להפעיל את Private Google Access כדי שמכונות עם כתובות IP פנימיות בלבד יוכלו לשלוח תנועה לכתובת ה-IP החיצונית של kms.windows.googlecloud.com (35.190.247.13 או 2001:4860:4802:32::86).

דרישות לכלל חומת אש

כלל חומת האש implied allow egress מאפשר למכונות לשלוח בקשות ולקבל תשובות מוגדרות מראש. אלא אם יצרתם כללי חומת אש מותאמים אישית לדחייה של תעבורת נתונים יוצאת (egress), מכונות Windows יכולות לתקשר עם kms.windows.googlecloud.com.

אם מתאימים אישית את כללי חומת האש, מומלץ ליצור כלל הרשאה ליציאה בעדיפות גבוהה שמאפשר באופן מפורש תקשורת עם 35.190.247.13 או 2001:4860:4802:32::86. כך, כשמשנים את כללי חומת האש, לא משביתים בטעות את ההפעלה של Windows.

הדוגמאות הבאות ל-gcloud יוצרות את כלל ההרשאה המומלץ ליציאה עם העדיפות הגבוהה ביותר:

IPv4 בלבד

gcloud compute firewall-rules create mskms-ipv4-firewall-rule-ipv4-network \
    --direction=EGRESS \
    --network=ipv4-network \
    --action=ALLOW \
    --rules=tcp:1688 \
    --destination-ranges=35.190.247.13/32 \
    --priority=0

סטאק כפול

gcloud compute firewall-rules create mskms-ipv4-firewall-rule-ipv4-network \
    --direction=EGRESS \
    --network=ipv4-network \
    --action=ALLOW \
    --rules=tcp:1688 \
    --destination-ranges=35.190.247.13/32 \
    --priority=0
gcloud compute firewall-rules create mskms-ipv6-firewall-rule-ipv6-network \
    --direction=EGRESS \
    --network=ipv6-network \
    --action=ALLOW \
    --rules=tcp:1688 \
    --destination-ranges=2001:4860:4802:32::86/128 \
    --priority=0

IPv6 בלבד

gcloud compute firewall-rules create mskms-ipv6-firewall-rule-ipv6-network \
    --direction=EGRESS \
    --network=ipv6-network \
    --action=ALLOW \
    --rules=tcp:1688 \
    --destination-ranges=2001:4860:4802:32::86/128 \
    --priority=0

מחליפים את ipv4-network או ipv6-network בשם של רשת ה-VPC.

אימות שהמכונה מופעלת

זמני ההפעלה של מכונות Windows ארוכים יותר בגלל תהליך sysprep. יכול להיות שבמסוף Google Cloud יופיע שהמכונה פועלת גם אם תהליך sysprep עדיין לא הושלם. כדי לבדוק אם המכונה הופעל בהצלחה ומוכנה לשימוש, בודקים את הפלט של serial port באמצעות הפקודה הבאה:

gcloud compute instances get-serial-port-output INSTANCE_NAME

מחליפים את INSTANCE_NAME בשם המכונה שרוצים לאמת.

...[snip]...
Running schtasks with arguments /run /tn GCEStartup
-->  SUCCESS: Attempted to run the scheduled task "GCEStartup".
-------------------------------------------------------------
Instance setup finished. INSTANCE_NAME is ready to use.
-------------------------------------------------------------

הפעלה והשבתה של תכונות של מכונות Windows

אם יש לכם מכונות Windows עם גרסאות תמונה v20170509 ואילך או עם גרסאות סוכן 4.1.0 ואילך, תוכלו להגדיר את תצורת המכונה בקובץ תצורה או במטא-נתונים מותאמים אישית של פרויקט או מכונה. קובץ התצורה בפורמט INI, והוא נמצא בנתיב הבא:

C:\Program Files\Google\Compute Engine\instance_configs.cfg

המערכת מעדכנת את הגדרות ההגדרה לפי סדר העדיפויות הבא, מהעדיפות הגבוהה ביותר לנמוכה ביותר:

  1. פרמטרים של תצורה שמגדירים בקובץ התצורה
  2. פרמטרים של הגדרות אישיות שמוגדרים במטא-נתונים מותאמים אישית ברמת המכונה
  3. פרמטרים של הגדרות שהוגדרו במטא-נתונים מותאמים אישית ברמת הפרויקט

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

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

תוכלו להשבית תכונות שונות של מכונות Windows באמצעות הדוגמאות הבאות.

השבתת מנהל החשבון

השבתת מנהל החשבון משביתה גם את האפשרות לאפס סיסמאות באמצעות Google Cloud CLI או Google Cloud המסוף:

  • קובץ תצורה:

    [accountManager]
    disable=true
    
  • במטא-נתונים מותאמים אישית, מגדירים את disable-account-manager לערך true במטא-נתונים.

השבתת מנהל הכתובות

  • הרשומה בקובץ התצורה:

    [addressManager]
    disable=true
    
  • במטא-נתונים מותאמים אישית, מגדירים את disable-address-manager לערך true במטא-נתונים.

Windows Server Failover Clustering

מפעילים את הסוכן של Windows Server Failover Clustering:

  • הרשומה בקובץ התצורה:

    [wsfc]
    enable=true
    
  • במטא-נתונים מותאמים אישית, מגדירים את enable-wsfc לערך true במטא-נתונים.

שימוש במספר מאזני עומסים פנימיים

מציינים את כתובת ה-IP של המכונה הפנימית לאיזון עומסים לצורך אשכול של יתירות (failover). זוהי הגדרה מתקדמת שאין צורך להגדיר באשכול חלופי ייעודי.

בדרך כלל משתמשים במכונה של איזון עומסים פנימי כדי לנתב את תעבורת הרשת למכונה וירטואלית אחת בכל פעם. אם מוסיפים מכונה שנייה של איזון עומסים פנימי שמשתמשת באשכול של מכונות וירטואליות לצורך יתירות (failover) כחלק מקצה עורפי של אתר עם איזון עומסים, יהיו לכם שתי כתובות IP של איזון עומסים פנימי. אם באשכול של חלוקת עומסים בעת כשל נעשה שימוש ב-10.0.0.10 ובמאזן העומסים של האתר נעשה שימוש ב-10.0.0.11, צריך לציין את כתובת ה-IP של מאזן העומסים שבו אתם משתמשים לאשכולות של חלוקת עומסים בעת כשל. כך אפשר להבין איזו כתובת נמצאת בשימוש באשכול.

  • הרשומה בקובץ התצורה:

    [wsfc]
    addresses=10.0.0.10
    
  • במטא-נתונים בהתאמה אישית, מגדירים את wsfc-addrs לערך 10.0.0.10.

שינוי היציאה של סוכן האשכולות

מגדירים את היציאה של סוכן האשכולות של חלוקת העומסים בעת כשל. יציאת ברירת המחדל היא 59998. צריך לציין יציאה רק אם רוצים להשתמש ביציאה אחרת:

  • הרשומה בקובץ התצורה:

    [wsfc]
    port=12345
    
  • במטא-נתונים בהתאמה אישית, מגדירים את wsfc-agent-port למספר היציאה.

הערות לגבי גרסאות של תמונות

בתמונות ישנות יותר לא נעשה שימוש בקובץ תצורה, והן כוללות רק קבוצת משנה של תכונות. בגרסאות תמונה בין v20160112 ל-v20170509, או בגרסאות סוכן Windows בין 3.2.1.0 ל-4.0.0, צריך להשתמש בערכים הבאים של המטא-נתונים בהתאמה אישית:

  • מגדירים את disable-account-manager לערך true במטא-נתונים של המכונה כדי להשבית את מנהל החשבון.
  • מגדירים את disable-address-manager לערך true במטא-נתונים של המכונה כדי להשבית את מנהל הכתובות.

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