Crear y utilizar máquinas virtuales puntuales


Esta página explica cómo crear y administrar máquinas virtuales puntuales , incluido lo siguiente:

  • Cómo crear, iniciar e identificar máquinas virtuales puntuales
  • Cómo detectar, manejar y probar la preferencia de máquinas virtuales puntuales
  • Mejores prácticas para máquinas virtuales puntuales

Las máquinas virtuales puntuales son instancias de máquinas virtuales (VM) con el modelo de aprovisionamiento puntual . Las máquinas virtuales spot están disponibles con un descuento de hasta el 60 % y el 91 % en comparación con el precio de las máquinas virtuales estándar. Sin embargo, Compute Engine podría reclamar los recursos adelantándose a las VM puntuales en cualquier momento. Las máquinas virtuales puntuales se recomiendan solo para aplicaciones tolerantes a fallas que puedan soportar la preferencia de máquinas virtuales. Asegúrese de que su aplicación pueda manejar la preferencia antes de decidir crear máquinas virtuales puntuales.

Antes de comenzar

  • Lea la documentación conceptual para Spot VM :
    • Revise las limitaciones y los precios de las máquinas virtuales de spot.
    • Para evitar que las máquinas virtuales Spot consuman sus cuotas para las CPU, GPU y discos de las máquinas virtuales estándar, considere solicitar una cuota interrumpible para las máquinas virtuales Spot.
  • Si aún no lo has hecho, configura la autenticación. La autenticación es el proceso mediante el cual se verifica su identidad para acceder a Google Cloud servicios y API. Para ejecutar código o muestras desde un entorno de desarrollo local, puedes autenticarte en Compute Engine seleccionando una de las siguientes opciones:

    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. Terraform

      Para usar las muestras de Terraform de esta página en un entorno de desarrollo local, instala e inicializa gcloud CLI y, luego, configura las credenciales predeterminadas de la aplicación con tus credenciales de usuario.

      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, confirm that you have configured the gcloud CLI to use Workforce Identity Federation.

      Para obtener más información, consulta Set up authentication for a local development environment.

      REST

      Para usar las muestras de la API de REST en esta página en un entorno de desarrollo local, debes usar las credenciales que proporcionas a la CLI de 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.

      Para obtener más información, consulta Autentica para usar REST en la documentación de autenticación de Google Cloud .

Crear una máquina virtual puntual

Cree una máquina virtual puntual mediante la consola de Google Cloud, la CLI de gcloud o la API de Compute Engine. Una máquina virtual puntual es cualquier máquina virtual configurada para utilizar el modelo de aprovisionamiento puntual:

  • Modelo de aprovisionamiento de VM configurado en Spot en la consola de Google Cloud
  • --provisioning-model=SPOT en la CLI de gcloud
  • "provisioningModel": "SPOT" en la API de Compute Engine

Consola

  1. En la consola de Google Cloud, vaya a la página Crear una instancia .

    Ir a Crear una instancia

  2. En el menú de navegación, haga clic en Avanzado . En el panel Avanzado que aparece, complete los siguientes pasos:

    1. En la sección Modelo de aprovisionamiento , seleccione Spot en la lista de modelos de aprovisionamiento de VM .
    2. Opcional: Para seleccionar la acción de terminación que ocurre cuando Compute Engine se adelanta a la VM, completa los siguientes pasos:

      1. Expanda la sección de configuración avanzada del modelo de aprovisionamiento de VM .
      2. En la lista Al terminar VM , seleccione una de las siguientes opciones:
        • Para detener la máquina virtual durante la preferencia, seleccione Detener (predeterminado).
        • Para eliminar la VM durante la preferencia, seleccione Eliminar .
  3. Opcional: especifique otras opciones de configuración. Para obtener más información, consulte Opciones de configuración durante la creación de instancias .

  4. Para crear e iniciar la VM, haga clic en Crear .

nube de gcloud

Para crear una máquina virtual desde la CLI de gcloud, use el comando gcloud compute instances create . Para crear máquinas virtuales puntuales, debe incluir el indicador --provisioning-model=SPOT . Opcionalmente, también puede especificar una acción de terminación para las máquinas virtuales de spot al incluir también el indicador --instance-termination-action .

gcloud compute instances create VM_NAME \
    --provisioning-model=SPOT \
    --instance-termination-action=TERMINATION_ACTION

Reemplace lo siguiente:

  • VM_NAME : nombre de la nueva VM.
  • TERMINATION_ACTION : Opcional: especifica qué acción tomar cuando Compute Engine se adelanta a la VM, ya sea STOP (comportamiento predeterminado) o DELETE .

Para obtener más información sobre las opciones que puede especificar al crear una VM, consulte Opciones de configuración durante la creación de instancias . Por ejemplo, para crear máquinas virtuales puntuales con una imagen y un tipo de máquina específicos, utilice el siguiente comando:

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

Reemplace lo siguiente:

  • VM_NAME : nombre de la nueva VM.
  • IMAGE : especifique uno de los siguientes:
    • IMAGE : una versión específica de una imagen pública o de la familia de imágenes. Por ejemplo, una imagen específica es --image=debian-10-buster-v20200309 .
    • Una familia de imágenes . Esto crea la máquina virtual a partir de la imagen del sistema operativo más reciente y no obsoleta. Por ejemplo, si especifica --image-family=debian-10 , Compute Engine crea una VM a partir de la última versión de la imagen del sistema operativo en la familia de imágenes de Debian 10.
  • IMAGE_PROJECT : el proyecto que contiene la imagen. Por ejemplo, si especifica debian-10 como familia de imágenes, especifique debian-cloud como proyecto de imagen.
  • MACHINE_TYPE : el tipo de máquina predefinido o personalizado para la nueva VM.
  • TERMINATION_ACTION : Opcional: especifica qué acción tomar cuando Compute Engine se adelanta a la VM, ya sea STOP (comportamiento predeterminado) o DELETE .

    Para obtener una lista de los tipos de máquinas disponibles en una zona, use el comando gcloud compute machine-types list con la marca --zones .

Terraformar

Puede utilizar un recurso de Terraform para crear una instancia puntual utilizando un bloque de programación


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

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

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

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

DESCANSAR

Para crear una VM desde la API de Compute Engine, usa el método instances.insert . Debe especificar un tipo de máquina y un nombre para la VM. Opcionalmente, también puede especificar una imagen para el disco de arranque.

Para crear máquinas virtuales de spot, debe incluir el campo "provisioningModel": spot Opcionalmente, también puede especificar una acción de terminación para máquinas virtuales de spot al incluir también el campo "instanceTerminationAction" .

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

Reemplace lo siguiente:

  • PROJECT_ID : la identificación del proyecto en el que se creará la VM.
  • ZONE : la zona en la que se creará la VM. La zona también debe admitir el tipo de máquina que se utilizará para la nueva VM.
  • MACHINE_TYPE : el tipo de máquina predefinido o personalizado para la nueva VM.
  • VM_NAME : el nombre de la nueva VM.
  • IMAGE_PROJECT : el proyecto que contiene la imagen. Por ejemplo, si especifica family/debian-10 como familia de imágenes, especifique debian-cloud como proyecto de imagen.
  • IMAGE : especifique uno de los siguientes:
    • Una versión específica de una imagen pública. Por ejemplo, una imagen específica es "sourceImage": "projects/debian-cloud/global/images/debian-10-buster-v20200309" donde debian-cloud es IMAGE_PROJECT .
    • Una familia de imágenes . Esto crea la máquina virtual a partir de la imagen del sistema operativo más reciente y no obsoleta. Por ejemplo, si especifica "sourceImage": "projects/debian-cloud/global/images/family/debian-10" donde debian-cloud es IMAGE_PROJECT , Compute Engine crea una VM a partir de la última versión de la imagen del sistema operativo en la familia de imágenes de Debian 10.
  • TERMINATION_ACTION : Opcional: especifica qué acción tomar cuando Compute Engine se adelanta a la VM, ya sea STOP (comportamiento predeterminado) o DELETE .

Para obtener más información sobre las opciones que puede especificar al crear una VM, consulte Opciones de configuración durante la creación de instancias .

Ir


import (
	"context"
	"fmt"
	"io"

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

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

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

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

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

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

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

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

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

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

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

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

Java


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

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

    createSpotInstance(projectId, instanceName, zone);
  }

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

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

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

    return instance;
  }

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

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

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

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

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

    return builder.build();
  }

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

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

    return build.build();
  }

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

Pitón

from __future__ import annotations

import re
import sys
from typing import Any
import warnings

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


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

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

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


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

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

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


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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result


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

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

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

    if internal_ip:
        network_interface.network_i_p = internal_ip

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

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

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

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

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

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

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

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

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

    operation = instance_client.insert(request=request)

    wait_for_extended_operation(operation, "instance creation")

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


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

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

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

Para crear varias máquinas virtuales puntuales con las mismas propiedades, puede crear una plantilla de instancia y usarla para crear un grupo de instancias administrado (MIG) . Para obtener más información, consulte las mejores prácticas .

Iniciar máquinas virtuales puntuales

Al igual que otras máquinas virtuales, las máquinas virtuales puntuales comienzan con su creación. Del mismo modo, si se detienen las máquinas virtuales puntuales, puede reiniciarlas para reanudar el estado RUNNING . Puede detener y reiniciar las máquinas virtuales spot con preferencia tantas veces como desee, siempre que haya capacidad. Para obtener más información, consulte Ciclo de vida de la instancia de VM .

Si Compute Engine detiene una o más máquinas virtuales puntuales en un grupo de instancias administradas (MIG) de escalado automático o en un clúster de Google Kubernetes Engine (GKE), el grupo reinicia las máquinas virtuales cuando los recursos vuelven a estar disponibles.

Identificar el modelo de aprovisionamiento de una VM y la acción de terminación

Identifique el modelo de aprovisionamiento de una máquina virtual para ver si es una máquina virtual estándar, una máquina virtual puntual o una máquina virtual interrumpible . Para una máquina virtual puntual, también puede identificar la acción de terminación . Puedes identificar el modelo de aprovisionamiento y la acción de terminación de una VM mediante la consola de Google Cloud, la CLI de gcloud o la API de Compute Engine.

Consola

  1. Vaya a la página de instancias de VM .

    Vaya a la página de instancias de VM

  2. Haga clic en el nombre de la máquina virtual que desea identificar. Se abre la página de detalles de la instancia de VM .

  3. Vaya a la sección Gestión en la parte inferior de la página. En la subsección Políticas de disponibilidad , marque las siguientes opciones:

    • Si el modelo de aprovisionamiento de VM está configurado en Spot , la VM es una VM Spot.
      • Al finalizar la VM indica qué acción tomar cuando Compute Engine se adelanta a la VM, ya sea detenerla o eliminarla .
    • De lo contrario, si el modelo de aprovisionamiento de VM está configurado en Estándar o :
      • Si la opción Preemptibility está configurada en On , la VM es una VM interrumpible.
      • De lo contrario, la VM es una VM estándar.

nube de gcloud

Para describir una VM desde la CLI de gcloud, usa el comando gcloud compute instances describe :

gcloud compute instances describe VM_NAME

donde VM_NAME es el nombre de la VM que desea verificar.

En el resultado, verifique el campo scheduling para identificar la VM:

  • Si el resultado incluye el campo provisioningModel establecido en SPOT , similar al siguiente, la VM es una VM Spot.

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

    donde TERMINATION_ACTION indica qué acción tomar cuando Compute Engine se adelanta a la VM, ya sea detener ( STOP ) o eliminar ( DELETE ) la VM. Si falta el campo instanceTerminationAction , el valor predeterminado es STOP .

  • De lo contrario, si el resultado incluye el campo provisioningModel establecido en standard o si el resultado omite el campo provisioningModel :

    • Si la salida incluye el campo preemptible establecido en true , la VM es una máquina virtual interrumpible.
    • De lo contrario, la VM es una VM estándar.

DESCANSAR

Para describir una VM desde la API de Compute Engine, usa el método instances.get :

GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME

Reemplace lo siguiente:

  • PROJECT_ID : la identificación del proyecto en el que se encuentra la VM.
  • ZONE : la zona donde se encuentra la VM.
  • VM_NAME : el nombre de la VM que desea verificar.

En el resultado, verifique el campo scheduling para identificar la VM:

  • Si el resultado incluye el campo provisioningModel establecido en SPOT , similar al siguiente, la VM es una VM Spot.

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

    donde TERMINATION_ACTION indica qué acción tomar cuando Compute Engine se adelanta a la VM, ya sea detener ( STOP ) o eliminar ( DELETE ) la VM. Si falta el campo instanceTerminationAction , el valor predeterminado es STOP .

  • De lo contrario, si el resultado incluye el campo provisioningModel establecido en standard o si el resultado omite el campo provisioningModel :

    • Si la salida incluye el campo preemptible establecido en true , la VM es una máquina virtual interrumpible.
    • De lo contrario, la VM es una VM estándar.

Ir


import (
	"context"
	"fmt"
	"io"

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

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

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

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

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

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

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

Java


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

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

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

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

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

Pitón

from google.cloud import compute_v1


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

Administrar la preferencia de Spot VM

Para aprender cómo administrar la preferencia de Spot VM, revise las siguientes secciones:

Manejar la preferencia con un script de apagado

Cuando Compute Engine se apropia de una VM puntual, puedes usar una secuencia de comandos de apagado para intentar realizar acciones de limpieza antes de que se apruebe la VM. Por ejemplo, puede detener cómodamente un proceso en ejecución y copiar un archivo de punto de control en Cloud Storage . En particular, la duración máxima del período de cierre es más corta para un aviso de preferencia que para un cierre iniciado por el usuario. Para obtener más información sobre el período de apagado de un aviso de preferencia, consulte Proceso de preferencia en la documentación conceptual para máquinas virtuales puntuales.

El siguiente es un ejemplo de una secuencia de comandos de apagado que puede agregar a una máquina virtual de spot en ejecución o al crear una nueva máquina virtual de spot. Este script se ejecuta cuando la VM comienza a apagarse, antes de que el comando kill normal del sistema operativo detenga todos los procesos restantes. Después de detener correctamente el programa deseado, el script realiza una carga paralela de un archivo de punto de control en un depósito de Cloud Storage.

#!/bin/bash

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

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

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

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

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

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

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

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

echo "Done uploading, shutting down."

Este script asume lo siguiente:

  • La VM se creó con al menos acceso de lectura/escritura a Cloud Storage. Para obtener instrucciones sobre cómo crear una máquina virtual con los ámbitos adecuados, consulte la documentación de autenticación .

  • Tienes un depósito de Cloud Storage existente y permiso para escribir en él.

Para agregar este script a una VM, configúrelo para que funcione con una aplicación en su VM y agréguelo a los metadatos de la VM.

  1. Copie o descargue el script de apagado:

    • Copie el script de apagado anterior después de reemplazar lo siguiente:

      • PROGRAM_NAME es el nombre del proceso o programa que desea cerrar. Por ejemplo, apache2 o nginx .
      • LOCAL_USER es el nombre de usuario con el que inició sesión en la máquina virtual.
      • BUCKET_NAME es el nombre del depósito de Cloud Storage donde desea guardar el archivo de punto de control del programa. Tenga en cuenta que el nombre del depósito no comienza con gs:// en este caso.
    • Descargue el script de apagado en su estación de trabajo local y luego reemplace las siguientes variables en el archivo:

      • [PROGRAM_NAME] es el nombre del proceso o programa que desea cerrar. Por ejemplo, apache2 o nginx .
      • [LOCAL_USER] es el nombre de usuario con el que inició sesión en la máquina virtual.
      • [BUCKET_NAME] es el nombre del depósito de Cloud Storage donde deseas guardar el archivo de punto de control del programa. Tenga en cuenta que el nombre del depósito no comienza con gs:// en este caso.
  2. Agregue el script de apagado a una máquina virtual nueva o existente .

Detectar preferencia de máquinas virtuales puntuales

Determine si Compute Engine se adelantó a las VM puntuales mediante la consola de Google Cloud , la CLI de gcloud o la API de Compute Engine .

Consola

Puede verificar si una VM fue reemplazada revisando los registros de actividad del sistema.

  1. En la consola de Google Cloud, vaya a la página Registros .

    Ir a registros

  2. Seleccione su proyecto y haga clic en Continuar .

  3. Agregue compute.instances.preempted al filtro por etiqueta o campo de búsqueda de texto .

  4. Opcionalmente, también puede ingresar un nombre de VM si desea ver las operaciones de preferencia para una VM específica.

  5. Presione Intro para aplicar los filtros especificados. La consola de Google Cloud actualiza la lista de registros para mostrar solo las operaciones en las que se adelantó una VM.

  6. Seleccione una operación en la lista para ver detalles sobre la VM que fue reemplazada.

nube de gcloud

Usa el comando gcloud compute operations list con un parámetro de filtro para obtener una lista de eventos de preferencia en tu proyecto.

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

Opcionalmente, puede utilizar parámetros de filtro adicionales para ampliar el alcance de los resultados. Por ejemplo, para ver eventos de preferencia solo para instancias dentro de un grupo de instancias administrado, use el siguiente comando:

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

donde BASE_INSTANCE_NAME es el nombre base especificado como prefijo para los nombres de todas las VM en este grupo de instancias administrado.

El resultado es similar al siguiente:

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

Un tipo de operación de compute.instances.preempted indica que la instancia de VM fue reemplazada. Puedes usar el comando gcloud compute operations describe para obtener más información sobre una operación de preferencia específica.

gcloud compute operations describe SYSTEM_EVENT \
    --zone=ZONE

Reemplace lo siguiente:

  • SYSTEM_EVENT : el evento del sistema del resultado del comando gcloud compute operations list ; por ejemplo, systemevent-xxxxxxxx .
  • ZONE : la zona del evento del sistema; por ejemplo, us-central1-f .

El resultado es similar al siguiente:

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

DESCANSAR

Para obtener una lista de operaciones recientes del sistema para un proyecto y una zona específicos, utilice el método zoneOperations.get .

GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/operations

Reemplace lo siguiente:

Opcionalmente, para que la respuesta muestre solo operaciones de preferencia, puede agregar un filtro a su solicitud de API:

operationType="compute.instances.preempted"

Como alternativa, para ver las operaciones de preferencia para una máquina virtual específica, agregue un parámetro targetLink al filtro:

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

Reemplace lo siguiente: + PROJECT_ID : la identificación del proyecto . + ZONE : la zona . + VM_NAME : el nombre de una VM específica en esta zona y proyecto.

La respuesta contiene una lista de operaciones recientes. Por ejemplo, una preferencia es similar a la siguiente:

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

Alternativamente, puede determinar si una VM fue reemplazada desde dentro de la propia VM. Esto es útil si deseas manejar un apagado debido a una preferencia de Compute Engine de manera diferente a un apagado normal en un script de apagado . Para hacer esto, simplemente verifique en el servidor de metadatos el valor preempted en los metadatos predeterminados de su VM.

Por ejemplo, use curl desde su VM para obtener el valor de preempted :

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

Si este valor es TRUE , Compute Engine se adelantó a la VM; de lo contrario, es FALSE .

Si desea utilizar esto fuera de un script de apagado, puede agregar ?wait_for_change=true a la URL. Esto realiza una solicitud HTTP GET bloqueada que solo regresa cuando los metadatos han cambiado y la VM ha sido reemplazada.

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

Configuración de preferencia de prueba

Puede ejecutar eventos de mantenimiento simulados en sus máquinas virtuales para obligarlas a apropiarse. Utilice esta función para probar cómo sus aplicaciones manejan las máquinas virtuales puntuales. Lea Simular un evento de mantenimiento de host para aprender cómo probar eventos de mantenimiento en sus instancias.

También puede simular una preferencia de VM deteniendo la instancia de VM , lo que se puede utilizar en lugar de simular un evento de mantenimiento y evita los límites de cuota.

Mejores prácticas

A continuación se presentan algunas prácticas recomendadas que le ayudarán a aprovechar al máximo las máquinas virtuales Spot.

  • Utilice plantillas de instancias . En lugar de crear máquinas virtuales de spot una a la vez, puede usar plantillas de instancias para crear varias máquinas virtuales de spot con las mismas propiedades. Se requieren plantillas de instancia para usar MIG. Como alternativa, también puede crear varias máquinas virtuales de spot utilizando la API de instancia masiva .

  • Utilice MIG para distribuir regionalmente y recrear automáticamente máquinas virtuales puntuales . Utilice MIG para hacer que las cargas de trabajo en máquinas virtuales puntuales sean más flexibles y resistentes. Por ejemplo, utilice MIG regionales para distribuir máquinas virtuales en varias zonas, lo que ayuda a mitigar los errores de disponibilidad de recursos. Además, utilice la reparación automática para recrear automáticamente las máquinas virtuales puntuales después de que se aprueben.

  • Elija tipos de máquinas más pequeñas . Los recursos para máquinas virtuales puntuales provienen del exceso y del respaldo Google Cloud capacidad. La capacidad para máquinas virtuales puntuales suele ser más fácil de conseguir para tipos de máquinas más pequeñas , es decir, tipos de máquinas con menos recursos, como vCPU y memoria. Es posible que encuentre más capacidad para máquinas virtuales puntuales seleccionando un tipo de máquina personalizada más pequeña, pero la capacidad es aún mayor para tipos de máquinas predefinidas más pequeñas. Por ejemplo, en comparación con la capacidad para el tipo de máquina predefinido n2-standard-32 , la capacidad para el tipo de máquina personalizada n2-custom-24-96 es más probable, pero la capacidad para el tipo de máquina predefinido n2-standard-16 es aún más probable.

  • Ejecute grandes grupos de máquinas virtuales puntuales durante las horas de menor actividad . la carga en Google Cloud Los centros de datos varían según la ubicación y la hora del día, pero generalmente son más bajos durante las noches y los fines de semana. Como tal, las noches y los fines de semana son los mejores momentos para ejecutar grandes grupos de máquinas virtuales Spot.

  • Diseñe sus aplicaciones para que sean tolerantes a fallas y apropiaciones . Es importante estar preparado para el hecho de que hay cambios en los patrones de preferencia en diferentes momentos. Por ejemplo, si una zona sufre una interrupción parcial, se podría sustituir una gran cantidad de máquinas virtuales puntuales para dejar espacio a las máquinas virtuales estándar que deben trasladarse como parte de la recuperación. En ese pequeño lapso de tiempo, la tasa de preferencia sería muy diferente a la de cualquier otro día. Si su aplicación supone que las apropiaciones siempre se realizan en grupos pequeños, es posible que no esté preparado para tal evento.

  • Vuelva a intentar crear máquinas virtuales puntuales que hayan sido reemplazadas . Si sus máquinas virtuales Spot han sido reemplazadas, intente crear nuevas máquinas virtuales Spot una o dos veces antes de recurrir a las máquinas virtuales estándar. Dependiendo de sus requisitos, podría ser una buena idea combinar máquinas virtuales estándar y máquinas virtuales puntuales en sus clústeres para garantizar que el trabajo avance a un ritmo adecuado.

  • Utilice scripts de apagado . Administre los avisos de apagado y prevención con una secuencia de comandos de apagado que puede guardar el progreso de un trabajo para que pueda continuar donde lo dejó, en lugar de comenzar desde cero.

¿Qué sigue?