Crear y utilizar máquinas virtuales interrumpibles


Esta página explica cómo crear y utilizar una instancia de máquina virtual (VM) interrumpible. Las máquinas virtuales interrumpibles 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 detener (adelantarse) a estas máquinas virtuales si necesita recuperar esos recursos para otras tareas. Las máquinas virtuales interrumpibles siempre se detienen después de 24 horas. Las VM interrumpibles solo se recomiendan para aplicaciones tolerantes a fallas que puedan soportar la preferencia de VM. Asegúrese de que su aplicación pueda manejar apropiaciones antes de decidir crear una VM apropiable. Para comprender los riesgos y el valor de las VM interrumpibles, lea la documentación sobre instancias de VM interrumpibles .

Antes de comenzar

Crear una VM interrumpible

Cree una VM interrumpible mediante la CLI de gcloud o la API de Compute Engine. Para usar la consola de Google Cloud, cree una máquina virtual puntual .

nube de gcloud

Con gcloud compute , usa el mismo comando instances create que usarías para crear una VM normal, pero agrega la marca --preemptible .

gcloud compute instances create [VM_NAME] --preemptible

donde [VM_NAME] es el nombre de la VM.

Ir

import (
	"context"
	"fmt"
	"io"

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

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

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

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

	// List of public operating system (OS) images:
	// https://cloud.google.com/compute/docs/images/os-details.
	newestDebianReq := &computepb.GetFromFamilyImageRequest{
		Project: "debian-cloud",
		Family:  "debian-11",
	}
	newestDebian, err := imagesClient.GetFromFamily(ctx, newestDebianReq)
	if err != nil {
		return fmt.Errorf("unable to get image from family: %w", err)
	}

	inst := &computepb.Instance{
		Name: proto.String(instanceName),
		Disks: []*computepb.AttachedDisk{
			{
				InitializeParams: &computepb.AttachedDiskInitializeParams{
					DiskSizeGb:  proto.Int64(10),
					SourceImage: newestDebian.SelfLink,
					DiskType:    proto.String(fmt.Sprintf("zones/%s/diskTypes/pd-standard", zone)),
				},
				AutoDelete: proto.Bool(true),
				Boot:       proto.Bool(true),
			},
		},
		Scheduling: &computepb.Scheduling{
			// Set the preemptible setting
			Preemptible: proto.Bool(true),
		},
		MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/n1-standard-1", zone)),
		NetworkInterfaces: []*computepb.NetworkInterface{
			{
				Name: proto.String("global/networks/default"),
			},
		},
	}

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

public class CreatePreemptibleInstance {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // projectId: 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”
    // instanceName: name of the new virtual machine.
    String projectId = "your-project-id-or-number";
    String zone = "zone-name";
    String instanceName = "instance-name";

    createPremptibleInstance(projectId, zone, instanceName);
  }

  // Send an instance creation request with preemptible settings to the Compute Engine API
  // and wait for it to complete.
  public static void createPremptibleInstance(String projectId, String zone, String instanceName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    String machineType = String.format("zones/%s/machineTypes/e2-small", zone);
    String sourceImage = "projects/debian-cloud/global/images/family/debian-11";
    long diskSizeGb = 10L;
    String networkName = "default";

    try (InstancesClient instancesClient = InstancesClient.create()) {

      AttachedDisk disk =
          AttachedDisk.newBuilder()
              .setBoot(true)
              .setAutoDelete(true)
              .setType(AttachedDisk.Type.PERSISTENT.toString())
              .setInitializeParams(
                  // Describe the size and source image of the boot disk to attach to the instance.
                  AttachedDiskInitializeParams.newBuilder()
                      .setSourceImage(sourceImage)
                      .setDiskSizeGb(diskSizeGb)
                      .build())
              .build();

      // Use the default VPC network.
      NetworkInterface networkInterface = NetworkInterface.newBuilder()
          .setName(networkName)
          .build();

      // Collect information into the Instance object.
      Instance instanceResource =
          Instance.newBuilder()
              .setName(instanceName)
              .setMachineType(machineType)
              .addDisks(disk)
              .addNetworkInterfaces(networkInterface)
              // Set the preemptible setting.
              .setScheduling(Scheduling.newBuilder()
                  .setPreemptible(true)
                  .build())
              .build();

      System.out.printf("Creating instance: %s at %s %n", instanceName, zone);

      // Prepare the request to insert an instance.
      InsertInstanceRequest insertInstanceRequest = InsertInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstanceResource(instanceResource)
          .build();

      // Wait for the create operation to complete.
      Operation response = instancesClient.insertAsync(insertInstanceRequest)
          .get(3, TimeUnit.MINUTES);
      ;

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

      System.out.printf("Instance created : %s\n", instanceName);
      System.out.println("Operation Status: " + response.getStatus());
    }
  }
}

Nodo.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 compute = require('@google-cloud/compute');

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

  const [response] = await instancesClient.insert({
    instanceResource: {
      name: instanceName,
      disks: [
        {
          initializeParams: {
            diskSizeGb: '64',
            sourceImage:
              'projects/debian-cloud/global/images/family/debian-11/',
          },
          autoDelete: true,
          boot: true,
        },
      ],
      scheduling: {
        // Set the preemptible setting
        preemptible: true,
      },
      machineType: `zones/${zone}/machineTypes/e2-small`,
      networkInterfaces: [
        {
          name: 'global/networks/default',
        },
      ],
    },
    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.');
}

createPreemptible();

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_preemptible_instance(
    project_id: str, zone: str, instance_name: str
) -> compute_v1.Instance:
    """
    Create a new preemptible 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, preemptible=True)
    return instance

DESCANSAR

En la API, cree una solicitud normal para crear una VM , pero incluya la propiedad preemptible en scheduling y configúrela en true . Por ejemplo:

POST https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/instances

{
  'machineType': 'zones/[ZONE]/machineTypes/[MACHINE_TYPE]',
  'name': '[INSTANCE_NAME]',
  'scheduling':
  {
    'preemptible': true
  },
  ...
}

Cuotas de CPU preferibles

Las máquinas virtuales interrumpibles requieren cuotas de CPU disponibles, como las máquinas virtuales estándar. Para evitar que las máquinas virtuales interrumpibles consuman las cuotas de CPU de sus máquinas virtuales estándar, puede solicitar una cuota especial de "CPU interrumpible". Después de que Compute Engine te otorga una cuota de CPU interrumpible en esa región, todas las VM interrumpibles cuentan para esa cuota y todas las VM estándar continúan contando para la cuota de CPU estándar.

En regiones donde no tiene una cuota de CPU interrumpible, puede usar una cuota de CPU estándar para iniciar máquinas virtuales interrumpibles. También necesita suficiente cuota de disco e IP, como de costumbre. La cuota de CPU preferente no es visible en la CLI de gcloud o en las páginas de cuotas de la consola de Google Cloud a menos que Compute Engine haya otorgado la cuota.

Para obtener más información sobre las cuotas, visite la página Cuotas de recursos .

Iniciar una VM con preferencia

Como cualquier otra máquina virtual, si una máquina virtual interrumpible se detiene o se interrumpe, puede iniciarla nuevamente y devolverla al estado RUNNING . Al iniciar una VM interrumpible se restablece el contador de 24 horas, pero como sigue siendo una VM interrumpible, Compute Engine puede hacerlo antes de las 24 horas. No es posible convertir una VM interrumpible en una VM estándar mientras se está ejecutando.

Si Compute Engine detiene una VM interrumpible en un grupo de instancias administradas (MIG) de escalamiento automático o en un clúster de Google Kubernetes Engine (GKE), el grupo reinicia la VM cuando los recursos vuelven a estar disponibles.

Manejar la preferencia con un script de apagado

Cuando Compute Engine se apropia de una VM, 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 cierre de un aviso de preferencia, consulte Proceso de preferencia en la documentación conceptual.

El siguiente es un script de apagado que puede agregar a una VM interrumpible en ejecución o agregar a una nueva VM interrumpible cuando la crea. 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_USERNAME]"
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."

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 en su estación de trabajo local.
  2. Abra el archivo para editarlo y cambiar las siguientes variables:
    • [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.
  3. Guarde sus cambios.
  4. Agregue el script de apagado a una máquina virtual nueva o existente .

Este script asume lo siguiente:

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

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

Identificar máquinas virtuales interrumpibles

Para verificar si una VM es una VM interrumpible, siga los pasos para Identificar el modelo de aprovisionamiento y la acción de terminación de una VM .

Determinar si una VM fue reemplazada

Determina si una VM fue reemplazada con la consola de Google Cloud , la CLI de gcloud o la API .

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"

Puede utilizar el parámetro de filtro para ampliar el alcance de los resultados. Por ejemplo, para ver eventos de preferencia solo para VM dentro de un grupo de instancias administrado:

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

gcloud devuelve una respuesta similar a:

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

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

gcloud compute operations describe \
    systemevent-xxxxxxxx

gcloud devuelve una respuesta similar a:

...
operationType: compute.instances.preempted
progress: 100
selfLink: https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/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, envíe una solicitud GET al URI de operaciones de zona.

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

La respuesta contiene una lista de operaciones recientes.

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

Para que la respuesta muestre solo operaciones de preferencia, puede agregar un filtro a su solicitud de API: operationType="compute.instances.preempted" . Para ver las operaciones de preferencia para una VM 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]" .

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 de instancia 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 característica para probar cómo sus aplicaciones manejan las máquinas virtuales interrumpibles. Lea cómo probar sus políticas de disponibilidad para aprender cómo probar eventos de mantenimiento en sus máquinas virtuales.

También puede simular la preferencia de una máquina virtual deteniéndola , lo que se puede usar 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 instancias de VM interrumpibles.

Usando la API de instancia masiva

En lugar de crear máquinas virtuales únicas, puede utilizar la API de instancia masiva .

Elija formas de máquinas más pequeñas

Los recursos para máquinas virtuales interrumpibles provienen del exceso y de la copia de seguridad Google Cloudcapacidad. La capacidad 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 interrumpibles seleccionando un tipo de máquina personalizada más pequeña, pero la capacidad es aún más probable 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 clústeres de VM interrumpibles 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 clústeres de VM interrumpibles.

Diseñe sus aplicaciones para que sean tolerantes a fallos y a la preferencia

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 interrumpibles 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. Puede probar el comportamiento de su aplicación en un evento de preferencia deteniendo la instancia de VM.

Reintentar la creación de máquinas virtuales que han sido reemplazadas

Si su instancia de VM ha sido reemplazada, intente crear nuevas VM interrumpibles una o dos veces antes de recurrir a las VM estándar. Dependiendo de sus requisitos, podría ser una buena idea combinar máquinas virtuales estándar e interrumpibles en sus clústeres para garantizar que el trabajo avance a un ritmo adecuado.

Usar 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?