使用自定义主机名创建虚拟机实例


创建虚拟机 (VM) 实例时,Google Cloud 会根据虚拟机名称创建内部 DNS 名称。除非您指定自定义主机名,否则 Google Cloud 会使用自动创建的内部 DNS 名称作为其提供给虚拟机的主机名。

您可以通过指定任何完全限定 DNS 名称来创建使用自定义主机名的虚拟机。自定义主机名有助于保持一致的命名惯例,或支持预期使用特定主机名的应用的要求。

即使您指定了自定义主机名,Google Cloud 也会创建 Compute Engine 内部 DNS 名称。您可以使用此自动创建的内部 DNS 记录连接到虚拟机。内部 DNS 记录解析为内部 DNS 名称,而不是自定义主机名。使用自定义主机名时,您仍然需要在适当的可用区中创建相应的 DNS 记录,例如使用 Cloud DNS。

准备工作

  • 设置身份验证(如果尚未设置)。身份验证是通过其进行身份验证以访问 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

所需的角色

如需获得创建具有自定义主机名的虚拟机所需的权限,请让您的管理员为您授予项目的 Compute Instance Admin (v1) (roles/compute.instanceAdmin.v1) IAM 角色。如需详细了解如何授予角色,请参阅管理访问权限

此预定义角色包含使用自定义主机名创建虚拟机所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

使用自定义主机名创建虚拟机需要以下权限:

  • 项目的 compute.instances.create 权限
  • 使用自定义映像创建虚拟机:针对映像的 compute.images.useReadOnly 权限
  • 使用快照创建虚拟机:针对快照的 compute.snapshots.useReadOnly 权限
  • 使用实例模板创建虚拟机:针对实例模板的 compute.instanceTemplates.useReadOnly 权限
  • 为虚拟机分配旧版网络:针对项目的 compute.networks.use 权限
  • 为虚拟机指定静态 IP 地址:针对项目的 compute.addresses.use 权限
  • 使用旧版网络时为虚拟机分配外部 IP 地址:针对项目的 compute.networks.useExternalIp 权限
  • 为虚拟机指定子网:针对项目或所选子网的 compute.subnetworks.use 权限
  • 在使用 VPC 网络时为虚拟机分配外部 IP 地址:针对项目或所选子网的 compute.subnetworks.useExternalIp 权限
  • 为虚拟机设置虚拟机实例元数据:针对项目的 compute.instances.setMetadata 权限
  • 为虚拟机设置标记:针对虚拟机的 compute.instances.setTags 权限
  • 为虚拟机设置标签:针对虚拟机的 compute.instances.setLabels 权限
  • 为虚拟机设置要使用的服务账号:针对虚拟机的 compute.instances.setServiceAccount 权限
  • 为虚拟机创建新磁盘:针对项目的 compute.disks.create 权限
  • 以只读或读写模式挂接现有磁盘:针对磁盘的 compute.disks.use 权限
  • 以只读模式挂接现有磁盘:针对磁盘的 compute.disks.useReadOnly 权限

您也可以使用自定义角色或其他预定义角色来获取这些权限。

限制

  • 您必须手动配置自定义主机名的 DNS 记录。Compute Engine 内部 DNS 提供的自动创建的记录不解析自定义主机名。您可以使用以下任一方法来托管自定义主机名的 DNS 记录:

  • 创建虚拟机后,就无法更改自定义主机名。

命名惯例

自定义主机名必须符合 RFC 1035 要求才能成为有效主机名。为了满足这些要求,自定义主机名必须符合以下格式规范:

  • 主机名至少包含两个标签,如下所示:
    • 每个标签包含仅包含以下字符的正则表达式:[a-z]([-a-z0-9]*[a-z0-9])?
    • 标签使用点串联。
    • 每个标签的长度为 1-63 个字符。
  • 主机名不超过 253 个字符。

无效:包含一个标签

my-host1234

有效:包含三个使用串联的标签

my-host1234.example.com

使用自定义主机名创建虚拟机

控制台

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

    转到“创建实例”

  2. 为您的虚拟机指定名称。如需了解详情,请参阅资源命名惯例

  3. 展开高级选项部分,然后执行以下操作:

    1. 展开网络部分。
    2. 主机名字段中,指定自定义主机名。
  4. 根据需要进行其他虚拟机自定义。

  5. 要创建并启动该虚拟机,请点击创建

下一步:配置 DNS 记录。如需了解详情,请参阅管理记录

gcloud

使用 Google Cloud CLI,按照从映像创建实例从快照创建实例的相同说明操作,添加 --hostname 标志,并使用 gcloud compute instances create 命令,如下所示:

gcloud compute instances create VM_NAME \
    --hostname=HOST_NAME

请替换以下内容:

  • VM_NAME:虚拟机的名称
  • HOST_NAME:要分配的完全限定网域主机名

例如,如需创建具有自定义主机名 test.example.com 的虚拟机 myinstance,请运行以下命令:

gcloud compute instances create myinstance \
    --hostname=test.example.com

下一步:配置 DNS 记录。如需了解详情,请参阅管理记录

Terraform

您可以借助 Terraform 资源hostname 参数来创建使用自定义主机名的实例。


resource "google_compute_instance" "custom_hostname_instance" {
  name         = "custom-hostname-instance-name"
  machine_type = "f1-micro"
  zone         = "us-central1-c"

  # Set a custom hostname below
  hostname = "hashicorptest.com"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }
  network_interface {
    # A default network is created for all GCP projects
    network = "default"
    access_config {
    }
  }
}
如需生成 Terraform 代码,您可以使用 Google Cloud 控制台中的等效代码组件。
  1. 在 Google Cloud 控制台中,转到虚拟机实例页面。

    转到“虚拟机实例”

  2. 点击创建实例
  3. 指定所需的参数。
  4. 在页面顶部或底部,点击等效代码,然后点击 Terraform 标签页以查看 Terraform 代码。

下一步:配置 DNS 记录。如需了解详情,请参阅管理记录

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

// createInstanceWithCustomHostname creates an instance with custom hostname.
func createInstanceWithCustomHostname(w io.Writer, projectID, zone, instanceName, hostname, machineType, sourceImage, networkName string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// hostname := "host.example.com" // Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
	// machineType := "n1-standard-1"
	// sourceImage := "projects/debian-cloud/global/images/family/debian-10"
	// networkName := "global/networks/default"

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

	req := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name: proto.String(instanceName),
			// Custom hostnames are not resolved by the automatically created records
			// provided by Compute Engine internal DNS.
			// You must manually configure the DNS record for your custom hostname.
			Hostname: proto.String(hostname),
			Disks: []*computepb.AttachedDisk{
				{
					// Describe the size and source image of the boot disk to attach to the instance.
					InitializeParams: &computepb.AttachedDiskInitializeParams{
						DiskSizeGb:  proto.Int64(10),
						SourceImage: proto.String(sourceImage),
					},
					AutoDelete: proto.Bool(true),
					Boot:       proto.Bool(true),
					Type:       proto.String(computepb.AttachedDisk_PERSISTENT.String()),
				},
			},
			MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/%s", zone, machineType)),
			NetworkInterfaces: []*computepb.NetworkInterface{
				{
					// Use the network interface provided in the networkName argument.
					Name: proto.String(networkName),
				},
			},
		},
	}

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

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

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

	return nil
}

Java


import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateInstanceWithCustomHostname {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // hostName: Custom hostname of the new VM instance.
    // *    Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
    String project = "your-project-id";
    String zone = "zone-name"; // eg: "us-central1-a"
    String instanceName = "instance-name";
    String hostName = "host.example.com";
    createInstanceWithCustomHostname(project, zone, instanceName, hostName);
  }

  // Creates an instance with custom hostname.
  public static void createInstanceWithCustomHostname(String projectId, String zone,
      String instanceName, String hostName)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    //  machineType - Machine type for the VM instance specified in the following format:
    //  *    "zones/{zone}/machineTypes/{type_name}". For example:
    //  *    "zones/europe-west3-c/machineTypes/f1-micro"
    //  *    You can find the list of available machine types by using this gcloud command:
    //  *    $ gcloud compute machine-types list
    //  sourceImage - Path of the disk image you want to use for your boot
    //  *    disk. This image can be one of the public images
    //  *    eg: "projects/...
    //  *    or a private image you have access to.
    //  *    You can check the list of available public images using:
    //  *    $ gcloud compute images list
    //  networkName - Name of the network you want the new instance to use.
    //  *    For example: global/networks/default - if you want to use the default network.
    String machineType = "n1-standard-1";
    String sourceImage = String.format("projects/%s/global/images/family/%s", "debian-cloud",
        "debian-11");
    String networkName = "global/networks/default";

    try (InstancesClient instancesClient = InstancesClient.create()) {
      System.out.printf("Creating the %s instance in %s with hostname %s...", instanceName, zone,
          hostName);

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

      // Use the network interface provided in the networkName argument.
      NetworkInterface networkInterface = NetworkInterface.newBuilder()
          .setName(networkName)
          .build();

      Instance instanceResource = Instance.newBuilder()
          // Custom hostnames are not resolved by the automatically created records
          // provided by Compute Engine internal DNS.
          // You must manually configure the DNS record for your custom hostname.
          .setName(instanceName)
          .setHostname(hostName)
          .addDisks(disk)
          .setMachineType(String.format("zones/%s/machineTypes/%s", zone, machineType))
          .addNetworkInterfaces(networkInterface).build();

      InsertInstanceRequest request = InsertInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstanceResource(instanceResource).build();

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

      if (response.hasError()) {
        System.out.printf("Instance creation failed for instance: %s ; Response: %s ! ! ",
            instanceName, response);
        return;
      }
      System.out.printf("Instance created : %s", instanceName);
      System.out.printf("Operation Status for instance %s is %s: ", instanceName,
          response.getStatus());
    }

  }

}

Node.js

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const zone = 'europe-central2-b'
// const instanceName = 'YOUR_INSTANCE_NAME'
// const hostname = 'host.example.com'
// const machineType = 'n1-standard-1';
// const sourceImage = 'projects/debian-cloud/global/images/family/debian-10';
// const networkName = 'global/networks/default';

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

// Create a new instance with the values provided above in the specified project and zone.
async function createInstanceWithCustomHostname() {
  const instancesClient = new compute.InstancesClient();

  console.log(
    `Creating the ${instanceName} instance in ${zone} with hostname ${hostname}...`
  );

  const [response] = await instancesClient.insert({
    instanceResource: {
      name: instanceName,
      // Custom hostnames are not resolved by the automatically created records
      // provided by Compute Engine internal DNS.
      // You must manually configure the DNS record for your custom hostname.
      hostname,
      disks: [
        {
          // Describe the size and source image of the boot disk to attach to the instance.
          initializeParams: {
            diskSizeGb: '10',
            sourceImage,
          },
          autoDelete: true,
          boot: true,
          type: 'PERSISTENT',
        },
      ],
      machineType: `zones/${zone}/machineTypes/${machineType}`,
      networkInterfaces: [
        {
          // Use the network interface provided in the networkName argument.
          name: networkName,
        },
      ],
    },
    project: projectId,
    zone,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

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

createInstanceWithCustomHostname();

Python

from __future__ import annotations

import re
import sys
from typing import Any
import warnings

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

def get_image_from_family(project: str, family: str) -> compute_v1.Image:
    """
    Retrieve the newest image that is part of a given family in a project.

    Args:
        project: project ID or project number of the Cloud project you want to get image from.
        family: name of the image family you want to get image from.

    Returns:
        An Image object.
    """
    image_client = compute_v1.ImagesClient()
    # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details
    newest_image = image_client.get_from_family(project=project, family=family)
    return newest_image

def disk_from_image(
    disk_type: str,
    disk_size_gb: int,
    boot: bool,
    source_image: str,
    auto_delete: bool = True,
) -> compute_v1.AttachedDisk:
    """
    Create an AttachedDisk object to be used in VM instance creation. Uses an image as the
    source for the new disk.

    Args:
         disk_type: the type of disk you want to create. This value uses the following format:
            "zones/{zone}/diskTypes/(pd-standard|pd-ssd|pd-balanced|pd-extreme)".
            For example: "zones/us-west3-b/diskTypes/pd-ssd"
        disk_size_gb: size of the new disk in gigabytes
        boot: boolean flag indicating whether this disk should be used as a boot disk of an instance
        source_image: source image to use when creating this disk. You must have read access to this disk. This can be one
            of the publicly available images or an image from one of your projects.
            This value uses the following format: "projects/{project_name}/global/images/{image_name}"
        auto_delete: boolean flag indicating whether this disk should be deleted with the VM that uses it

    Returns:
        AttachedDisk object configured to be created using the specified image.
    """
    boot_disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = source_image
    initialize_params.disk_size_gb = disk_size_gb
    initialize_params.disk_type = disk_type
    boot_disk.initialize_params = initialize_params
    # Remember to set auto_delete to True if you want the disk to be deleted when you delete
    # your VM instance.
    boot_disk.auto_delete = auto_delete
    boot_disk.boot = boot
    return boot_disk

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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result

def create_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    disks: list[compute_v1.AttachedDisk],
    machine_type: str = "n1-standard-1",
    network_link: str = "global/networks/default",
    subnetwork_link: str = None,
    internal_ip: str = None,
    external_access: bool = False,
    external_ipv4: str = None,
    accelerators: list[compute_v1.AcceleratorConfig] = None,
    preemptible: bool = False,
    spot: bool = False,
    instance_termination_action: str = "STOP",
    custom_hostname: str = None,
    delete_protection: bool = False,
) -> compute_v1.Instance:
    """
    Send an instance creation request to the Compute Engine API and wait for it to complete.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone to create the instance in. For example: "us-west3-b"
        instance_name: name of the new virtual machine (VM) instance.
        disks: a list of compute_v1.AttachedDisk objects describing the disks
            you want to attach to your new instance.
        machine_type: machine type of the VM being created. This value uses the
            following format: "zones/{zone}/machineTypes/{type_name}".
            For example: "zones/europe-west3-c/machineTypes/f1-micro"
        network_link: name of the network you want the new instance to use.
            For example: "global/networks/default" represents the network
            named "default", which is created automatically for each project.
        subnetwork_link: name of the subnetwork you want the new instance to use.
            This value uses the following format:
            "regions/{region}/subnetworks/{subnetwork_name}"
        internal_ip: internal IP address you want to assign to the new instance.
            By default, a free address from the pool of available internal IP addresses of
            used subnet will be used.
        external_access: boolean flag indicating if the instance should have an external IPv4
            address assigned.
        external_ipv4: external IPv4 address to be assigned to this instance. If you specify
            an external IP address, it must live in the same region as the zone of the instance.
            This setting requires `external_access` to be set to True to work.
        accelerators: a list of AcceleratorConfig objects describing the accelerators that will
            be attached to the new instance.
        preemptible: boolean value indicating if the new instance should be preemptible
            or not. Preemptible VMs have been deprecated and you should now use Spot VMs.
        spot: boolean value indicating if the new instance should be a Spot VM or not.
        instance_termination_action: What action should be taken once a Spot VM is terminated.
            Possible values: "STOP", "DELETE"
        custom_hostname: Custom hostname of the new VM instance.
            Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
        delete_protection: boolean value indicating if the new virtual machine should be
            protected against deletion or not.
    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()

    # Use the network interface provided in the network_link argument.
    network_interface = compute_v1.NetworkInterface()
    network_interface.network = network_link
    if subnetwork_link:
        network_interface.subnetwork = subnetwork_link

    if internal_ip:
        network_interface.network_i_p = internal_ip

    if external_access:
        access = compute_v1.AccessConfig()
        access.type_ = compute_v1.AccessConfig.Type.ONE_TO_ONE_NAT.name
        access.name = "External NAT"
        access.network_tier = access.NetworkTier.PREMIUM.name
        if external_ipv4:
            access.nat_i_p = external_ipv4
        network_interface.access_configs = [access]

    # Collect information into the Instance object.
    instance = compute_v1.Instance()
    instance.network_interfaces = [network_interface]
    instance.name = instance_name
    instance.disks = disks
    if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type):
        instance.machine_type = machine_type
    else:
        instance.machine_type = f"zones/{zone}/machineTypes/{machine_type}"

    instance.scheduling = compute_v1.Scheduling()
    if accelerators:
        instance.guest_accelerators = accelerators
        instance.scheduling.on_host_maintenance = (
            compute_v1.Scheduling.OnHostMaintenance.TERMINATE.name
        )

    if preemptible:
        # Set the preemptible setting
        warnings.warn(
            "Preemptible VMs are being replaced by Spot VMs.", DeprecationWarning
        )
        instance.scheduling = compute_v1.Scheduling()
        instance.scheduling.preemptible = True

    if spot:
        # Set the Spot VM setting
        instance.scheduling.provisioning_model = (
            compute_v1.Scheduling.ProvisioningModel.SPOT.name
        )
        instance.scheduling.instance_termination_action = instance_termination_action

    if custom_hostname is not None:
        # Set the custom hostname for the instance
        instance.hostname = custom_hostname

    if delete_protection:
        # Set the delete protection bit
        instance.deletion_protection = True

    # Prepare the request to insert an instance.
    request = compute_v1.InsertInstanceRequest()
    request.zone = zone
    request.project = project_id
    request.instance_resource = instance

    # Wait for the create operation to complete.
    print(f"Creating the {instance_name} instance in {zone}...")

    operation = instance_client.insert(request=request)

    wait_for_extended_operation(operation, "instance creation")

    print(f"Instance {instance_name} created.")
    return instance_client.get(project=project_id, zone=zone, instance=instance_name)

def create_instance_custom_hostname(
    project_id: str, zone: str, instance_name: str, hostname: str
) -> compute_v1.Instance:
    """
    Create a new VM instance with Debian 10 operating system and a custom hostname.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone to create the instance in. For example: "us-west3-b"
        instance_name: name of the new virtual machine (VM) instance.
        hostname: the hostname you want to use for the new instance.

    Returns:
        Instance object.
    """
    newest_debian = get_image_from_family(project="debian-cloud", family="debian-11")
    disk_type = f"zones/{zone}/diskTypes/pd-standard"
    disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)]
    instance = create_instance(
        project_id, zone, instance_name, disks, custom_hostname=hostname
    )
    return instance

REST

按照 API 说明通过映像快照创建实例,并在请求正文中指定 hostname 字段。

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

{
 "name": "VM_NAME",
 "hostname": "HOST_NAME",
 ...
}

请替换以下内容:

  • PROJECT_ID:您的项目 ID
  • ZONE:要在其中创建虚拟机的可用区
  • VM_NAME:虚拟机的名称
  • HOST_NAME:要分配的完全限定网域主机名

验证自定义主机名

对于 Linux 虚拟机,您可以通过在虚拟机上运行 hostname -f 命令来验证主机名。

您还可以使用 Google Cloud Console 或 Google Cloud CLI 验证自定义主机名。

控制台

  1. 如需查看虚拟机的自定义主机名,请转到虚拟机实例页面。

    转到虚拟机实例

  2. 点击实例名称打开虚拟机实例详情页面。

  3. 查看主机名部分。仅当已设置自定义主机名时,才会显示主机名字段。

    显示主机名的虚拟机实例页面。

gcloud

如需使用 gcloud compute 查看虚拟机的自定义主机名,请使用带 --format 标志的 instances describe 子命令过滤输出。将 VM_NAME 替换为虚拟机的名称。

gcloud compute instances describe VM_NAME \
    --format='get(hostname)'

例如,如需查看名为 myinstance 的虚拟机的自定义主机名,请运行以下命令。

gcloud compute instances describe myinstance \
    --format='get(hostname)'

输出结果可能类似于以下内容:

test.example.com

如果未设置自定义主机名,则此命令的输出为空。

后续步骤