创建实例模板

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

您可以使用实例模板在代管式实例组 (MIG) 中创建实例,或创建单个虚拟机

准备工作

限制

  • gcloud CLI 和 API 支持实例模板中位于 nic0 以外的接口的共享 VPC,但控制台不支持。
  • 您无法更新现有实例模板,也无法在创建实例模板后对其进行更改。如果实例模板过期,或者您需要更改配置,请创建一个新的实例模板。

新建实例模板

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

通过 Google Cloud ConsoleGoogle Cloud CLIAPI、Terraform 或 Cloud 客户端库创建实例模板。

控制台

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

    转到“实例模板”

  2. 点击创建实例模板

  3. 为以下字段输入值,或接受默认值。默认值会根据您所选的机器系列而变化。

    • 机器类型
    • 映像
    • 启动磁盘
    • VPC 网络
    • IP 地址
  4. 可选:如果您选择了支持安全强化型虚拟机的映像,请更改虚拟机的安全强化型虚拟机设置:

    1. 管理、安全、磁盘、网络、单独租用下,点击安全标签页。
    2. 如果您要停用安全启动,请清除开启安全启动复选框。安全启动功能可帮助保护您的虚拟机实例免受启动级和内核级恶意软件和 rootkit 的攻击。如需了解详情,请参阅安全启动
    3. 如果您要停用虚拟可信平台模块 (vTPM),请清除开启 vTPM 复选框。vTPM 将启用测量启动,该功能可验证虚拟机预启动和启动完整性。如需了解详情,请参阅虚拟可信平台模块 (vTPM)

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

  5. 可选:在管理、安全、磁盘、网络、单独租用下,点击相应标签页以进一步自定义模板。例如,您最多可以添加 15 个辅助非启动磁盘。

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

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

gcloud

gcloud compute 中,使用 instance-templates create 命令创建实例模板。

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME

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 属性。

gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
    --create-disk= \
        {--image=DISK_IMAGE | --image-family=DISK_IMAGE_FAMILY}, \
        image-project=DISK_IMAGE_PROJECT, \
        size=SIZE_GB

请替换以下内容:

  • INSTANCE_TEMPLATE_NAME:新模板的名称

  • DISK_IMAGEDISK_IMAGE_FAMILY:指定以下其中一项:
    • DISK_IMAGE:您要用作非启动磁盘的映像的名称
    • DISK_IMAGE_FAMILY:要用作非启动磁盘的映像系列

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

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

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

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

  • SIZE_GB:辅助磁盘的大小

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

  • --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

API

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

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

PROJECT_ID 替换为项目 ID。

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

{
  "name": "INSTANCE_TEMPLATE_NAME"
  "properties": {
    "machineType": "zones/ZONE/machineTypes/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"
        }
      }
    ]
  }
}

请替换以下内容:

  • 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 上使用映像系列时的最佳做法

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

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

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

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

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

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

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

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

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

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

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

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

Terraform

您可以使用 Terraform 资源创建实例模板。

以下 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"

    # secret default
    access_config {
      network_tier = "PREMIUM"
    }
  }

  # secret default
  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",
    ]
  }
}

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: %v", 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: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", 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)
              .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)
              .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

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:
    """
    This method will wait 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)

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

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

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

gcloud

使用带有 --source-instance--source-instance-zone 标志的 gcloud instance-templates create 命令

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 是包含来源实例的地区。
  • 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

API

调用 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"
      }
    ]
  }
}

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: %v", 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: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", 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

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:
    """
    This method will wait 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)

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

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

    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. 点击创建

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

您可以在实例模板中指定容器映像。默认情况下,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

使用 --subnet 标志可将通过模板创建的实例置入您选择的子网中。--subnet 标志需要与 --region 标志搭配使用。

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

请替换以下内容:

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

以下示例会创建一个名为 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: %v", 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: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", 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

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:
    """
    This method will wait 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 上使用映像系列时的最佳做法

后续步骤