创建实例模板


本页面介绍如何创建和管理实例模板。通过实例模板,您可以指定在创建虚拟机 (VM) 实例时要使用的机器类型、启动磁盘映像、网络和其他虚拟机属性。

您可以使用实例模板执行以下操作:

准备工作

  • 了解何时以及为何要创建确定性实例模板
  • 了解区域和全球实例模板
  • 如果您尚未设置身份验证,请进行设置。 身份验证是通过其进行身份验证以访问 Google Cloud 服务和 API 的过程。如需从本地开发环境运行代码或示例,您可以按如下方式向 Compute Engine 进行身份验证。

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

    控制台

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

    gcloud

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

      gcloud init
    2. 设置默认区域和可用区

    Terraform

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

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

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

      gcloud auth application-default login

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

    Go

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

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

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

      gcloud auth application-default login

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

    Java

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

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

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

      gcloud auth application-default login

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

    Node.js

    如需从本地开发环境使用本页面上的 Node.js 示例,请安装并初始化 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

限制

  • gcloud CLI 和 REST 支持实例模板中位于 nic0 以外的接口的共享 VPC,但 Google Cloud 控制台不支持。
  • 您无法更新现有实例模板,也无法在创建实例模板后对其进行更改。如果实例模板过期,或者您需要更改配置,请创建一个新的实例模板。
  • 如果您要在实例模板中指定映像系列,则不能使用 Google Cloud 控制台。您可以改用 Google Cloud CLI 或 REST。
  • 如果要在实例模板中指定区域永久性磁盘,则不能使用 Google Cloud 控制台。您可以改用 Google Cloud CLI 或 REST。

创建实例模板

您在创建单个虚拟机实例的请求中指定的大多数虚拟机属性也可以为实例模板指定,包括任何虚拟机元数据、启动脚本、永久性磁盘、服务账号等等。您必须指定机器类型、启动磁盘和网络。

通过 Google Cloud 控制台Google Cloud CLIAPI 创建区域或全局实例模板。如需创建全局实例模板,您也可以使用 Terraform 或 Cloud 客户端库

控制台

  1. 在 Google Cloud 控制台中,打开实例模板页面。

    转到“实例模板”

    其余步骤将自动显示在 Google Cloud 控制台中。

  2. 点击创建实例模板
  3. 按如下方式选择位置
    1. 如果要跨区域使用实例模板,请选择全球级
    2. 如果要降低跨区域依赖性,请选择区域级
  4. 如果选择区域级,则选择要在其中创建实例模板的区域
  5. 对于以下字段,接受默认值或根据需要进行修改。默认值会根据您所选的机器系列而变化。

    • 选择机器类型
    • 如需更新启动磁盘类型或映像,请在启动磁盘部分中点击更改
    • 如需更新网络接口或 IP 地址设置,请点击高级选项,点击网络,然后点击要修改的网络接口。
  6. 可选:如果您选择了支持安全强化型虚拟机的映像,请更改虚拟机的安全强化型虚拟机设置:

    1. 点击高级选项,然后点击安全标签页。
    2. 如果您要停用安全启动,取消选中开启安全启动复选框。安全启动功能可帮助保护您的虚拟机实例免受启动级和内核级恶意软件和 rootkit 的攻击。如需了解详情,请参阅安全启动
    3. 如果您要停用虚拟可信平台模块 (vTPM),取消选中开启 vTPM 复选框。vTPM 将启用测量启动,该功能可验证虚拟机预启动和启动完整性。如需了解详情,请参阅虚拟可信平台模块 (vTPM)

    4. 如果您要停用完整性监控,请取消选中开启完整性监控复选框。借助完整性监控功能,您可以使用 Cloud Monitoring 监控安全强化型虚拟机实例的启动完整性。如需了解详情,请参阅完整性监控

  7. 可选:在高级选项下,点击相应标签页以进一步自定义模板。例如,您最多可以添加 15 个辅助非启动磁盘。

  8. 可选:点击等效 REST 以查看 REST 请求正文,其中包括您的实例模板的 JSON 表示法

  9. 点击创建以创建模板。

gcloud

如需创建区域或全局实例模板,请使用 instance-templates create 命令。对于区域实例模板,您必须使用 --instance-template-region 标志来设置模板的区域。

使用以下命令创建区域实例模板:

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --instance-template-region=REGION

使用以下命令创建全球实例模板:

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME

如果您未提供明确的模板设置,gcloud compute 将使用以下默认值:

  • 机器类型:例如 n1-standard-1
  • 映像:最新的 Debian 映像
  • 启动磁盘:以虚拟机命名的新标准启动磁盘
  • 网络:默认 VPC 网络
  • IP 地址:临时外部 IP 地址

您也可以明确提供这些配置设置。例如:

gcloud compute instance-templates create example-template-custom \
    --machine-type=e2-standard-4 \
    --image-family=debian-10 \
    --image-project=debian-cloud \
    --boot-disk-size=250GB

您最多可以添加 15 个辅助非启动磁盘。为您创建的每个辅助磁盘指定 --create-disk 标志。如需通过公共映像或自定义映像创建辅助磁盘,请在 --create-disk 标志中为每个磁盘指定 imageimage-project 属性。如需创建空白磁盘,请勿包含这些属性。您可以根据需要添加磁盘属性 sizetype。如需指定区域级永久性磁盘,请使用 replica-zones 属性。

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --create-disk= \
        image-family=DISK_IMAGE_FAMILY, \
        image-project=DISK_IMAGE_PROJECT, \
        size=SIZE_GB_DISK1 \
    --create-disk= \
        device-name=DISK_NAME,type=DISK_TYPE, \
        size=SIZE_GB_DISK2 \
        replica-zones=^:^ZONE:REMOTE_ZONE, \
        boot=false

替换以下内容:

  • INSTANCE_TEMPLATE_NAME:模板的名称
  • REGION:要创建区域实例模板的区域
  • IMAGE_FAMILY:要用作非启动磁盘的映像系列

    如需详细了解映像系列,请参阅在 Compute Engine 上使用映像系列时的最佳做法

    您可以改用 --image=IMAGE 标志来指定映像的特定版本。

    对于空白磁盘,请勿指定 image-familyimage 属性。

  • DISK_IMAGE_PROJECT:映像所属的映像项目

    对于空白磁盘,请勿指定 image-project 属性。如需详细了解公共映像,请参阅公共映像

  • SIZE_GB_DISK1SIZE_GB_DISK2:每个辅助磁盘的大小

  • DISK_NAME(可选):创建虚拟机后向客机操作系统显示的磁盘名称。

  • DISK_TYPE(可选):要创建的磁盘类型。如果未指定,则默认值为 pd-standardpd-balanced,具体取决于机器类型。

  • ZONEREMOTE_ZONE:要在其中创建区域永久性磁盘的可用区,以及要将磁盘复制到的可用区。

    对于可用区级磁盘,请勿添加 replica-zones 属性。

如果选择支持受防护的虚拟机的映像,则可以选择使用以下标志之一更改实例的受防护的虚拟机设置:

  • --no-shielded-secure-boot:关闭安全启动

    安全启动功能可帮助保护您的虚拟机实例免受启动级和内核级恶意软件和 rootkit 的攻击。如需了解详情,请参阅安全启动

  • --no-shielded-vtpm:关闭虚拟可信平台模块 (vTPM)

    vTPM 将启用测量启动,该功能可验证虚拟机预启动和启动完整性。如需了解详情,请参阅虚拟可信平台模块 (vTPM)

  • --no-shielded-integrity-monitoring:关闭完整性监控

    借助完整性监控功能,您可以使用 Cloud Monitoring 监控安全强化型虚拟机实例的启动完整性。如需了解详情,请参阅完整性监控

如需查看所有可用子命令和标志的列表,请参阅 instance-templates 参考文档

采用了默认配置设置的模板可能如下所示:

gcloud compute instance-templates describe example-template
creationTimestamp: '2019-09-10T16:18:32.042-07:00'
description: ''
id: '6057583701980539406'
kind: compute#instanceTemplate
name: example-template
properties:
  canIpForward: false
  disks:
  - autoDelete: true
    boot: true
    initializeParams:
      sourceImage: https://compute.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-10
    kind: compute#attachedDisk
    mode: READ_WRITE
    type: PERSISTENT
  machineType: e2-standard-2
  networkInterfaces:
  - accessConfigs:
    - kind: compute#accessConfig
      name: external-nat
      type: ONE_TO_ONE_NAT
    network: https://compute.googleapis.com/compute/v1/projects/myproject/global/networks/default
  scheduling:
    automaticRestart: true
    onHostMaintenance: MIGRATE
  serviceAccounts:
  - email: default
    scopes:
    - https://www.googleapis.com/auth/devstorage.read_only
selfLink: https://compute.googleapis.com/compute/v1/projects/myproject/global/instanceTemplates/example-template

Terraform

如需创建实例模板,您可以使用 google_compute_instance_template 资源

以下 Terraform 示例类似于以下 gcloud CLI 命令:

gcloud compute instance-templates create my-instance-template \
    --machine-type=e2-standard-4 \
    --image-family=debian-9 \
    --image-project=debian-cloud \
    --boot-disk-size=250GB
resource "google_compute_instance_template" "foobar" {
  name         = "my-instance-template"
  machine_type = "e2-standard-4"

  disk {
    source_image = "debian-cloud/debian-11"
    disk_size_gb = 250
  }

  network_interface {
    network = "default"

    # default access config, defining external IP configuration
    access_config {
      network_tier = "PREMIUM"
    }
  }

  # To avoid embedding secret keys or user credentials in the instances, Google recommends that you use custom service accounts with the following access scopes.
  service_account {
    scopes = [
      "https://www.googleapis.com/auth/devstorage.read_only",
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring.write",
      "https://www.googleapis.com/auth/pubsub",
      "https://www.googleapis.com/auth/service.management.readonly",
      "https://www.googleapis.com/auth/servicecontrol",
      "https://www.googleapis.com/auth/trace.append",
    ]
  }
}

如需了解如何应用或移除 Terraform 配置,请参阅基本 Terraform 命令

Go

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"
)

// createTemplate creates a new instance template with the provided name and a specific instance configuration.
func createTemplate(w io.Writer, projectID, templateName string) error {
	// projectID := "your_project_id"
	// templateName := "your_template_name"

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

	req := &computepb.InsertInstanceTemplateRequest{
		Project: projectID,
		InstanceTemplateResource: &computepb.InstanceTemplate{
			Name: proto.String(templateName),
			Properties: &computepb.InstanceProperties{
				// The template describes the size and source image of the boot disk
				// to attach to the instance.
				Disks: []*computepb.AttachedDisk{
					{
						InitializeParams: &computepb.AttachedDiskInitializeParams{
							DiskSizeGb:  proto.Int64(250),
							SourceImage: proto.String("projects/debian-cloud/global/images/family/debian-11"),
						},
						AutoDelete: proto.Bool(true),
						Boot:       proto.Bool(true),
					},
				},
				MachineType: proto.String("e2-standard-4"),
				// The template connects the instance to the `default` network,
				// without specifying a subnetwork.
				NetworkInterfaces: []*computepb.NetworkInterface{
					{
						Name: proto.String("global/networks/default"),
						// The template lets the instance use an external IP address.
						AccessConfigs: []*computepb.AccessConfig{
							{
								Name:        proto.String("External NAT"),
								Type:        proto.String(computepb.AccessConfig_ONE_TO_ONE_NAT.String()),
								NetworkTier: proto.String(computepb.AccessConfig_PREMIUM.String()),
							},
						},
					},
				},
			},
		},
	}

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

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

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

	return nil
}

Java

import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.NetworkTier;
import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.GlobalOperationsClient;
import com.google.cloud.compute.v1.InsertInstanceTemplateRequest;
import com.google.cloud.compute.v1.InstanceProperties;
import com.google.cloud.compute.v1.InstanceTemplate;
import com.google.cloud.compute.v1.InstanceTemplatesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateInstanceTemplate {

  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 use.
    // templateName: name of the new template to create.
    String projectId = "your-project-id";
    String templateName = "template-name";
    createInstanceTemplate(projectId, templateName);
  }

  /*
    Create a new instance template with the provided name and a specific
    instance configuration.
   */
  public static void createInstanceTemplate(String projectId, String templateName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    try (InstanceTemplatesClient instanceTemplatesClient = InstanceTemplatesClient.create()) {

      String machineType = "e2-standard-4";
      String sourceImage = "projects/debian-cloud/global/images/family/debian-11";

      // The template describes the size and source image of the boot disk
      // to attach to the instance.
      AttachedDisk attachedDisk = AttachedDisk.newBuilder()
          .setInitializeParams(AttachedDiskInitializeParams.newBuilder()
              .setSourceImage(sourceImage)
              .setDiskType("pd-balanced")
              .setDiskSizeGb(250).build())
          .setAutoDelete(true)
          .setBoot(true).build();

      // The template connects the instance to the `default` network,
      // without specifying a subnetwork.
      NetworkInterface networkInterface = NetworkInterface.newBuilder()
          .setName("global/networks/default")
          // The template lets the instance use an external IP address.
          .addAccessConfigs(AccessConfig.newBuilder()
              .setName("External NAT")
              .setType(AccessConfig.Type.ONE_TO_ONE_NAT.toString())
              .setNetworkTier(NetworkTier.PREMIUM.toString()).build()).build();

      InstanceProperties instanceProperties = InstanceProperties.newBuilder()
          .addDisks(attachedDisk)
          .setMachineType(machineType)
          .addNetworkInterfaces(networkInterface).build();

      InsertInstanceTemplateRequest insertInstanceTemplateRequest = InsertInstanceTemplateRequest
          .newBuilder()
          .setProject(projectId)
          .setInstanceTemplateResource(InstanceTemplate.newBuilder()
              .setName(templateName)
              .setProperties(instanceProperties).build()).build();

      // Create the Instance Template.
      Operation response = instanceTemplatesClient.insertAsync(insertInstanceTemplateRequest)
          .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        System.out.println("Instance Template creation failed ! ! " + response);
        return;
      }
      System.out
          .printf("Instance Template Operation Status %s: %s", templateName, response.getStatus());
    }
  }

  public static void createInstanceTemplateWithDiskType(String projectId, String templateName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    try (InstanceTemplatesClient instanceTemplatesClient = InstanceTemplatesClient.create();
        GlobalOperationsClient globalOperationsClient = GlobalOperationsClient.create()) {

      AttachedDisk disk = AttachedDisk.newBuilder()
          .setInitializeParams(AttachedDiskInitializeParams.newBuilder()
              .setDiskSizeGb(10)
              .setDiskType("pd-balanced")
              .setSourceImage("projects/debian-cloud/global/images/family/debian-10").build())
          .setAutoDelete(true)
          .setBoot(true)
          .setType(AttachedDisk.Type.PERSISTENT.toString()).build();

      InstanceTemplate instanceTemplate = InstanceTemplate.newBuilder()
          .setName(templateName)
          .setProperties(InstanceProperties.newBuilder()
              .setMachineType("n1-standard-1")
              .addDisks(disk)
              .addNetworkInterfaces(NetworkInterface.newBuilder()
                  .setName("global/networks/default").build()).build()).build();

      InsertInstanceTemplateRequest insertInstanceTemplateRequest = InsertInstanceTemplateRequest
          .newBuilder()
          .setProject(projectId)
          .setInstanceTemplateResource(instanceTemplate).build();

      Operation response = instanceTemplatesClient.insertAsync(insertInstanceTemplateRequest)
          .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        System.out.println("Instance Template creation failed ! ! " + response);
        return;
      }
      System.out
          .printf("Instance Template Operation Status %s: %s", templateName, response.getStatus());
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const templateName = 'your_template_name';

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

// Create a new instance template with the provided name and a specific instance configuration.
async function createTemplate() {
  const instanceTemplatesClient = new compute.InstanceTemplatesClient();

  const [response] = await instanceTemplatesClient.insert({
    project: projectId,
    instanceTemplateResource: {
      name: templateName,
      properties: {
        disks: [
          {
            // The template describes the size and source image of the boot disk
            // to attach to the instance.
            initializeParams: {
              diskSizeGb: '250',
              sourceImage:
                'projects/debian-cloud/global/images/family/debian-11',
            },
            autoDelete: true,
            boot: true,
          },
        ],
        machineType: 'e2-standard-4',
        // The template connects the instance to the `default` network,
        // without specifying a subnetwork.
        networkInterfaces: [
          {
            // Use the network interface provided in the networkName argument.
            name: 'global/networks/default',
            // The template lets the instance use an external IP address.
            accessConfigs: [
              {
                name: 'External NAT',
                type: 'ONE_TO_ONE_NAT',
                networkTier: 'PREMIUM',
              },
            ],
          },
        ],
      },
    },
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.GlobalOperationsClient();

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

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

createTemplate();

Python

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 create_template(project_id: str, template_name: str) -> compute_v1.InstanceTemplate:
    """
    Create a new instance template with the provided name and a specific
    instance configuration.

    Args:
        project_id: project ID or project number of the Cloud project you use.
        template_name: name of the new template to create.

    Returns:
        InstanceTemplate object that represents the new instance template.
    """
    # The template describes the size and source image of the boot disk
    # to attach to the instance.
    disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = (
        "projects/debian-cloud/global/images/family/debian-11"
    )
    initialize_params.disk_size_gb = 250
    disk.initialize_params = initialize_params
    disk.auto_delete = True
    disk.boot = True

    # The template connects the instance to the `default` network,
    # without specifying a subnetwork.
    network_interface = compute_v1.NetworkInterface()
    network_interface.name = "global/networks/default"

    # The template lets the instance use an external IP address.
    access_config = compute_v1.AccessConfig()
    access_config.name = "External NAT"
    access_config.type_ = "ONE_TO_ONE_NAT"
    access_config.network_tier = "PREMIUM"
    network_interface.access_configs = [access_config]

    template = compute_v1.InstanceTemplate()
    template.name = template_name
    template.properties.disks = [disk]
    template.properties.machine_type = "e2-standard-4"
    template.properties.network_interfaces = [network_interface]

    template_client = compute_v1.InstanceTemplatesClient()
    operation = template_client.insert(
        project=project_id, instance_template_resource=template
    )

    wait_for_extended_operation(operation, "instance template creation")

    return template_client.get(project=project_id, instance_template=template_name)

REST

如需创建区域级实例模板,请向 regionInstanceTemplates.insert 方法发出 POST 请求,如下所示:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION/instanceTemplates

如需创建全局实例模板,请向 instanceTemplates.insert 方法发出 POST 请求:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/instanceTemplates

使用 disks 属性您最多可以添加 15 个辅助非启动磁盘,每个额外磁盘都有一个字段。对于每个额外的磁盘,您可以执行以下操作:

  • 使用公共映像或自定义映像创建额外磁盘。
  • 如需添加空白磁盘,请定义不带 sourceImage 值的 initializeParams 条目。
  • 如需创建区域级永久性磁盘,请使用属性 replicaZones 定义 initializeParams 条目。

在请求正文中,提供模板属性:

{
  "name": "INSTANCE_TEMPLATE_NAME",
  "properties": {
    "machineType": "MACHINE_TYPE",
    "networkInterfaces": [
      {
        "network": "global/networks/default",
        "accessConfigs":
        [
          {
            "name": "external-IP",
            "type": "ONE_TO_ONE_NAT"
          }
        ]
      }
    ],
    "disks":
    [
      {
        "type": "PERSISTENT",
        "boot": true,
        "mode": "READ_WRITE",
        "initializeParams":
        {
          "sourceImage": "projects/IMAGE_PROJECT/global/images/IMAGE"
        }
      },
      {
        "type": "PERSISTENT",
        "boot": false,
        "deviceName": "DISK_NAME",
        "initializeParams":
        {
          "replicaZones": [
              "projects/PROJECT_NAME/zones/ZONE",
              "projects/PROJECT_NAME/zones/REMOTE_ZONE"
          ]
        }
      }
    ]
  }
}

替换以下内容:

  • PROJECT_ID:您的项目 ID
  • REGION:要在其中创建区域实例模板的区域
  • INSTANCE_TEMPLATE_NAME:实例模板的名称
  • ZONE:虚拟机所在的可用区
  • MACHINE_TYPE:虚拟机的机器类型

  • IMAGE_PROJECT:映像所属的映像项目

    如需详细了解公共映像,请参阅公共映像

  • IMAGEIMAGE_FAMILY:指定以下其中一项:
    • IMAGE:映像的特定版本

      例如 "sourceImage": "projects/debian-cloud/global/images/debian-10-buster-v20200309"

    • IMAGE_FAMILY映像系列

      此项表示通过最新的未弃用的操作系统映像创建虚拟机。 例如,如果您指定 "sourceImage": "projects/debian-cloud/global/images/family/debian-10",则 Compute Engine 会通过 Debian 10 映像系列中最新版本的操作系统映像创建虚拟机。

      如需详细了解映像系列,请参阅在 Compute Engine 上使用映像系列时的最佳做法

  • DISK_NAME(可选):创建虚拟机后向客机操作系统显示的磁盘名称。

  • PROJECT_NAME:与虚拟机关联的项目

  • REMOTE_ZONE:区域级磁盘应复制到的可用区

您可以为 disks 属性指定以下选项之一:

  • 指定 initializeParams 可为每个实例创建永久性启动磁盘。通过对每个额外磁盘使用 initializeParams 属性,最多可以添加 15 个辅助非启动磁盘。您可以使用 sourceImage 中的公共或自定义映像(或映像系列)创建磁盘,如上例所示。如需添加空白磁盘,请勿指定 sourceImage

  • 指定 source 可挂接现有的永久性启动磁盘。如果挂接现有启动磁盘,则只能通过模板创建一个实例。

另外,您也可以视需要为 initializeParams 指定 diskSizeGbdiskTypelabels 属性,为 source 指定 diskSizeGb 属性。

如果选择支持安全强化型虚拟机的映像,则可以视需要使用以下布尔值请求正文项更改虚拟机的安全强化型虚拟机设置:

  • enableSecureBoot:开启或关闭安全启动

    安全启动功能可帮助保护您的虚拟机实例免受启动级和内核级恶意软件和 rootkit 的攻击。如需了解详情,请参阅安全启动

  • enableVtpm:开启或关闭虚拟可信平台模块 (vTPM)

    vTPM 将启用测量启动,该功能可验证虚拟机预启动和启动完整性。如需了解详情,请参阅虚拟可信平台模块 (vTPM)

  • enableIntegrityMonitoring:开启或关闭完整性监控

    借助完整性监控功能,您可以使用 Cloud Monitoring 报告监控和验证安全强化型虚拟机实例的运行时启动完整性。如需了解详情,请参阅完整性监控

如需详细了解请求参数,请参阅 instanceTemplates.insert 方法

根据现有实例创建实例模板

您可以使用 REST 或 gcloud CLI 将现有虚拟机实例的配置另存为实例模板。(可选)您可以覆盖模板中定义实例的来源磁盘的方式。

如果您需要覆盖其他属性,请先根据现有实例创建一个实例模板,然后借助其他覆盖创建一个类似模板

gcloud

使用带有 --source-instance--source-instance-zone 标志的 gcloud compute instance-templates create 命令。 如果您要创建区域实例模板,则还必须使用 --instance-template-region 标志来指定实例模板的区域。

如需创建区域实例模板,请使用以下命令:

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --source-instance=SOURCE_INSTANCE \
    --source-instance-zone=SOURCE_INSTANCE_ZONE \
    --instance-template-region=REGION

如需创建全局实例模板,请使用以下命令:

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --source-instance=SOURCE_INSTANCE \
    --source-instance-zone=SOURCE_INSTANCE_ZONE

如需替换源实例的磁盘定义方式,请添加一个或多个 --configure-disk 标志。

以下示例根据现有实例创建全局实例模板,并使用您提供的规范替换源实例的磁盘。

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --source-instance=SOURCE_INSTANCE \
    --source-instance-zone=SOURCE_INSTANCE_ZONE \
    --configure-disk= \
        device-name=SOURCE_DISK, \
        instantiate-from=INSTANTIATE_OPTIONS, \
        auto-delete=AUTO_DELETE

替换以下内容:

  • INSTANCE_TEMPLATE_NAME 是要创建的模板的名称。
  • SOURCE_INSTANCE 是要用作新模板的模型的实例名称。
  • SOURCE_INSTANCE_ZONE 是包含来源实例的可用区。
  • REGION 是要创建区域实例模板的区域。
  • SOURCE_DISK 是您要在模板中替换的来源实例磁盘的名称。
  • INSTANTIATE_OPTIONS 指定是否添加磁盘以及要使用的映像。有效值取决于磁盘类型,具体如下:

    • source-imagesource-image-family(仅对启动磁盘和其他永久性读写磁盘有效)。如果要使用用于在来源虚拟机实例中创建磁盘的来源映像或来源映像系列,请指定此选项。
    • custom-image(仅对启动磁盘和其他永久性读写磁盘有效)。如果要在实例模板中保留来源虚拟机中的应用和设置,您可以创建自定义映像,然后在创建模板时指定该映像。指定时,请提供自定义映像的路径或网址,如以下示例所示。或者,您也可以使用以下格式指定映像系列:

      --configure-disk=device-name=DATA_DISK_NAME,instantiate-from=custom-image,
      custom-image=projects/PROJECT_ID/global/images/family/IMAGE_FAMILY_NAME

    • attach-read-only(仅对只读磁盘有效)。

    • blank(仅对非启动永久性磁盘和本地 SSD 有效)。如果已指定,则在使用模板创建新实例时,将创建未格式化的该磁盘。您必须先在启动脚本中格式化并装载该磁盘,然后才能在可扩缩的设置中使用。

    • do-not-include(仅对非启动永久性磁盘和只读磁盘有效)。

  • AUTO_DELETE 指定删除实例时是否自动删除磁盘。有效值为 falsenotrueyes

例如,以下命令会根据 my-source-instance 创建一个实例模板,同时可以选择使用 data-disk-a 的原始映像,但将 auto-delete 设置为 true,并将 data-disk-b 替换为自定义映像。

gcloud compute instance-templates create my-instance-template  \
    --source-instance=my-source-instance \
    --configure-disk=device-name=data-disk-a,instantiate-from=source-image, \
      auto-delete=true
    --configure-disk=device-name=data-disk-b,instantiate-from=custom-image, \
      custom-image=projects/cps-cloud/global/images/cos-89-16108-403-15

Go

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"
)

// createTemplateFromInstance creates a new instance template based on an existing instance.
// This new template specifies a different boot disk.
func createTemplateFromInstance(w io.Writer, projectID, instance, templateName string) error {
	// projectID := "your_project_id"
	// instance := "projects/project/zones/zone/instances/instance"
	// templateName := "your_template_name"

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

	req := &computepb.InsertInstanceTemplateRequest{
		Project: projectID,
		InstanceTemplateResource: &computepb.InstanceTemplate{
			Name:           proto.String(templateName),
			SourceInstance: proto.String(instance),
			SourceInstanceParams: &computepb.SourceInstanceParams{
				DiskConfigs: []*computepb.DiskInstantiationConfig{
					{
						// Device name must match the name of a disk attached to the instance
						// your template is based on.
						DeviceName: proto.String("disk-1"),
						// Replace the original boot disk image used in your instance with a Rocky Linux image.
						InstantiateFrom: proto.String(computepb.DiskInstantiationConfig_CUSTOM_IMAGE.String()),
						CustomImage:     proto.String("projects/rocky-linux-cloud/global/images/family/rocky-linux-8"),
						// Override the auto_delete setting.
						AutoDelete: proto.Bool(true),
					},
				},
			},
		},
	}

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

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

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

	return nil
}

Java


import com.google.cloud.compute.v1.DiskInstantiationConfig;
import com.google.cloud.compute.v1.DiskInstantiationConfig.InstantiateFrom;
import com.google.cloud.compute.v1.GlobalOperationsClient;
import com.google.cloud.compute.v1.InsertInstanceTemplateRequest;
import com.google.cloud.compute.v1.InstanceTemplate;
import com.google.cloud.compute.v1.InstanceTemplatesClient;
import com.google.cloud.compute.v1.Operation;
import com.google.cloud.compute.v1.SourceInstanceParams;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateTemplateFromInstance {

  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 use.
    // instance: the instance to base the new template on. This value uses the following format:
    // **NOTE**: "projects/{project}/zones/{zone}/instances/{instance_name}"
    // templateName: name of the new template to create.
    String projectId = "your-project-id";
    String templateName = "template-name";
    String instance = String.format("projects/%s/zones/%s/instances/%s", projectId, "zone",
        "instanceName");
    createTemplateFromInstance(projectId, templateName, instance);
  }

  // Create a new instance template based on an existing instance.
  // This new template specifies a different boot disk.
  public static void createTemplateFromInstance(String projectId, String templateName,
      String instance)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    try (InstanceTemplatesClient instanceTemplatesClient = InstanceTemplatesClient.create();
        GlobalOperationsClient globalOperationsClient = GlobalOperationsClient.create()) {

      SourceInstanceParams sourceInstanceParams = SourceInstanceParams.newBuilder()
          .addDiskConfigs(DiskInstantiationConfig.newBuilder()
              // Device name must match the name of a disk attached to the instance you are
              // basing your template on.
              .setDeviceName("disk-1")
              // Replace the original boot disk image used in your instance
              // with a Rocky Linux image.
              .setInstantiateFrom(InstantiateFrom.CUSTOM_IMAGE.toString())
              .setCustomImage(
                  String.format("projects/%s/global/images/family/%s", "rocky-linux-cloud",
                      "rocky-linux-8"))
              // Override the AutoDelete setting.
              .setAutoDelete(true).build())
          .build();

      InstanceTemplate instanceTemplate = InstanceTemplate.newBuilder()
          .setName(templateName)
          .setSourceInstance(instance)
          .setSourceInstanceParams(sourceInstanceParams)
          .build();

      InsertInstanceTemplateRequest insertInstanceTemplateRequest = InsertInstanceTemplateRequest
          .newBuilder()
          .setProject(projectId)
          .setInstanceTemplateResource(instanceTemplate)
          .build();

      Operation operation = instanceTemplatesClient.insertCallable()
          .futureCall(insertInstanceTemplateRequest).get(3, TimeUnit.MINUTES);

      Operation response = globalOperationsClient.wait(projectId, operation.getName());

      if (response.hasError()) {
        System.out.println("Instance Template creation failed ! ! " + response);
        return;
      }
      System.out.printf("Instance Template creation operation status %s: %s", templateName,
          response.getStatus());
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const instance = 'projects/project/zones/zone/instances/instance';
// const templateName = 'your_template_name';

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

// Create a new instance template based on an existing instance.
// This new template specifies a different boot disk.
async function createTemplateFromInstance() {
  const instanceTemplatesClient = new compute.InstanceTemplatesClient();

  const [response] = await instanceTemplatesClient.insert({
    project: projectId,
    instanceTemplateResource: {
      name: templateName,
      sourceInstance: instance,
      sourceInstanceParams: {
        diskConfigs: [
          {
            // Device name must match the name of a disk attached to the instance
            // your template is based on.
            deviceName: 'disk-1',
            // Replace the original boot disk image used in your instance with a Rocky Linux image.
            instantiateFrom: 'CUSTOM_IMAGE',
            customImage:
              'projects/rocky-linux-cloud/global/images/family/rocky-linux-8',
            // Override the auto_delete setting.
            autoDelete: true,
          },
        ],
      },
    },
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.GlobalOperationsClient();

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

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

createTemplateFromInstance();

Python

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 create_template_from_instance(
    project_id: str, instance: str, template_name: str
) -> compute_v1.InstanceTemplate:
    """
    Create a new instance template based on an existing instance.
    This new template specifies a different boot disk.

    Args:
        project_id: project ID or project number of the Cloud project you use.
        instance: the instance to base the new template on. This value uses
            the following format: "projects/{project}/zones/{zone}/instances/{instance_name}"
        template_name: name of the new template to create.

    Returns:
        InstanceTemplate object that represents the new instance template.
    """
    disk = compute_v1.DiskInstantiationConfig()
    # Device name must match the name of a disk attached to the instance you are
    # basing your template on.
    disk.device_name = "disk-1"
    # Replace the original boot disk image used in your instance with a Rocky Linux image.
    disk.instantiate_from = "CUSTOM_IMAGE"
    disk.custom_image = "projects/rocky-linux-cloud/global/images/family/rocky-linux-8"
    # Override the auto_delete setting.
    disk.auto_delete = True

    template = compute_v1.InstanceTemplate()
    template.name = template_name
    template.source_instance = instance
    template.source_instance_params = compute_v1.SourceInstanceParams()
    template.source_instance_params.disk_configs = [disk]

    template_client = compute_v1.InstanceTemplatesClient()
    operation = template_client.insert(
        project=project_id, instance_template_resource=template
    )

    wait_for_extended_operation(operation, "instance template creation")

    return template_client.get(project=project_id, instance_template=template_name)

REST

如需创建区域级实例模板,请使用 regionInstanceTemplates.insert 方法;如需创建全局实例模板,请使用 instanceTemplates.insert 方法

您必须在请求中指定 sourceInstance 字段。如需替换如何定义源实例的磁盘,请添加一个或多个 diskConfigs 字段。

例如,进行以下调用,以根据现有实例创建全局实例模板。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/instanceTemplates

{
  "name": "INSTANCE_TEMPLATE_NAME",
  "sourceInstance": "zones/SOURCE_INSTANCE_ZONE/instances/SOURCE_INSTANCE",
  "sourceInstanceParams": {
    "diskConfigs": [
      {
        "deviceName": "SOURCE_DISK",
        "instantiateFrom": "INSTANTIATE_OPTIONS",
        "autoDelete": false
      }
    ]
  }
}

替换以下内容:

  • PROJECT_ID:您的项目 ID
  • INSTANCE_TEMPLATE_NAME:新模板的名称
  • SOURCE_INSTANCE_ZONE:来源实例所在的可用区
  • SOURCE_INSTANCE:要用作此实例模板模型的来源实例的名称
  • SOURCE_DISK:您要在模板中替换的来源实例磁盘的名称
  • INSTANTIATE_OPTIONS 指定是否添加磁盘以及要使用的映像

    有效值取决于磁盘类型,具体如下:

    • source-imagesource-image-family(仅对启动磁盘和其他永久性读写磁盘有效)。
    • custom-image(仅对启动磁盘和其他永久性读写磁盘有效)。如果要在实例模板中保留来源虚拟机中的应用和设置,您可以创建自定义映像,然后在创建模板时指定该映像。指定时,请提供自定义映像的路径或网址,如以下示例所示。或者,您也可以使用以下格式指定映像系列:

      --configure-disk=device-name=DATA_DISK_NAME,instantiate-from=custom-image,
      custom-image=projects/PROJECT_ID/global/images/family/IMAGE_FAMILY_NAME

    • attach-read-only(仅对只读磁盘有效)。

    • blank(仅对非启动永久性磁盘和本地 SSD 有效)。如果已指定,则在使用模板创建新实例时,将创建未格式化的该磁盘。您必须先在启动脚本中格式化并装载该磁盘,然后才能在可扩缩的设置中使用。

    • do-not-include(仅对非启动永久性磁盘和只读磁盘有效)。

以下示例将根据 my-source-instance 创建新的实例模板。在实例模板中,data-disk-a 的映像被替换为 projects/cos-cloud/global/images/cos-89-16108-403-15

POST https://compute.googleapis.com/compute/v1/projects/my_project/global/instanceTemplates

{
  "name": "my-instance-template",
  "sourceInstance": "zones/us-central1-a/instances/my-source-instance",
  "sourceInstanceParams":
  {
    "diskConfigs":
    [
      {
        "deviceName": "data-disk-a",
        "instantiateFrom": "custom-image",
        "customImage": "projects/cos-cloud/global/images/cos-89-16108-403-15"
      }
    ]
  }
}

下表显示了在模板中定义覆盖磁盘的选项。

磁盘类型 选项
启动磁盘
  • [默认] 使用用于在来源实例中创建启动磁盘的相同来源映像或映像系列。
  • 使用前面示例中所述的任何映像(自定义或公共)的网址,或使用以下格式指定映像系列:
  • projects/exampleproject/global/images/family/IMAGE_FAMILY_NAME

其他读写永久性磁盘
  • [默认] 使用用于在来源实例中创建磁盘的来源映像/来源映像系列。注意:如果来源实例的磁盘没有来源映像/来源映像系列属性,则系统会将其作为空白磁盘添加到模板中。
  • 使用前面示例中所述的任何映像(自定义或公共)的网址,或使用以下格式指定映像系列:

    projects/exampleproject/global/images/family/IMAGE_FAMILY_NAME

  • 在模板中使用空白磁盘。使用模板创建新实例时,将创建未格式化的此磁盘。 您必须先在启动脚本中格式化并装载该磁盘,然后才能在可扩缩的设置中使用。
  • 请勿添加磁盘。
只读磁盘
  • [默认] 添加处于只读模式的磁盘。
  • 请勿添加磁盘。
本地 SSD
  • [默认] 添加空白本地 SSD。使用模板创建新实例时,将创建未格式化的此磁盘。您必须先在启动脚本中格式化并装载该磁盘,然后才能在可扩缩的设置中使用。

对于每个磁盘,您还可以替换 auto-delete 特性 (Attribute),以指定在删除关联实例时是否应删除该磁盘。

默认情况下,如果未指定覆盖选项,则模板中的磁盘配置与来源实例一致。

根据现有模板创建实例模板

您无法更新现有实例模板。但是,如果实例模板过期或您需要做出更改,则可以使用控制台,创建另一个具有类似属性的实例模板。

  1. 转到实例模板页面。

    转到“实例模板”

  2. 点击您要复制和更新的实例模板。

  3. 点击创建类似模板

  4. 在新模板中更新配置。

  5. 点击创建

为 GPU 虚拟机创建实例模板

创建实例模板时,您可以通过指定以下内容来将其配置为创建挂接了 GPU 的虚拟机:

控制台

如需为 GPU 虚拟机创建实例模板,请执行以下操作:

  1. 在 Google Cloud 控制台中,转到实例模板页面。

    转到“实例模板”

  2. 点击创建实例模板

  3. 名称字段中,输入实例模板的名称。

  4. 位置部分,选择以下选项之一:

    • 如需创建全球实例模板,请选择全球(默认)。

    • 如需创建区域级实例模板,请选择区域,然后选择要在其中创建实例模板的区域。

  5. 机器配置部分中,执行以下操作:

    1. 点击 GPU 标签页。

    2. GPU 类型菜单中,选择 GPU 类型。

    3. GPU 数量菜单中,选择 GPU 的数量。

    4. 可选:如果您的 GPU 模型支持适用于图形工作负载的 NVIDIA RTX 虚拟工作站 (vWS),并且您计划运行图形密集型工作负载,请选择启用虚拟工作站 (NVIDIA GRID)

    5. 机器类型部分中,选择一种机器类型。

  6. 如需更改启动磁盘类型或映像的默认值,请在启动磁盘部分中点击更改。然后,按照提示更改启动磁盘。

  7. 点击创建

gcloud

如需为 GPU 虚拟机创建实例模板,请使用 instance-templates create 命令,并将 --maintenance-policy 标志设置为 TERMINATE

例如,如需为 GPU 虚拟机创建全局实例模板,请使用以下命令:

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --machine-type=MACHINE_TYPE \
    --maintenance-policy=TERMINATE

替换以下内容:

  • INSTANCE_TEMPLATE_NAME:实例模板的名称。

  • MACHINE_TYPE:虚拟机的机器类型。如果您指定 N1 机器类型,请添加 --accelerator 标志以指定要挂接到虚拟机的 GPU 数量和类型。

例如,假设您要为 GPU 虚拟机创建指定以下属性的全局实例模板:

  • 具有 2 个 vCPU 的 N1 预定义机器类型。

  • 一个要挂接到虚拟机的 NVIDIA T4 GPU。

  • Debian 作为映像项目。

  • Debian 10 作为映像系列。

如需创建示例实例模板,请使用以下命令:

gcloud compute instance-templates create instance-template-gpu \
    --accelerator=count=1,type=nvidia-tesla-t4 \
    --machine-type=n1-standard-2 \
    --image-family=debian-10 \
    --image-project=debian-cloud \
    --maintenance-policy=TERMINATE

Terraform

如需为 GPU 虚拟机创建实例模板,请使用 google_compute_region_instance_template 资源

例如,如需创建全局实例模板以指定配备 2 个 vCPU 和 1 个 NVIDIA T4 GPU 的 N1 预定义机器类型,请使用以下资源:

resource "google_compute_instance_template" "default" {
  name         = "gpu-template"
  machine_type = "n1-standard-2"

  disk {
    source_image = "debian-cloud/debian-11"
  }

  network_interface {
    network = "default"
  }

  guest_accelerator {
    type  = "nvidia-tesla-t4"
    count = 1
  }

  scheduling {
    on_host_maintenance = "TERMINATE"
  }
}

如需了解如何应用或移除 Terraform 配置,请参阅基本 Terraform 命令

REST

如需为 GPU 虚拟机创建实例模板,请向 instanceTemplates.insert 方法发出 POST 请求。在请求正文中,添加 onHostMaintenance 字段并将其设置为 TERMINATE

例如,如需为 GPU 虚拟机创建全局实例模板,请发出 POST 请求,如下所示:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/instanceTemplates

{
  "name": "INSTANCE_TEMPLATE_NAME",
  "properties": {
    "disks": [
      {
        "type": "PERSISTENT",
        "boot": true,
        "mode": "READ_WRITE",
        "initializeParams": {
          "sourceImage": "projects/IMAGE_PROJECT/global/images/IMAGE"
        }
      }
    ],
    "machineType": "MACHINE_TYPE",
    "networkInterfaces": [
      {
        "accessConfigs": [
          {
            "name": "external-IP",
            "type": "ONE_TO_ONE_NAT"
          }
        ],
        "network": "global/networks/default"
      }
    ],
    "scheduling": {
      "onHostMaintenance": "TERMINATE"
    }
  }
}

替换以下内容:

  • PROJECT_ID:您要在其中创建实例模板的项目的 ID。

  • INSTANCE_TEMPLATE_NAME:实例模板的名称。

  • IMAGE_PROJECT:映像所属的映像项目;例如 debian-cloud。如需详细了解支持的映像项目,请参阅公共映像

  • IMAGEIMAGE_FAMILY:指定以下其中一项:

    • IMAGE:操作系统映像的特定版本;例如 debian-10-buster-v20200309

    • IMAGE_FAMILY映像系列。此项指定最新的未弃用操作系统映像。例如,如果您指定 debian-10,则系统会使用 Debian 10 映像系列中的最新版本。如需详细了解如何使用映像系列,请参阅映像系列最佳实践

  • MACHINE_TYPE:虚拟机的机器类型。如果您指定 N1 机器类型,请添加 guestAccelerators 字段以指定要挂接到虚拟机的 GPU 数量和类型。

例如,假设您要为 GPU 虚拟机创建指定以下属性的全局实例模板:

  • 具有 2 个 vCPU 的 N1 预定义机器类型。

  • 一个要挂接到虚拟机的 NVIDIA T4 GPU。

  • Debian 作为映像项目。

  • Debian 10 作为映像系列。

要创建示例实例模板,请发出 POST 请求,如下所示:

POST https://compute.googleapis.com/compute/v1/projects/example-project/global/instanceTemplates

{
  "name": "instance-template-gpu",
  "properties": {
    "disks": [
      {
        "type": "PERSISTENT",
        "boot": true,
        "mode": "READ_WRITE",
        "initializeParams": {
          "sourceImage": "projects/debian-cloud/global/images/debian-10"
        }
      }
    ],
    "guestAccelerators": [
      {
        "acceleratorType": "nvidia-tesla-t4",
        "acceleratorCount": 1
      }
    ],
    "machineType": "n1-standard-2",
    "networkInterfaces": [
      {
        "accessConfigs": [
          {
            "name": "external-IP",
            "type": "ONE_TO_ONE_NAT"
          }
        ],
        "network": "global/networks/default"
      }
    ],
    "scheduling": {
      "onHostMaintenance": "TERMINATE"
    }
  }
}

如需了解创建实例模板时的更多配置选项,请参阅本文档中的创建实例模板

使用容器映像创建实例模板

您可以在实例模板中指定容器映像。默认情况下,Compute Engine 还会在模板中添加安装了 Docker 的 Container-Optimized OS 映像。当您使用模板创建新实例时,容器会在实例启动时自动启动。

控制台

  1. 转到实例模板页面。

    转到“实例模板”

  2. 点击创建实例模板

  3. 容器部分中,点击部署容器

  4. 配置容器对话框中,指定要使用的容器映像

    • 您可以指定 Container RegistryArtifact Registry 中的映像。例如:
      • gcr.io/cloud-marketplace/google/nginx1:TAG,其中 TAG 是为 Google Cloud Marketplace 上提供的特定 NGINX 容器映像版本定义的标记。
      • us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 用于选择 Artifact Registry 中存储的示例 hello-app 映像。
    • 如果您使用 Docker Hub 中的容器映像,请始终指定完整的 Docker 映像名称。例如,指定以下映像名称以部署一个 Apache 容器映像:docker.io/httpd:2.4
  5. (可选)点击高级容器选项。如需了解详情,请参阅配置选项以便运行容器

  6. 点击创建

gcloud

使用 gcloud compute instance-templates create-with-container 命令

gcloud compute instance-templates create-with-container INSTANCE_TEMPLATE_NAME \
     --container-image=CONTAINER_IMAGE

替换以下内容:

  • INSTANCE_TEMPLATE_NAME:要创建的模板的名称。
  • CONTAINER_IMAGE:要使用的容器映像的全名。

例如,以下命令会创建一个名为 nginx-vm 的新实例模板。当虚拟机启动时,使用此模板创建的虚拟机实例将启动并运行容器映像 gcr.io/cloud-marketplace/google/nginx1:TAG

gcloud compute instance-templates create-with-container nginx-vm \
     --container-image=gcr.io/cloud-marketplace/google/nginx1:TAG

TAG 替换为为 Google Cloud Marketplace 上提供的特定 NGINX 容器映像版本定义的标记。

此外,您还可以配置运行容器的选项

创建可指定子网的实例模板

gcloud

如需创建区域或全局实例模板,请使用 instance-templates create 命令。使用 --subnet 标志可将通过模板创建的实例置入您选择的子网中。--subnet 标志需要与 --region 标志搭配使用。

如果要创建区域实例模板,则必须使用 --instance-template-region 标志来设置模板的区域。确保使用与要创建区域实例模板相同的区域的子网。

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
  --region=REGION \
  --subnet=SUBNET_NAME_OR_URL \
  --instance-template-region=INSTANCE_TEMPLATE_REGION

替换以下内容:

  • INSTANCE_TEMPLATE_NAME:实例模板的名称
  • REGION:子网的区域
  • SUBNET_NAME_OR_URL:子网的名称或网址

  • INSTANCE_TEMPLATE_REGION:要在其中创建实例模板的区域。此值必须与 REGION 相同

以下示例会创建一个名为 template-qa 的模板,该模板仅在 subnet-us-qa 子网中创建实例。

gcloud compute instance-templates create template-qa \
  --region=us-central1 \
  --subnet=subnet-us-qa

Created [https://compute.googleapis.com/compute/latest/projects/PROJECT_ID/global/instanceTemplates/template-qa].
NAME        MACHINE_TYPE        PREEMPTIBLE CREATION_TIMESTAMP
template-qa e2-standard-2       2019-12-23T20:34:00.791-07:00

Go

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"
)

// createTemplateWithSubnet creates an instance template that uses a provided subnet.
func createTemplateWithSubnet(w io.Writer, projectID, network, subnetwork, templateName string) error {
	// projectID := "your_project_id"
	// network := "projects/project/global/networks/network"
	// subnetwork := "projects/project/regions/region/subnetworks/subnetwork"
	// templateName := "your_template_name"

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

	req := &computepb.InsertInstanceTemplateRequest{
		Project: projectID,
		InstanceTemplateResource: &computepb.InstanceTemplate{
			Name: proto.String(templateName),
			Properties: &computepb.InstanceProperties{
				// The template describes the size and source image of the boot disk
				// to attach to the instance.
				Disks: []*computepb.AttachedDisk{
					{
						InitializeParams: &computepb.AttachedDiskInitializeParams{
							DiskSizeGb:  proto.Int64(250),
							SourceImage: proto.String("projects/debian-cloud/global/images/family/debian-11"),
						},
						AutoDelete: proto.Bool(true),
						Boot:       proto.Bool(true),
					},
				},
				MachineType: proto.String("e2-standard-4"),
				// The template connects the instance to the specified network and subnetwork.
				NetworkInterfaces: []*computepb.NetworkInterface{
					{
						Network:    proto.String(network),
						Subnetwork: proto.String(subnetwork),
					},
				},
			},
		},
	}

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

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

	fmt.Fprintf(w, "Instance template 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.GlobalOperationsClient;
import com.google.cloud.compute.v1.InsertInstanceTemplateRequest;
import com.google.cloud.compute.v1.InstanceProperties;
import com.google.cloud.compute.v1.InstanceTemplate;
import com.google.cloud.compute.v1.InstanceTemplatesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateTemplateWithSubnet {

  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 use.
    network: the network to be used in the new template. This value uses
        the following format: "projects/{project}/global/networks/{network}"
    subnetwork: the subnetwork to be used in the new template. This value
        uses the following format: "projects/{project}/regions/{region}/subnetworks/{subnetwork}"
    templateName: name of the new template to create.
    */
    String projectId = "your-project-id";
    String network = String.format("projects/%s/global/networks/%s", projectId, "network");
    String subnetwork = String.format("projects/%s/regions/%s/subnetworks/%s", projectId, "region",
        "subnetwork");
    String templateName = "template-name";
    createTemplateWithSubnet(projectId, network, subnetwork, templateName);
  }

  // Create an instance template that uses a provided subnet.
  public static void createTemplateWithSubnet(String projectId, String network, String subnetwork,
      String templateName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    try (InstanceTemplatesClient instanceTemplatesClient = InstanceTemplatesClient.create();
        GlobalOperationsClient globalOperationsClient = GlobalOperationsClient.create()) {

      AttachedDisk disk = AttachedDisk.newBuilder()
          .setInitializeParams(AttachedDiskInitializeParams.newBuilder()
              .setSourceImage(
                  String.format("projects/%s/global/images/family/%s", "debian-cloud", "debian-11"))
              .setDiskSizeGb(250).build())
          .setAutoDelete(true)
          .setBoot(true)
          .build();

      InstanceProperties instanceProperties = InstanceProperties.newBuilder()
          .addDisks(disk)
          .setMachineType("e2-standard-4")
          .addNetworkInterfaces(NetworkInterface.newBuilder()
              .setNetwork(network)
              .setSubnetwork(subnetwork).build())
          .build();

      InstanceTemplate instanceTemplate = InstanceTemplate.newBuilder()
          .setName(templateName)
          .setProperties(instanceProperties)
          .build();

      InsertInstanceTemplateRequest insertInstanceTemplateRequest = InsertInstanceTemplateRequest
          .newBuilder()
          .setProject(projectId)
          .setInstanceTemplateResource(instanceTemplate)
          .build();

      Operation operation = instanceTemplatesClient.insertCallable()
          .futureCall(insertInstanceTemplateRequest).get(3, TimeUnit.MINUTES);

      Operation response = globalOperationsClient.wait(projectId, operation.getName());

      if (response.hasError()) {
        System.out.println("Template creation from subnet failed ! ! " + response);
        return;
      }
      System.out.printf("Template creation from subnet operation status %s: %s", templateName,
          response.getStatus());
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const network = 'projects/project/global/networks/network';
// const subnetwork = 'projects/project/regions/region/subnetworks/subnetwork';
// const templateName = 'your_template_name';

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

// Create an instance template that uses a provided subnet.
async function createTemplateWithSubnet() {
  const instanceTemplatesClient = new compute.InstanceTemplatesClient();

  const [response] = await instanceTemplatesClient.insert({
    project: projectId,
    instanceTemplateResource: {
      name: templateName,
      properties: {
        // The template describes the size and source image of the boot disk
        // to attach to the instance.
        disks: [
          {
            // The template describes the size and source image of the boot disk
            // to attach to the instance.
            initializeParams: {
              diskSizeGb: '250',
              sourceImage:
                'projects/debian-cloud/global/images/family/debian-11',
            },
            autoDelete: true,
            boot: true,
          },
        ],
        machineType: 'e2-standard-4',
        // The template connects the instance to the specified network and subnetwork.
        networkInterfaces: [
          {
            network,
            subnetwork,
          },
        ],
      },
    },
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.GlobalOperationsClient();

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

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

createTemplateWithSubnet();

Python

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 create_template_with_subnet(
    project_id: str, network: str, subnetwork: str, template_name: str
) -> compute_v1.InstanceTemplate:
    """
    Create an instance template that uses a provided subnet.

    Args:
        project_id: project ID or project number of the Cloud project you use.
        network: the network to be used in the new template. This value uses
            the following format: "projects/{project}/global/networks/{network}"
        subnetwork: the subnetwork to be used in the new template. This value
            uses the following format: "projects/{project}/regions/{region}/subnetworks/{subnetwork}"
        template_name: name of the new template to create.

    Returns:
        InstanceTemplate object that represents the new instance template.
    """
    # The template describes the size and source image of the book disk to
    # attach to the instance.
    disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = (
        "projects/debian-cloud/global/images/family/debian-11"
    )
    initialize_params.disk_size_gb = 250
    disk.initialize_params = initialize_params
    disk.auto_delete = True
    disk.boot = True

    template = compute_v1.InstanceTemplate()
    template.name = template_name
    template.properties = compute_v1.InstanceProperties()
    template.properties.disks = [disk]
    template.properties.machine_type = "e2-standard-4"

    # The template connects the instance to the specified network and subnetwork.
    network_interface = compute_v1.NetworkInterface()
    network_interface.network = network
    network_interface.subnetwork = subnetwork
    template.properties.network_interfaces = [network_interface]

    template_client = compute_v1.InstanceTemplatesClient()
    operation = template_client.insert(
        project=project_id, instance_template_resource=template
    )
    wait_for_extended_operation(operation, "instance template creation")

    return template_client.get(project=project_id, instance_template=template_name)

如果使用此模板为 MIG(无论是否启用自动扩缩功能)创建实例,则系统会自动在指定的区域和子网中创建实例。这样一来,您就可以控制为了进行负载均衡而创建的新实例的子网。

在实例模板中使用自定义或公共映像

您可以为实例模板使用自定义映像或公共映像:

  • 自定义映像由于 MIG 用于频繁地添加和移除实例,因此创建自定义映像并在实例模板中指定该映像会很有用。您可以在映像中做好准备,使其配备您的实例需要的应用和设置,这样您就不必在 MIG 中的各个虚拟机上手动配置这几项内容。

  • 公共映像。您可以创建一个实例模板,该模板使用公共映像启动脚本,可在实例开始运行后为其做好准备。

与使用启动脚本的虚拟机相比,自定义映像的确定性更高,且启动速度更快。但是,启动脚本更加灵活,可让您更轻松地更新实例中的应用和设置。

如果您要使用映像系列管理映像,则可以在实例模板中指定自定义或公共映像系列的名称。如需详细了解映像系列,请参阅在 Compute Engine 上使用映像系列时的最佳做法

后续步骤