修改虚拟机实例的机器类型


如果您的虚拟机没有本地 SSD 且不属于代管式实例组 (MIG),您可以停止虚拟机,然后更改虚拟机的机器类型

如果现有机器类型不适合您在虚拟机上运行的工作负载,请更改该虚拟机的机器类型。在工作负载发生变化时,您可以更改虚拟机的机器类型,以调整 vCPU 数量和内存量。例如,您可以在设置、开发和测试阶段使用具有较小机器类型的虚拟机,然后在准备好运行生产工作负载时将该虚拟机改为使用较大的机器类型。

对于没有本地 SSD 且不属于 MIG 的虚拟机,您可以在不影响以下资源的情况下更改机器类型:

  • 虚拟机的 SSH 密钥
  • 虚拟机配置,例如虚拟机元数据
  • 虚拟机的永久性磁盘数据,包括已安装的应用和应用数据

如果您需要更改 MIG 中的虚拟机的机器类型,请参阅在 MIG 中自动应用虚拟机配置更新

准备工作

  • 了解如何关停虚拟机
  • 了解机器类型
  • 如果您尚未设置身份验证,请进行设置。身份验证是通过其进行身份验证以访问 Google Cloud 服务和 API 的过程。如需从本地开发环境运行代码或示例,您可以按如下方式向 Compute Engine 进行身份验证。

    选择标签页以了解您打算如何使用本页面上的示例:

    控制台

    当您使用 Google Cloud 控制台访问 Google Cloud 服务和 API 时,无需设置身份验证。

    Java

    如需从本地开发环境使用本页面上的 Java 示例,请安装并初始化 gcloud CLI,然后使用用户凭据设置应用默认凭据。

    1. 安装 Google Cloud CLI。
    2. 如需初始化 gcloud CLI,请运行以下命令:

      gcloud init
    3. 为您的 Google 账号创建本地身份验证凭据:

      gcloud auth application-default login

    如需了解详情,请参阅 为本地开发环境设置身份验证

    Python

    如需从本地开发环境使用本页面上的 Python 示例,请安装并初始化 gcloud CLI,然后使用用户凭据设置应用默认凭据。

    1. 安装 Google Cloud CLI。
    2. 如需初始化 gcloud CLI,请运行以下命令:

      gcloud init
    3. 为您的 Google 账号创建本地身份验证凭据:

      gcloud auth application-default login

    如需了解详情,请参阅 为本地开发环境设置身份验证

    REST

    如需在本地开发环境中使用本页面上的 REST API 示例,请使用您提供给 gcloud CLI 的凭据。

      安装 Google Cloud CLI,然后通过运行以下命令初始化 Google Cloud CLI:

      gcloud init

限制

结算影响

不同机器类型的计费费率不同,因此请确保您了解更改机器类型的价格影响。例如,e2-standard-2 机器类型的费用高于 e2-micro 机器类型。

更改机器类型可能还会影响相关虚拟机的持续使用折扣。系统会针对同一区域中的不同类别单独计算持续使用折扣。如果您要更改机器类型,使新机器类型属于其他类别,则虚拟机的后续运行时间将计入新类别的持续使用折扣。

例如,假设您有一个机器类型为 n2-standard-2 的虚拟机,该虚拟机运行了半个月。然后决定将该机器类型更改为 m1-ultramem-40。在您进行此更改后,Compute Engine 就会开始将虚拟机的运行时间计入内存优化的 vCPU 和内存类别的持续使用折扣。

在您的账单上,您会看到机器类型更改之前应用于 n2-standard-2 机器类型的持续使用折扣,以及针对 m1-ultramem-40 的单独持续使用折扣(如果您的虚拟机在 m1-ultramem-40 上保持运行的时间至少占本月剩余时间的 25%)。

最佳做法

以下是一些可帮助您成功更改虚拟机机器类型的最佳实践。

  • 使用快照定期备份永久性磁盘数据。在更改机器类型之前,考虑截取永久性磁盘数据的快照。如果您要确保新机器类型能够支持现有虚拟机上的数据,可以截取永久性磁盘快照,并使用该快照来启动第二个运行新机器类型的虚拟机,以确认该虚拟机将成功启动。

  • 将其他永久性磁盘添加到 /etc/fstab 文件中。如果您已将其他永久性磁盘挂接到虚拟机,请确保将它们添加到 /etc/fstab 文件中,以便在虚拟机重新启动时自动装载这些磁盘。

  • 在更改机器类型之前创建预留。为避免与资源可用性相关的错误,请在新机器类型可用时为它们创建 Compute Engine 预留,以便在区域内进行预留。预留有助于确保资源在您需要时可用。

如需创建预留,请完成以下步骤:

  1. 创建预留(或标识现有预留),其属性与计划虚拟机相同。预留的虚拟机数量必须大于或等于您要更改的虚拟机数量。(可选)为了防止其他虚拟机使用此预留,请使用 specificReservationRequired 选项。

  2. 验证计划的虚拟机是否可以使用该预留:

    1. 验证所需的虚拟机是否具有正确的预留亲和性
    2. 在更改虚拟机之前,立即确保预留具有足够的容量

更改机器类型

您只能更改已停止虚拟机的机器类型。只有当虚拟机处于 TERMINATED 状态时,才会被视为已停止。您无法更改正在运行的虚拟机的机器类型。

如果您要将机器类型升级到最新一代,请先查看将虚拟机迁移到第三代机器系列,然后再继续操作。

执行此任务所需的权限

您必须拥有以下权限才能执行此任务:

  • 针对虚拟机的 compute.instances.setMachineType 权限

控制台

  1. 在 Google Cloud 控制台中,转到虚拟机实例页面。

    转到虚拟机实例

  2. 名称列中,点击您要更改其机器类型的虚拟机的名称。

  3. 虚拟机实例详情页面中,完成以下步骤:

    1. 如果虚拟机正在运行,请在页面顶部的菜单中选择停止以停止虚拟机。
    2. 如需修改虚拟机,请点击 修改
    3. 机器配置部分中,选择要使用的机器类型,或创建自定义机器类型

    4. 要保存更改,请点击保存

    5. 重启虚拟机。

gcloud

  1. 使用 gcloud compute instances stop 命令停止虚拟机:

    gcloud compute instances stop VM_NAME
    

    VM_NAME 替换为包含要更改的机器类型的虚拟机。

  2. 使用 gcloud compute instances set-machine-type 命令更改机器类型。

    gcloud compute instances set-machine-type VM_NAME \
        --machine-type NEW_MACHINE_TYPE
    

    NEW_MACHINE_TYPE 替换为虚拟机的新机器类型。机器类型可以是以下类型之一:

  3. 使用 gcloud compute instances start 命令启动虚拟机:

    gcloud compute instances start VM_NAME
    

    VM_NAME 替换为您更改的虚拟机的名称。

Java

Java

试用此示例之前,请按照《Compute Engine 快速入门:使用客户端库》中的 Java 设置说明进行操作。 如需了解详情,请参阅 Compute Engine Java API 参考文档

如需向 Compute Engine 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证


import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.Instance.Status;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.InstancesSetMachineTypeRequest;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ChangeInstanceMachineType {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Cloud project you want to use.
    String projectId = "your-project-id";
    // Name of the zone your instance belongs to.
    String zone = "zone-name";
    // Name of the VM you want to modify.
    String instanceName = "instance-name";
    // The new machine type you want to use for the VM.
    // For example: "e2-standard-8", "e2-custom-4-2048" or "m1-ultramem-40"
    // More about machine types: https://cloud.google.com/compute/docs/machine-resource
    String newMachineType = "e2-standard-8";
    changeMachineType(projectId, zone, instanceName, newMachineType);
  }

  // Changes the machine type of VM.
  // The VM needs to be in the 'TERMINATED' state for this operation to be successful.
  public static void changeMachineType(String projectId, String zone, String instanceName,
      String newMachineType)
      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()) {

      Instance instance = instancesClient.get(projectId, zone, instanceName);
      if (!instance.getStatus().equals(Status.TERMINATED.name())) {
        throw new Error(String.format(
            "Only machines in TERMINATED state can have their machine type changed. "
                + "%s is in %s state.", instance.getName(), instance.getStatus()));
      }

      InstancesSetMachineTypeRequest machineTypeRequest =
          InstancesSetMachineTypeRequest.newBuilder()
              .setMachineType(String.format("projects/%s/zones/%s/machineTypes/%s",
                  projectId, zone, newMachineType))
              .build();

      Operation response = instancesClient
          .setMachineTypeAsync(projectId, zone, instanceName, machineTypeRequest)
          .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        System.out.println("Machine type update failed! " + response);
        return;
      }
      System.out.println("Machine type update - operation status: " + response.getStatus());
    }
  }
}

Python

Python

试用此示例之前,请按照《Compute Engine 快速入门:使用客户端库》中的 Python 设置说明进行操作。 如需了解详情,请参阅 Compute Engine Python API 参考文档

如需向 Compute Engine 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

from __future__ import annotations

import sys
from typing import Any

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


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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result


def change_machine_type(
    project_id: str, zone: str, instance_name: str, new_machine_type: str
) -> None:
    """
    Changes the machine type of VM. The VM needs to be in the 'TERMINATED' state for this operation to be successful.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone your instance belongs to.
        instance_name: name of the VM you want to modify.
        new_machine_type: the new machine type you want to use for the VM.
            For example: `e2-standard-8`, `e2-custom-4-2048` or `m1-ultramem-40`
            More about machine types: https://cloud.google.com/compute/docs/machine-resource
    """
    client = compute_v1.InstancesClient()
    instance = client.get(project=project_id, zone=zone, instance=instance_name)

    if instance.status != compute_v1.Instance.Status.TERMINATED.name:
        raise RuntimeError(
            f"Only machines in TERMINATED state can have their machine type changed. "
            f"{instance.name} is in {instance.status}({instance.status_message}) state."
        )

    machine_type = compute_v1.InstancesSetMachineTypeRequest()
    machine_type.machine_type = (
        f"projects/{project_id}/zones/{zone}/machineTypes/{new_machine_type}"
    )
    operation = client.set_machine_type(
        project=project_id,
        zone=zone,
        instance=instance_name,
        instances_set_machine_type_request_resource=machine_type,
    )

    wait_for_extended_operation(operation, "changing machine type")

REST

  1. 使用 instances.stop 方法停止虚拟机:

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

    请替换以下内容:

    • PROJECT_ID:项目 ID

    • ZONE:包含虚拟机的可用区

    • VM_NAME:包含要更改的机器类型的虚拟机

  2. 使用 instances.setMachineType 方法更改机器类型:

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

    在请求正文中,提供更新后的 machineType

    {
        machineType: "zones/MACHINE_TYPE_ZONE/machineTypes/NEW_MACHINE_TYPE"
    }
    

    替换以下内容:

    • MACHINE_TYPE_ZONE:包含机器类型的可用区

    • NEW_MACHINE_TYPE:虚拟机的新机器类型

      机器类型可以是以下类型之一:

  3. 使用 instances.start 方法启动虚拟机:

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

    请替换以下内容:

    • PROJECT_ID:项目 ID
    • ZONE:包含虚拟机的可用区
    • VM_NAME:您更改的虚拟机的名称

迁移到较小的机器类型

如果您弃用配备更多资源的机器类型而改用配备较少资源的机器类型(如弃用 e2-standard-8 机器类型而改用 e2-standard-2),可能会遇到硬件资源问题或性能限制,因为较小机器类型不如较大机器类型功能强大。请确保新的机器类型能够支持目前在虚拟机上运行的所有应用和服务,或者更新您的服务和应用以便在较小的机器类型上运行。

在更改机器类型之前,请查阅合理容量建议。如需了解 Compute Engine 的容量建议,请参阅为虚拟机实例应用机器类型建议

将虚拟机迁移到第三代机器系列

满足要求后,您可以通过更改机器类型(例如从 m1-ultramem-160 更改为 m3-ultramem-128)来修改虚拟机以使用新一代机器系列中的机器类型。

第三代机器类型和 Arm T2A 机器类型可能不支持当前机器类型支持的功能和接口。在开始迁移过程之前,请查看准备迁移到新虚拟机中的要求和注意事项。

如需将虚拟机实例的机器类型更改为第三代机器类型,您可以使用以下任一方法。

创建新的虚拟机实例并迁移工作负载

在此过程中,您需要创建一个新的虚拟机实例,然后将工作负载迁移到新虚拟机。

如需详细了解如何完成此过程,请参阅将工作负载从现有虚拟机迁移到新虚拟机

将机器类型更改为新机器类型

在此过程中,您需要验证当前虚拟机实例是否可以更新为使用新的机器类型,然后更改机器类型。

  1. 验证当前虚拟机实例是否使用新机器类型支持的操作系统版本。如果版本不受支持,请按照将工作负载从现有虚拟机迁移到新虚拟机中的说明操作。

  2. 如果您要将虚拟机的机器类型更改为 T2A 机器类型,请按照将工作负载从现有虚拟机迁移到新虚拟机中的说明操作。

  3. 如果当前虚拟机已挂接本地 SSD,请按照将工作负载从现有虚拟机迁移到新虚拟机中的说明操作。

  4. 验证您的应用和程序是否可以支持其他网络或存储接口,例如 gVNIC 或 NVMe。

  5. 查看更改虚拟机的机器类型的最佳实践

  6. 按照更改机器类型中所述的过程操作。

后续步骤