Adicione um SSD local à VM


Os SSDs locais foram projetados para casos de uso de armazenamento temporário como caches ou espaço de processamento de trabalho. Como os SSDs locais estão localizados na máquina física em que a VM está sendo executada, só é possível criá-los durante o processo de criação da VM. Não é possível usar os SSDs locais como dispositivos de inicialização.

Para a série de máquinas de terceira geração, uma quantidade definida de discos SSD locais é adicionada à VM quando você a cria. A única maneira de adicionar armazenamento SSD local a essas VMs é:

  • Para C3 e C3D, o armazenamento SSD local está disponível apenas com determinados tipos de máquina, como c3-standard-88-lssd.
  • Para as séries de máquinas ultra Z3, A3 e A2, cada tipo de máquina vem com armazenamento SSD local.

Para os tipos de máquina M3 e de primeira e segunda geração, especifique discos SSD locais ao criar a VM.

Depois de criar um SSD local, formate e ative o dispositivo antes de usá-lo.

Para informações sobre a quantidade de armazenamento SSD local disponível com vários tipos de máquina e o número de discos SSD locais que você pode anexar a uma VM, consulteComo escolher um número válido de SSDs locais.

Antes de começar

  • Confira as limitações do SSD local antes de usá-lo.
  • Analise os cenários de persistência de dados dos discos SSD locais.
  • Se você estiver adicionando SSDs locais a instâncias de máquinas virtuais (VM) com GPUs anexadas, consulte Disponibilidade de SSDs locais por regiões e zonas de GPU.
  • Configure a autenticação, caso ainda não tenha feito isso. A autenticação é o processo de verificação da sua identidade para acesso a serviços e APIs do Google Cloud. Para executar códigos ou amostras de um ambiente de desenvolvimento local, autentique-se no Compute Engine da seguinte maneira.

    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. Install the Google Cloud CLI, then initialize it by running the following command:

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

      Para usar os exemplos do Terraform nesta página em um ambiente de desenvolvimento local, instale e inicialize a gcloud CLI e, em seguida, configure o Application Default Credentials com suas credenciais de usuário.

      1. Install the Google Cloud CLI.
      2. To initialize the gcloud CLI, run the following command:

        gcloud init
      3. 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.

      Confira mais informações em Set up authentication for a local development environment.

      Go

      Para usar os exemplos Go desta página em um ambiente de desenvolvimento local, instale e inicialize o gcloud CLI e e configure o Application Default Credentials com suas credenciais de usuário.

      1. Install the Google Cloud CLI.
      2. To initialize the gcloud CLI, run the following command:

        gcloud init
      3. 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.

      Confira mais informações em Set up authentication for a local development environment.

      Java

      Para usar os exemplos Java desta página em um ambiente de desenvolvimento local, instale e inicialize o gcloud CLI e e configure o Application Default Credentials com suas credenciais de usuário.

      1. Install the Google Cloud CLI.
      2. To initialize the gcloud CLI, run the following command:

        gcloud init
      3. 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.

      Confira mais informações em Set up authentication for a local development environment.

      Python

      Para usar os exemplos Python desta página em um ambiente de desenvolvimento local, instale e inicialize o gcloud CLI e e configure o Application Default Credentials com suas credenciais de usuário.

      1. Install the Google Cloud CLI.
      2. To initialize the gcloud CLI, run the following command:

        gcloud init
      3. 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.

      Confira mais informações em Set up authentication for a local development environment.

      REST

      Para usar as amostras da API REST nesta página em um ambiente de desenvolvimento local, use as credenciais fornecidas para gcloud CLI.

        Install the Google Cloud CLI, then initialize it by running the following command:

        gcloud init

      Para mais informações, consulte Autenticar para usar REST na documentação de autenticação do Google Cloud.

Criar uma VM com um SSD local

É possível criar uma VM com armazenamento em disco SSD local usando o console do Google Cloud, a CLI gcloud ou a API Compute Engine.

Console

  1. Acesse a página Criar uma instância.

    Acesse "Criar uma instância"

  2. Especifique o Nome, a Região e a Zona da VM. Opcionalmente, adicione tags ou rótulos.

  3. Na seção Configuração da máquina, escolha a família de máquinas que contém o tipo de máquina de destino.

  4. Selecione uma série na lista Série e escolha o tipo de máquina.

    • Para a série de máquinas de terceira geração C3 e C3D, escolha um tipo de máquina que termine em -lssd.
    • Para o Z3, A3 e A2 ultra, cada tipo de máquina vem com armazenamento SSD local.
    • No caso do M3 ou de séries de máquinas de primeira e segunda geração, depois de selecionar o tipo de máquina, faça o seguinte:
      1. Expanda a seção Opções avançadas.
      2. Expanda Discos, clique em Adicionar SSD local e faça o seguinte:
        1. Na página Configurar SSD local, escolha o tipo de interface do disco.
        2. Selecione o número de discos que você quer na lista Capacidade de disco.
        3. Clique em Save.
  5. Continue com o processo de criação da VM.

  6. Depois de criar a VM com discos SSD locais, formate e ative cada dispositivo antes de usar os discos.

gcloud

  • Para as séries de máquinas ultra Z3, A3 e A2, para criar uma VM com discos SSD locais anexados, crie uma VM que use qualquer um dos tipos de máquina disponíveis para essa série, seguindo as instruções para Crie uma instância.

  • Para a série de máquinas C3 ou C3D, para criar uma VM com discos SSD locais anexados, siga as instruções para criar uma instância, mas especifique um tipo de instância que inclua discos SSD locais. Discos SSD (-lssd).

    Por exemplo, é possível criar uma VM C3 com duas partições SSD locais que usam a interface do disco NVMe da seguinte maneira:

    gcloud compute instances create example-c3-instance \
       --zone ZONE \
       --machine-type c3-standard-8-lssd \
       --image-project IMAGE_PROJECT \
       --image-family IMAGE_FAMILY
    
  • Para as séries de máquinas M3 e de primeira e segunda geração, para criar uma VM com discos SSD locais anexados, siga as instruções para criar uma instância, mas use o --local-ssd para criar e anexar um disco SSD local. Para criar várias partições de SSD local, adicione mais sinalizações --local-ssd. Se quiser, também é possível definir valores da interface e o nome do dispositivo de cada sinalização --local-ssd.

    Por exemplo, é possível criar uma VM do M3 com quatro discos SSD locais e especificar o tipo de interface do disco da seguinte maneira:

    gcloud compute instances VM_NAME \
       --machine-type m3-ultramem-64 \
       --zone ZONE \
       --local-ssd interface=INTERFACE_TYPE device-name=DEVICE-NAME \
       --local-ssd interface=INTERFACE_TYPE device-name=DEVICE-NAME \
       --local-ssd interface=INTERFACE_TYPE device-name=DEVICE-NAME \
       --local-ssd interface=INTERFACE_TYPE \
       --image-project IMAGE_PROJECT \
       --image-family IMAGE_FAMILY
    

Substitua:

  • VM_NAME: o nome da nova VM;
  • ZONE: zona em que a VM será criada. Essa sinalização é opcional se você tiver configurado a propriedade compute/zone da CLI gcloud ou a variável de ambiente CLOUDSDK_COMPUTE_ZONE.
  • INTERFACE_TYPE: é o tipo de interface do disco que você quer usar para o dispositivo SSD local. Especifique nvme se estiver criando uma VM M3 ou se a imagem do disco de inicialização tiver drivers NVMe otimizados. Especifique scsi para outras imagens.
  • DEVICE-NAME (opcional): um nome que indica o nome do disco a ser usado no link simbólico (link simbólico) do sistema operacional convidado.
  • IMAGE_FAMILY: é uma das famílias de imagens disponíveis que você quer instalar no disco de inicialização
  • IMAGE_PROJECT: o projeto de imagem ao qual a família de imagens pertence.

Se necessário, anexe SSDs locais a uma VM de primeira ou segunda geração usando uma combinação de nvme e scsi para diferentes partições. O desempenho do dispositivo nvme depende da imagem de disco de inicialização da instância. As VMs de terceira geração oferecem suporte apenas à interface de disco NVMe.

Depois de criar uma VM com o SSD local, formate e ative cada dispositivo antes de usá-lo.

Terraform

Para criar uma VM com discos SSD locais anexados, use o recurso google_compute_instance.


# Create a VM with a local SSD for temporary storage use cases

resource "google_compute_instance" "default" {
  name         = "my-vm-instance-with-scratch"
  machine_type = "n2-standard-8"
  zone         = "us-central1-a"

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

  # Local SSD interface type; NVME for image with optimized NVMe drivers or SCSI
  # Local SSD are 375 GiB in size
  scratch_disk {
    interface = "SCSI"
  }

  network_interface {
    network = "default"
    access_config {}
  }
}

Para saber como aplicar ou remover uma configuração do Terraform, consulte Comandos básicos do Terraform.

Para gerar o código do Terraform, use o componente Código equivalente no Console do Google Cloud.
  1. No console do Google Cloud, acesse a página Instâncias de VMs.

    Acessar instâncias de VM

  2. Clique em Criar instância.
  3. Especifique os parâmetros desejados.
  4. Na parte superior ou inferior da página, clique em Código equivalente e, em seguida, clique na guia Terraform para ver o código do Terraform.

Go

Go

Antes de testar esta amostra, siga as instruções de configuração do Go no Guia de início rápido do Compute Engine: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Go do Compute Engine.

Para autenticar-se no Compute Engine, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

import (
	"context"
	"fmt"
	"io"

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

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

	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-10",
	}
	newestDebian, err := imagesClient.GetFromFamily(ctx, newestDebianReq)
	if err != nil {
		return fmt.Errorf("unable to get image from family: %w", err)
	}

	req := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &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),
					Type:       proto.String(computepb.AttachedDisk_PERSISTENT.String()),
				},
				{
					InitializeParams: &computepb.AttachedDiskInitializeParams{
						DiskType: proto.String(fmt.Sprintf("zones/%s/diskTypes/local-ssd", zone)),
					},
					AutoDelete: proto.Bool(true),
					Type:       proto.String(computepb.AttachedDisk_SCRATCH.String()),
				},
			},
			MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/n1-standard-1", zone)),
			NetworkInterfaces: []*computepb.NetworkInterface{
				{
					Name: proto.String("global/networks/default"),
				},
			},
		},
	}

	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

Java

Antes de testar esta amostra, siga as instruções de configuração do Java no Guia de início rápido do Compute Engine: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Java do Compute Engine.

Para autenticar-se no Compute Engine, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.


import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.Image;
import com.google.cloud.compute.v1.ImagesClient;
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.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateWithLocalSsd {

  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.
    String projectId = "your-project-id";
    // zone: name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "zone-name";
    // instanceName: name of the new virtual machine (VM) instance.
    String instanceName = "instance-name";

    createWithLocalSsd(projectId, zone, instanceName);
  }

  // Create a new VM instance with Debian 10 operating system and SSD local disk.
  public static void createWithLocalSsd(String projectId, String zone, String instanceName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    int diskSizeGb = 10;
    boolean boot = true;
    boolean autoDelete = true;
    String diskType = String.format("zones/%s/diskTypes/pd-standard", zone);
    // Get the latest debian image.
    Image newestDebian = getImageFromFamily("debian-cloud", "debian-10");
    List<AttachedDisk> disks = new ArrayList<>();

    // Create the disks to be included in the instance.
    disks.add(
        createDiskFromImage(diskType, diskSizeGb, boot, newestDebian.getSelfLink(), autoDelete));
    disks.add(createLocalSsdDisk(zone));

    // Create the instance.
    Instance instance = createInstance(projectId, zone, instanceName, disks);

    if (instance != null) {
      System.out.printf("Instance created with local SSD: %s", instance.getName());
    }

  }

  // Retrieve the newest image that is part of a given family in a project.
  // Args:
  //    projectId: 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.
  private static Image getImageFromFamily(String projectId, String family) 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. After completing all of your requests, call
    // the `imagesClient.close()` method on the client to safely
    // clean up any remaining background resources.
    try (ImagesClient imagesClient = ImagesClient.create()) {
      // List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details
      return imagesClient.getFromFamily(projectId, family);
    }
  }

  // Create an AttachedDisk object to be used in VM instance creation. Uses an image as the
  // source for the new disk.
  //
  // Args:
  //    diskType: 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"
  //
  //    diskSizeGb: size of the new disk in gigabytes.
  //
  //    boot: boolean flag indicating whether this disk should be used as a
  //    boot disk of an instance.
  //
  //    sourceImage: 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}"
  //
  //    autoDelete: boolean flag indicating whether this disk should be deleted
  //    with the VM that uses it.
  private static AttachedDisk createDiskFromImage(String diskType, int diskSizeGb, boolean boot,
      String sourceImage, boolean autoDelete) {

    AttachedDiskInitializeParams attachedDiskInitializeParams =
        AttachedDiskInitializeParams.newBuilder()
            .setSourceImage(sourceImage)
            .setDiskSizeGb(diskSizeGb)
            .setDiskType(diskType)
            .build();

    AttachedDisk bootDisk = AttachedDisk.newBuilder()
        .setInitializeParams(attachedDiskInitializeParams)
        // Remember to set auto_delete to True if you want the disk to be deleted when you delete
        // your VM instance.
        .setAutoDelete(autoDelete)
        .setBoot(boot)
        .build();

    return bootDisk;
  }

  // Create an AttachedDisk object to be used in VM instance creation. The created disk contains
  // no data and requires formatting before it can be used.
  // Args:
  //    zone: The zone in which the local SSD drive will be attached.
  private static AttachedDisk createLocalSsdDisk(String zone) {

    AttachedDiskInitializeParams attachedDiskInitializeParams =
        AttachedDiskInitializeParams.newBuilder()
            .setDiskType(String.format("zones/%s/diskTypes/local-ssd", zone))
            .build();

    AttachedDisk disk = AttachedDisk.newBuilder()
        .setType(AttachedDisk.Type.SCRATCH.name())
        .setInitializeParams(attachedDiskInitializeParams)
        .setAutoDelete(true)
        .build();

    return disk;
  }

  // Send an instance creation request to the Compute Engine API and wait for it to complete.
  // Args:
  //    projectId: 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"
  //    instanceName: 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.
  private static Instance createInstance(String projectId, String zone, String instanceName,
      List<AttachedDisk> disks)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the `instancesClient.close()` method on the client to safely
    // clean up any remaining background resources.
    try (InstancesClient instancesClient = InstancesClient.create()) {

      // machineType: 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"
      String typeName = "n1-standard-1";
      String machineType = String.format("zones/%s/machineTypes/%s", zone, typeName);

      // 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";

      // Collect information into the Instance object.
      Instance instance = Instance.newBuilder()
          .setName(instanceName)
          .setMachineType(machineType)
          .addNetworkInterfaces(NetworkInterface.newBuilder().setName(networkLink).build())
          .addAllDisks(disks)
          .build();

      Operation response = instancesClient.insertAsync(projectId, zone, instance)
          .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        throw new Error("Instance creation failed ! ! " + response);
      }
      System.out.println("Operation Status: " + response.getStatus());
      return instancesClient.get(projectId, zone, instanceName);
    }

  }

}

Python

Python

Antes de testar esta amostra, siga as instruções de configuração do Python no Guia de início rápido do Compute Engine: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Python do Compute Engine.

Para autenticar-se no Compute Engine, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

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 local_ssd_disk(zone: str) -> compute_v1.AttachedDisk():
    """
    Create an AttachedDisk object to be used in VM instance creation. The created disk contains
    no data and requires formatting before it can be used.

    Args:
        zone: The zone in which the local SSD drive will be attached.

    Returns:
        AttachedDisk object configured as a local SSD disk.
    """
    disk = compute_v1.AttachedDisk()
    disk.type_ = compute_v1.AttachedDisk.Type.SCRATCH.name
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.disk_type = f"zones/{zone}/diskTypes/local-ssd"
    disk.initialize_params = initialize_params
    disk.auto_delete = True
    return 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_with_ssd(
    project_id: str, zone: str, instance_name: str
) -> compute_v1.Instance:
    """
    Create a new VM instance with Debian 10 operating system and SSD local disk.

    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-10")
    disk_type = f"zones/{zone}/diskTypes/pd-standard"
    disks = [
        disk_from_image(disk_type, 10, True, newest_debian.self_link, True),
        local_ssd_disk(zone),
    ]
    instance = create_instance(project_id, zone, instance_name, disks)
    return instance

REST

Use o instances.insert method para criar uma VM a partir de uma família de imagens ou de uma versão específica de uma imagem do sistema operacional.

  • Para as séries de máquinas ultra Z3, A3 e A2, para criar uma VM com discos SSD locais anexados, crie uma VM que use qualquer um dos tipos de máquina disponíveis para essa série,
  • Para a série de máquinas C3 ou C3D, para criar uma VM com discos SSD locais anexados, especifique um tipo de instância que inclua discos SSD locais (-lssd).

    Veja um exemplo de payload de solicitação que cria uma VM C3 com um disco de inicialização do Ubuntu e dois discos SSD locais:

    {
     "machineType":"zones/us-central1-c/machineTypes/c3-standard-8-lssd",
     "name":"c3-with-local-ssd",
     "disks":[
        {
           "type":"PERSISTENT",
           "initializeParams":{
              "sourceImage":"projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts"
           },
           "boot":true
        }
     ],
     "networkInterfaces":[
        {
           "network":"global/networks/default"
    }
     ]
    }
    
  • Para as séries de máquinas M3 e de primeira e segunda geração, para criar uma VM com discos SSD locais anexados, é possível adicionar dispositivos SSD locais durante a criação da VM usando a propriedade initializeParams. Forneça também as propriedades a seguir:

    • diskType: definido como o SSD local
    • autoDelete: definido como verdadeiro
    • type: definido como SCRATCH

    Não é possível usar as propriedades a seguir com dispositivos SSD locais:

    • diskName
    • Propriedade sourceImage
    • diskSizeGb

    Veja um exemplo de payload de solicitação que cria uma VM M3 com um disco de inicialização e quatro discos SSD locais:

    {
     "machineType":"zones/us-central1-f/machineTypes/m3-ultramem-64",
     "name":"local-ssd-instance",
     "disks":[
        {
         "type":"PERSISTENT",
         "initializeParams":{
            "sourceImage":"projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts"
         },
         "boot":true
        },
        {
           "type":"SCRATCH",
           "initializeParams":{
              "diskType":"zones/us-central1-f/diskTypes/local-ssd"
           },
           "autoDelete":true,
           "interface": "NVME"
        },
        {
           "type":"SCRATCH",
           "initializeParams":{
              "diskType":"zones/us-central1-f/diskTypes/local-ssd"
           },
           "autoDelete":true,
           "interface": "NVME"
        },
        {
           "type":"SCRATCH",
           "initializeParams":{
              "diskType":"zones/us-central1-f/diskTypes/local-ssd"
           },
           "autoDelete":true,
           "interface": "NVME"
        },
        {
           "type":"SCRATCH",
           "initializeParams":{
              "diskType":"zones/us-central1-f/diskTypes/local-ssd"
           },
           "autoDelete":true,
           "interface": "NVME"
        },
     ],
     "networkInterfaces":[
        {
           "network":"global/networks/default"
        }
     ]
    }
    

Depois de criar um SSD local, formate e ative cada dispositivo antes de usá-lo.

Para mais informações sobre como criar uma instância usando REST, consulte a API Compute Engine.

Formatar e ativar um dispositivo SSD local

É possível formatar e ativar cada disco SSD local individualmente ou combinar vários discos SSD locais em um único volume lógico.

Formatar e ativar partições SSD locais individuais

O jeito mais fácil de conectar SSDs locais à instância é formatar e ativar cada dispositivo com uma partição simples. Como alternativa, combine várias partições em um único volume lógico.

Instâncias do Linux

Formate e ative o novo SSD local na instância do Linux. Use qualquer formato de partição e configuração que precisar. Neste exemplo, crie uma única partição ext4.

  1. Acesse a página "Instâncias de VM".

    Acessar instâncias de VM

  2. Clique no botão SSH ao lado da instância que tem o novo SSD local anexado. O navegador abrirá uma conexão de terminal com a instância.

  3. No terminal, use o comando find para identificar o SSD local que você quer ativar.

    $ find /dev/ | grep google-local-nvme-ssd
    

    Os SSDs locais no modo SCSI têm nomes padrão como google-local-ssd-0. Os SSDs locais no modo NVMe têm nomes como google-local-nvme-ssd-0, conforme mostrado na saída a seguir:

     $ find /dev/ | grep google-local-nvme-ssd
    
     /dev/disk/by-id/google-local-nvme-ssd-0
    
  4. Formate o SSD local com um sistema de arquivos ext4. Esse comando exclui todos os dados atuais do SSD local.

    $ sudo mkfs.ext4 -F /dev/disk/by-id/[SSD_NAME]
    

    Substitua [SSD_NAME] pelo ID do SSD local que você quer formatar. Por exemplo, especifique google-local-nvme-ssd-0 para formatar o primeiro SSD local NVMe na instância.

  5. Use o comando mkdir para criar um diretório em que seja possível ativar o dispositivo.

    $ sudo mkdir -p /mnt/disks/[MNT_DIR]
    

    Substitua [MNT_DIR] pelo caminho do diretório em que você quer ativar o disco SSD local.

  6. Ative o SSD local na VM.

    $ sudo mount /dev/[SSD_NAME] /mnt/disks/[MNT_DIR]
    

    Substitua:

    • [SSD_NAME]: o ID do SSD local que você quer ativar.
    • [MNT_DIR]: o diretório em que você quer ativar o SSD local.
  7. Configure o acesso de leitura e gravação no dispositivo. Neste exemplo, conceda acesso de gravação no dispositivo a todos os usuários.

    $ sudo chmod a+w /mnt/disks/[MNT_DIR]
    

    Substitua [MNT_DIR] pelo diretório em que você ativou o SSD local.

Se quiser, adicione o SSD local ao arquivo /etc/fstab para que o dispositivo seja reativado automaticamente quando a instância for reiniciada. Essa entrada não preserva dados no SSD local se a instância for interrompida. Consulte Persistência de dados do SSD local para ver todos os detalhes.

Ao especificar o arquivo /etc/fstab de entrada, inclua a opção nofail para que a instância possa continuar a inicialização mesmo que o SSD local não esteja presente. Por exemplo, se você tirar um snapshot do disco de inicialização e criar uma nova instância sem nenhum disco permanente vinculado, a instância poderá continuar o processo de inicialização sem pausar indefinidamente.

  1. Crie a entrada /etc/fstab. Use o comando blkid para localizar o UUID do sistema de arquivos no dispositivo e edite o arquivo /etc/fstab para incluir esse UUID com as opções de ativação. É possível concluir esta etapa com um único comando.

    Por exemplo, para um SSD local no modo NVMe, use o seguinte comando:

    $ echo UUID=`sudo blkid -s UUID -o value /dev/disk/by-id/google-local-nvme-ssd-0` /mnt/disks/[MNT_DIR] ext4 discard,defaults,nofail 0 2 | sudo tee -a /etc/fstab
    

    Para um SSD local em um modo não NVMe, como SCSI, use o seguinte comando:

    $ echo UUID=`sudo blkid -s UUID -o value /dev/disk/by-id/google-local-ssd-0` /mnt/disks/[MNT_DIR] ext4 discard,defaults,nofail 0 2 | sudo tee -a /etc/fstab
    

    Substitua [MNT_DIR] pelo diretório em que você ativou o SSD local.

  2. Use o comando cat para verificar se as entradas /etc/fstab estão corretas:

    $ cat /etc/fstab
    

Se você criar um snapshot a partir do disco de inicialização dessa instância e usá-lo para gerar uma instância separada que não tenha SSDs locais, edite o arquivo /etc/fstab e remova a entrada desse SSD local. Mesmo com a opção nofail, mantenha o arquivo /etc/fstab sincronizado com as partições anexadas à instância e remova essas entradas antes de criar o snapshot do disco de inicialização.

Instâncias do Windows

Use a ferramenta de gerenciamento de disco do Windows para formatar e ativar um SSD local em uma instância do Windows.

  1. Conecte-se à instância por meio do RDP. Neste exemplo, acesse a página "Instâncias de VM" e clique no botão RDP ao lado da instância que tem os SSDs locais anexados. Depois de inserir o nome de usuário e a senha, uma janela é aberta com a interface da área de trabalho do servidor.

  2. Clique com o botão direito do mouse no botão "Iniciar" do Windows e selecione Gerenciamento de Disco.

    Como selecionar a ferramenta "Gerenciamento de Disco" clicando com o botão direito do mouse no botão "Iniciar" do Windows.

  3. Se você não inicializou o SSD locais antes, a ferramenta solicitará que você selecione um esquema de particionamento para as novas partições. Selecione GPT e clique em OK.

    Selecione um esquema de partição na janela de inicialização do disco.

  4. Após a inicialização do SSD local, clique com o botão direito do mouse no espaço em disco não alocado e selecione Novo Volume Simples.

    Crie um novo volume simples no disco anexado.

  5. Siga as instruções no Assistente para Novas Partições Simples para configurar o novo volume. É possível usar qualquer formato de partição que preferir, mas, neste exemplo, selecione NTFS. Além disso, marque Executar uma formatação rápida para acelerar esse processo.

    Como selecionar o tipo de formato da partição no "Assistente para Novas Partições Simples".

  6. Após a conclusão do assistente e da formatação do volume, verifique se o novo SSD local tem o status Healthy.

    Visualize a lista de discos reconhecidos pelo Windows e verifique se o SSD local tem status "Íntegro".

Pronto. Agora é possível gravar arquivos no SSD local.

Formatar e ativar várias partições de SSD local em um único volume lógico

Ao contrário dos SSDs permanentes, os SSDs locais têm uma capacidade fixa de 375 GB para cada dispositivo anexado à instância. Se quiser combinar várias partições de SSDs locais em um único volume lógico, defina o gerenciamento de volume em todas essas partições.

Instâncias do Linux

Use mdadm para criar uma matriz RAID 0. Neste exemplo, a matriz é formatada com um único sistema de arquivos ext4, mas é possível aplicar qualquer sistema de arquivos que quiser.

  1. Acesse a página "Instâncias de VM".

    Acessar instâncias de VM

  2. Clique no botão SSH ao lado da instância que tem o novo SSD local anexado. O navegador abrirá uma conexão de terminal com a instância.

  3. No terminal, instale a ferramenta mdadm. O processo de instalação de mdadm inclui um prompt do usuário que interrompe os scripts. Por isso, execute esse processo manualmente.

    Debian e Ubuntu:

    $ sudo apt update && sudo apt install mdadm --no-install-recommends
    

    CentOS e RHEL:

    $ sudo yum install mdadm -y
    

    SLES e openSUSE:

    $ sudo zypper install -y mdadm
    

  4. Use o comando find para identificar todos os SSDs locais que você quer ativar:

    Neste exemplo, a instância tem oito partições de SSDs locais no modo NVMe:

    $  find /dev/ | grep google-local-nvme-ssd
    
     /dev/disk/by-id/google-local-nvme-ssd-7
     /dev/disk/by-id/google-local-nvme-ssd-6
     /dev/disk/by-id/google-local-nvme-ssd-5
     /dev/disk/by-id/google-local-nvme-ssd-4
     /dev/disk/by-id/google-local-nvme-ssd-3
     /dev/disk/by-id/google-local-nvme-ssd-2
     /dev/disk/by-id/google-local-nvme-ssd-1
     /dev/disk/by-id/google-local-nvme-ssd-0
    

    find não garante uma ordem. Não tem problema se os dispositivos estiverem listados em uma ordem diferente, desde que o número de linhas de saída corresponda ao número esperado de partições SSD. Os SSDs locais no modo SCSI têm nomes padrão como google-local-ssd. Os SSDs locais no modo NVMe têm nomes como google-local-nvme-ssd.

  5. Use mdadm para combinar vários dispositivos de SSD local em uma única matriz chamada /dev/md0. Neste exemplo, são combinados oito dispositivos de SSD local no modo NVMe. Para dispositivos de SSD local no modo SCSI, especifique os nomes que você conseguiu a partir do comando find:

    $ sudo mdadm --create /dev/md0 --level=0 --raid-devices=8 \
     /dev/disk/by-id/google-local-nvme-ssd-0 \
     /dev/disk/by-id/google-local-nvme-ssd-1 \
     /dev/disk/by-id/google-local-nvme-ssd-2 \
     /dev/disk/by-id/google-local-nvme-ssd-3 \
     /dev/disk/by-id/google-local-nvme-ssd-4 \
     /dev/disk/by-id/google-local-nvme-ssd-5 \
     /dev/disk/by-id/google-local-nvme-ssd-6 \
     /dev/disk/by-id/google-local-nvme-ssd-7
    
    mdadm: Defaulting to version 1.2 metadata
    mdadm: array /dev/md0 started.
    
    

    É possível confirmar os detalhes da matriz com mdadm --detail. Adicionar a sinalização --prefer=by-id listará os dispositivos usando os caminhos /dev/disk/by-id.

     sudo mdadm --detail --prefer=by-id /dev/md0
     

    A saída será semelhante à mostrada a seguir para cada dispositivo na matriz.

     ...
     Number   Major   Minor   RaidDevice State
        0      259      0         0      active sync   /dev/disk/by-id/google-local-nvme-ssd-0
     ...
     

  6. Formate a matriz /dev/md0 inteira com um sistema de arquivos ext4.

    $ sudo mkfs.ext4 -F /dev/md0
    
  7. Crie um diretório em que seja possível ativar /dev/md0. Neste exemplo, crie o diretório /mnt/disks/ssd-array:

    $ sudo mkdir -p /mnt/disks/[MNT_DIR]
    

    Substitua [MNT_DIR] pelo diretório em que você quer ativar a matriz do SSD local.

  8. Ative a matriz /dev/md0 no diretório /mnt/disks/ssd-array:

    $ sudo mount /dev/md0 /mnt/disks/[MNT_DIR]
    

    Substitua [MNT_DIR] pelo diretório em que você quer ativar a matriz do SSD local.

  9. Configure o acesso de leitura e gravação no dispositivo. Neste exemplo, conceda acesso de gravação no dispositivo a todos os usuários.

    $ sudo chmod a+w /mnt/disks/[MNT_DIR]
    

    Substitua [MNT_DIR] pelo diretório em que você ativou a matriz do SSD local.

Se quiser, adicione o SSD local ao arquivo /etc/fstab para que o dispositivo seja reativado automaticamente quando a instância for reiniciada. Essa entrada não preserva dados no SSD local se a instância for interrompida. Consulte Permanência de dados do SSD local para mais detalhes.

Ao especificar o arquivo /etc/fstab de entrada, inclua a opção nofail para que a instância possa continuar a inicialização mesmo que o SSD local não esteja presente. Por exemplo, se você gerar um snapshot do disco de inicialização e criar uma instância nova sem SSDs locais anexados, a instância poderá continuar o processo de inicialização sem pausar indefinidamente.

  1. Crie a entrada /etc/fstab. Use o comando blkid para localizar o UUID do sistema de arquivos no dispositivo e edite o arquivo /etc/fstab para incluir esse UUID com as opções de ativação. Especifique a opção nofail para permitir que o sistema seja inicializado mesmo se o SSD local estiver indisponível. É possível concluir essa etapa com um único comando. Exemplo:

    $ echo UUID=`sudo blkid -s UUID -o value /dev/md0` /mnt/disks/[MNT_DIR] ext4 discard,defaults,nofail 0 2 | sudo tee -a /etc/fstab
    

    Substitua [MNT_DIR] pelo diretório em que você ativou a matriz do SSD local.

  2. Se você usar um nome de dispositivo como /dev/md0 no arquivo /etc/fstab em vez de UUID, precisará editar o arquivo /etc/mdadm/mdadm.conf para garantir que a matriz seja remontada automaticamente na inicialização. Para isso, siga as duas etapas a seguir:

    1. Verifique se a matriz do disco foi verificada e remontada automaticamente na inicialização.
      $ sudo mdadm --detail --scan | sudo tee -a /etc/mdadm/mdadm.conf
      
    2. Atualize initramfs para que a matriz esteja disponível durante o processo de inicialização antecipada.
      $ sudo update-initramfs -u
      
  3. Use o comando cat para verificar se as entradas /etc/fstab estão corretas:

    $ cat /etc/fstab
    

Se você criar um snapshot a partir do disco de inicialização dessa instância e usá-lo para gerar uma instância separada que não tenha SSDs locais, edite o arquivo /etc/fstab e remova a entrada dessa matriz de SSD local. Mesmo com a opção nofail, mantenha o arquivo /etc/fstab sincronizado com as partições anexadas à instância e remova essas entradas antes de criar o snapshot do disco de inicialização.

Instâncias do Windows

Use a ferramenta de gerenciamento de disco do Windows para formatar e ativar uma matriz de SSDs locais em uma instância do Windows.

  1. Conecte-se à instância por meio do RDP. Neste exemplo, acesse a página "Instâncias de VM" e clique no botão RDP ao lado da instância que tem os SSDs locais anexados. Depois de inserir o nome de usuário e a senha, uma janela é aberta com a interface da área de trabalho do servidor.

  2. Clique com o botão direito do mouse no botão "Iniciar" do Windows e selecione Gerenciamento de Disco.

    Como selecionar a ferramenta "Gerenciamento de Disco" clicando com o botão direito do mouse no botão "Iniciar" do Windows.

  3. Se você não inicializou os SSDs locais antes, a ferramenta solicitará que você selecione um esquema de particionamento para as novas partições. Selecione GPT e clique em OK.

    Selecione um esquema de partição na janela de inicialização do disco.

  4. Após a inicialização do SSD local, clique com o botão direito do mouse no espaço em disco não alocado e selecione Novo Volume Distribuído.

    Crie um novo volume distribuído no disco anexado.

  5. Selecione as partições do SSD local que você quer incluir na matriz distribuída. Neste exemplo, selecione todos as partições para combiná-las em apenas um dispositivo de SSD local.

    Seleção das partições do SSD local a serem incluídas na matriz.

  6. Siga as instruções no Assistente de Novo Volume Distribuído para configurar o novo volume. É possível usar qualquer formato de partição que preferir, mas, neste exemplo, selecione NTFS. Além disso, marque Executar uma formatação rápida para acelerar esse processo.

    Como selecionar o tipo de formato da partição no "Assistente de Novo Volume Distribuído".

  7. Após a conclusão do assistente e da formatação do volume, verifique se o novo SSD local tem o status Healthy.

    Visualize a lista de discos reconhecidos pelo Windows e verifique se o SSD local tem status "Íntegro".

Agora é possível gravar arquivos no SSD local.

A seguir

Saiba mais sobre nomes de dispositivos para sua VM.