静的外部 IP アドレスを構成する


仮想マシン(VM)インスタンスに静的外部 IP アドレスを割り当てることができます。VM の静的 IP アドレスの変更、一覧取得、解放を行うこともできます。外部 IP アドレスには、静的なものとエフェメラルなものがあります。

変更されない固定外部 IP アドレスが VM に必要な場合は、次の操作を行います。

  1. 静的外部 IP アドレスを取得します。新しい外部 IP アドレスを予約することも、既存のエフェメラル外部 IP アドレスを昇格させることもできます。
  2. 予約した IP アドレスを既存の VM に割り当てるか、新しい VM の作成時に割り当てます。

内部 Compute Engine ネットワーク上の静的 IP アドレスが必要な場合は、静的内部 IP アドレスの予約をご覧ください。

静的外部 IP アドレスの予約またはグローバル外部 IP アドレスの作成については、静的外部 IP アドレスを予約するをご覧ください。

始める前に

  • IP アドレスの詳細をご覧ください。
  • 静的外部 IP アドレスの割り当てと上限をご覧ください。
  • 外部 IP アドレス料金をご覧ください。
  • まだ設定していない場合は、認証を設定します。認証とは、Google Cloud のサービスと API にアクセスするために ID を確認するプロセスです。ローカル開発環境からコードまたはサンプルを実行するには、次のいずれかのオプションを選択して Compute Engine に対する認証を行います。

    Select the tab for how you plan to use the samples on this page:

    Console

    When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.

    gcloud

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

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

      ローカル開発環境でこのページの Terraform サンプルを使用するには、gcloud CLI をインストールして初期化し、ユーザー認証情報を使用してアプリケーションのデフォルト認証情報を設定します。

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

        gcloud init
      3. If you're using a local shell, then create local authentication credentials for your user account:

        gcloud auth application-default login

        You don't need to do this if you're using Cloud Shell.

      詳細については Set up authentication for a local development environment をご覧ください。

      REST

      このページの REST API サンプルをローカル開発環境で使用するには、gcloud CLI に指定した認証情報を使用します。

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

        gcloud init

      詳細については、Google Cloud 認証ドキュメントの REST を使用して認証するをご覧ください。

必要なロール

静的 IP アドレスの構成と管理に必要な権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

これらの事前定義ロールには、静的 IP アドレスの構成と管理に必要な権限が含まれています。必要とされる正確な権限については、「必要な権限」セクションを開いてご確認ください。

必要な権限

静的 IP アドレスの構成と管理には、次の権限が必要です。

  • VM インスタンスに対する compute.instances.update
  • VM インスタンスに対する compute.instances.updateNetworkInterface
  • VM インスタンスに対する compute.instances.addAccessConfig
  • VM インスタンスに対する compute.instances.deleteAccessConfig
  • ネットワークに対する compute.networks.list
  • サブネットに対する compute.subnetworks.use
  • サブネットに対する compute.subnetworks.list
  • VM を作成する:
    • プロジェクトに対する compute.instances.create
    • カスタム イメージを使用して VM を作成する: イメージに対する compute.images.useReadOnly
    • スナップショットを使用して VM を作成する: スナップショットに対する compute.snapshots.useReadOnly
    • インスタンス テンプレートを使用して VM を作成する: インスタンス テンプレートに対する compute.instanceTemplates.useReadOnly
    • レガシー ネットワークを VM に割り当てる: プロジェクトに対する compute.networks.use
    • VM の静的 IP アドレスを指定する: プロジェクトに対する compute.addresses.use
    • レガシー ネットワークの使用時に VM に外部 IP アドレスを割り当てる: プロジェクトに対する compute.networks.useExternalIp
    • VM のサブネットを指定する: プロジェクトまたは選択したサブネットに対する compute.subnetworks.use
    • VPC ネットワークの使用時に VM に外部 IP アドレスを割り当てる: プロジェクトまたは選択したサブネットに対する compute.subnetworks.useExternalIp
    • VM の VM インスタンス メタデータを設定する: プロジェクトに対する compute.instances.setMetadata
    • VM にタグを設定する: VM に対する compute.instances.setTags
    • VM にラベルを設定する: VM に対する compute.instances.setLabels
    • VM が使用するサービス アカウントを設定する: VM に対する compute.instances.setServiceAccount
    • VM に新しいディスクを作成する: プロジェクトに対する compute.disks.create
    • 既存のディスクを読み取り専用モードまたは読み取り / 書き込みモードでアタッチする: ディスクに対する compute.disks.use
    • 既存のディスクを読み取り専用モードでアタッチする: ディスクに対する compute.disks.useReadOnly

カスタムロールや他の事前定義ロールを使用して、これらの権限を取得することもできます。

制限事項

  • 一度に複数のリソースが同じ静的外部 IP アドレスを使用することはできません。

  • IP アドレスをリソースに割り当てた後に、その IP アドレスが静的であるかエフェメラルであるかを確認する方法はありません。IP アドレスと、そのプロジェクトに予約されている静的外部 IP アドレスのリストを比較することは可能です。プロジェクトで使用可能な静的外部 IP アドレスのリストを表示するには、gcloud compute addresses list サブコマンドを使用します。

  • 各 VM は複数のネットワーク インターフェースを持つことができ、各インターフェースには次の IP アドレスを割り振ることができます。

    • 内部 IPv4 アドレス(必須)
    • 外部 IPv4 アドレス
    • /96 IPv6 アドレス範囲(内部または外部のどちらか一方)
  • 静的 IP アドレスの名前は変更できません。

  • 割り当てられた外部 IP アドレスは、VM と同じ物理ホストに存在し、すべての用途(ルーティング、レイテンシ、料金設定など)の VM と同じリージョンに存在します。これは、インターネットの位置情報に関する検索情報に関係なく当てはまります。

注: ネットワーク インターフェースは複数の転送ルールからトラフィックを受信できますが、ルールの中には他の外部 IP アドレスを対象とするものもあります。これらの転送ルールによって任意の数の外部 IP アドレスがネットワーク インターフェースを参照できますが、各ネットワーク インターフェースには、外部 IPv4 アドレスを 1 つと、外部の /96 IPv6 アドレス範囲を 1 つだけ割り振ることができます。

ロード バランシングと転送ルールの詳細については、ロード バランシングのドキュメントをご覧ください。

使用可能な静的外部 IP アドレスを表示する

プロジェクト用に予約した静的外部 IP アドレスのリストを取得するには、次の操作を行います。

コンソール

  1. Google Cloud コンソールで、[IP アドレス] ページに移動します。

    [IP アドレス] に移動

  2. [外部 IP アドレス] をクリックします。

gcloud

gcloud compute addresses list コマンドを実行します。

  • すべての IP アドレスのリストを取得するには、次のコマンドを使用します。

    gcloud compute addresses list
  • すべてのグローバル IP アドレスを一覧取得するには、次のコマンドを使用します。

    gcloud compute addresses list --global
  • 特定のリージョンのすべてのリージョン IP アドレスのリストを取得するには、次のコマンドを使用します。

    gcloud compute addresses list \
        --regions=REGION
    

    REGION は、アドレスのリストを取得するリージョンに置き換えます。カンマ区切りでリージョン名を指定すると、複数のリージョンのアドレスのリストを取得できます。

    gcloud compute addresses list \
        --regions=REGION1,REGION2,..REGION_n_
    

API

  • リージョン IPv4 アドレスまたはリージョン IPv6 アドレスを一覧表示するには、addresses.list メソッドを呼び出します。

    GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION/addresses
    

    次のように置き換えます。

    • PROJECT_ID: このリクエストのプロジェクト ID
    • REGION: このリクエストのリージョン名
  • すべてのリージョンのアドレスのリストを取得するには、addresses.aggregatedList メソッドを呼び出します。

    GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/aggregated/addresses
    
  • グローバル IPv4 アドレスまたはグローバル IPv6 アドレスを一覧表示するには、globalAddresses.list メソッドを呼び出します。

    GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/addresses
    

    次のように置き換えます。

    PROJECT_ID: このリクエストのプロジェクト ID

Go

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	"google.golang.org/api/iterator"

	"cloud.google.com/go/compute/apiv1/computepb"
)

// listRegionalExternal retrieves list external IP addresses in Google Cloud Platform region.
func listRegionalExternal(w io.Writer, projectID, region string) ([]*computepb.Address, error) {
	// projectID := "your_project_id"
	// region := "europe-west3"

	ctx := context.Background()
	// Create the service client.
	addressesClient, err := compute.NewAddressesRESTClient(ctx)
	if err != nil {
		return nil, err
	}
	defer addressesClient.Close()

	// Build the request.
	req := &computepb.ListAddressesRequest{
		Project: projectID,
		Region:  region,
	}

	// List the addresses.
	it := addressesClient.List(ctx, req)

	// Iterate over the results.
	var addresses []*computepb.Address
	for {
		address, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		addresses = append(addresses, address)
	}

	// Print the addresses.
	fmt.Fprint(w, "Fetched addresses: \n")
	for _, address := range addresses {
		fmt.Fprintf(w, "%s\n", *address.Name)
	}

	return addresses, nil
}

// listGlobalExternal retrieves list external global IP addresses in Google Cloud Platform.
func listGlobalExternal(w io.Writer, projectID string) ([]*computepb.Address, error) {
	// projectID := "your_project_id"

	ctx := context.Background()
	// Create the service client.
	addressesClient, err := compute.NewGlobalAddressesRESTClient(ctx)
	if err != nil {
		return nil, err
	}
	defer addressesClient.Close()

	// Build the request.
	req := &computepb.ListGlobalAddressesRequest{
		Project: projectID,
	}

	// List the addresses.
	it := addressesClient.List(ctx, req)

	// Iterate over the results.
	var addresses []*computepb.Address
	for {
		address, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		addresses = append(addresses, address)
	}

	// Print the addresses.
	fmt.Fprint(w, "Fetched addresses: \n")
	for _, address := range addresses {
		fmt.Fprintf(w, "%s\n", *address.Name)
	}

	return addresses, nil
}

Java


import com.google.cloud.compute.v1.Address;
import com.google.cloud.compute.v1.AddressesClient;
import com.google.cloud.compute.v1.GlobalAddressesClient;
import com.google.cloud.compute.v1.ListAddressesRequest;
import com.google.cloud.compute.v1.ListGlobalAddressesRequest;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

public class ListStaticExternalIp {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Region where the VM and IP is located.
    String region = "your-region-id";

    listStaticExternalIp(projectId, region);
  }

  // Lists all static external IP addresses, either regional or global.
  public static List<Address> listStaticExternalIp(String projectId, String region)
          throws IOException {
    // Use regional client if a region is specified
    if (region != null) {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      try (AddressesClient client = AddressesClient.create()) {
        ListAddressesRequest request = ListAddressesRequest.newBuilder()
                .setProject(projectId)
                .setRegion(region)
                .build();

        return Lists.newArrayList(client.list(request).iterateAll());
      }
    } else {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      try (GlobalAddressesClient client = GlobalAddressesClient.create()) {
        ListGlobalAddressesRequest request = ListGlobalAddressesRequest.newBuilder()
                .setProject(projectId)
                .build();

        return Lists.newArrayList(client.list(request).iterateAll());
      }
    }
  }
}

Python

from typing import List, Optional

from google.cloud.compute_v1.services.addresses.client import AddressesClient
from google.cloud.compute_v1.services.global_addresses import GlobalAddressesClient
from google.cloud.compute_v1.types import Address


def list_static_ip_addresses(
    project_id: str, region: Optional[str] = None
) -> List[Address]:
    """
    Lists all static external IP addresses, either regional or global.

    Args:
    project_id (str): project ID.
    region (Optional[str]): The region of the IP addresses if regional. None if global.

    Returns:
    List[Address]: A list of Address objects containing details about the requested IPs.
    """
    if region:
        # Use regional client if a region is specified
        client = AddressesClient()
        addresses_iterator = client.list(project=project_id, region=region)
    else:
        # Use global client if no region is specified
        client = GlobalAddressesClient()
        addresses_iterator = client.list(project=project_id)

    return list(addresses_iterator)  # Convert the iterator to a list to return

静的外部 IP アドレスを構成する

以降のセクションでは、VM の静的外部 IP アドレスを構成する方法について説明します。

静的外部 IP アドレスを使用する VM を作成する

静的外部 IP アドレスを予約したら、VM に割り当てることができます。

コンソール

  1. Google Cloud コンソールで、[インスタンスの作成] ページに移動します。

    [インスタンスの作成] に移動

  2. VM の詳細を指定します。

  3. [詳細オプション] セクションを開きます。

  4. [ネットワーキング] セクションを開きます。

  5. [ネットワーク インターフェース] セクションで、ネットワーク インターフェースを開いて編集します。

  6. IPv4 アドレスを割り当てるには、次の手順を行います。

    1. ネットワークを選択してください。
    2. [外部 IPv4 アドレス] リストから IP アドレスを選択します。
  7. IPv6 アドレスを割り当てるには、次の手順を行います。

    1. IPv6 サブネットを含むネットワークを選択します。
    2. [サブネットワーク] リストからデュアルスタック サブネットを選択します。
    3. [IP スタックタイプ] には、[IPv4 と IPv6(デュアルスタック)] を選択します。
    4. [外部 IPv6 アドレス] リストから、新しく予約した外部 IPv6 アドレスを選択します。または、[IP アドレスを作成] を選択して、新しい静的外部 IPv6 アドレスを予約します。
    5. [ネットワーク サービス ティア] で [プレミアム] を選択します。
  8. ネットワーク インターフェースの変更を終了するには、[完了] をクリックします。

  9. VM 作成プロセスを続行します。

gcloud

VM を作成し、すでに予約した静的リージョン外部 IP アドレスを割り当てることができます。

  • 静的外部 IPv4 アドレスを割り当てるには、次の手順を行います。

    gcloud compute instances create VM_NAME --address=IP_ADDRESS
    

    次のように置き換えます。

    • VM_NAME: VM の名前。
    • IP_ADDRESS: VM に割り当てる IP アドレス。アドレス名ではなく、予約済みの静的外部 IP アドレスを使用してください。
  • 静的外部 IPv6 アドレスを割り当てるには、次の手順を行います。

    gcloud compute instances create VM_NAME \
        --subnet=SUBNET \
        --stack-type=IPV4_IPV6 \
        --external-ipv6-address=IPV6_ADDRESS \
        --external-ipv6-prefix-length=96 \
        --ipv6-network-tier=PREMIUM \
        --zone=ZONE
    

Terraform

google_compute_instance リソースを使用して外部 IP アドレスを割り当てることができます。

resource "google_compute_instance" "default" {
  name         = "dns-proxy-nfs"
  machine_type = "n1-standard-1"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "ubuntu-1404-trusty-v20160627"
    }
  }

  network_interface {
    network = "default"
    access_config {
      nat_ip = google_compute_address.default.address
    }
  }
}

REST

新しい VM に静的外部 IPv4 アドレスを割り当てるには、次の手順を行います。

新しい VM を作成するリクエストで、networkInterfaces[].accessConfigs[].natIP プロパティと使用する外部 IPv4 アドレスを明示的に指定します。例:

{
  "name": "VM_NAME",
  "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
  "networkInterfaces": [{
    "accessConfigs": [{
      "type": "ONE_TO_ONE_NAT",
      "name": "External NAT",
      "natIP": "IPV4_ADDRESS"
     }],
    "network": "global/networks/default"
  }],
  "disks": [{
      "autoDelete": "true",
      "boot": "true",
      "type": "PERSISTENT",
      "initializeParams": {
          "sourceImage": "SOURCE_IMAGE"
      }
}]
}

新しい VM に静的外部 IPv6 アドレスを割り当てるには、次の手順を行います。

新しい VM を作成するリクエストで、networkInterfaces[].ipv6AccessConfigs[].externalIpv6 プロパティと使用する外部 IPv6 アドレスを明示的に指定します。例:

{
  "name": "VM_NAME",
  "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
  "networkInterfaces": [{
          "accessConfigs": [{
              "name": "external-nat",
              "type": "ONE_TO_ONE_NAT"
          }],
          "ipv6AccessConfigs": [{
        "externalIpv6": "IOV6_ADDRESS",
        "externalIpv6PrefixLength": 96,
        "name": "external-ipv6-access-config",
        "networkTier": "PREMIUM",
        "type": "DIRECT_IPV6"
          }],
      "stackType": "IPV4_IPV6",
      "subnetwork":"SUBNETWORK
  }],
  "disks": [{
    "autoDelete": "true",
    "boot": "true",
    "mode": "READ_WRITE",
    "type": "PERSISTENT",
    "initializeParams": {
        "sourceImage": "SOURCE_IMAGE"
    },
  }],
 }

Go


// assignStaticExternalToNewVM creates a new VM instance and assigns a static external IP address to it.
// NOTE: ip address is expected to exist and be located in the same region as new VM
func assignStaticExternalToNewVM(w io.Writer, projectID, zone, instanceName, ipAddress string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// ipAddress := 301.222.11.123

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

	imagesClient, err := compute.NewImagesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewImagesRESTClient: %w", err)
	}
	defer imagesClient.Close()

	// List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details.
	newestDebianReq := &computepb.GetFromFamilyImageRequest{
		Project: "debian-cloud",
		Family:  "debian-12",
	}
	newestDebian, err := imagesClient.GetFromFamily(ctx, newestDebianReq)
	if err != nil {
		return fmt.Errorf("unable to get image from family: %w", err)
	}

	req := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name: proto.String(instanceName),
			Disks: []*computepb.AttachedDisk{
				{
					InitializeParams: &computepb.AttachedDiskInitializeParams{
						DiskSizeGb:  proto.Int64(10),
						SourceImage: newestDebian.SelfLink,
						DiskType:    proto.String(fmt.Sprintf("zones/%s/diskTypes/pd-standard", zone)),
					},
					AutoDelete: proto.Bool(true),
					Boot:       proto.Bool(true),
					Type:       proto.String(computepb.AttachedDisk_PERSISTENT.String()),
				},
			},
			MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/n1-standard-1", zone)),
			NetworkInterfaces: []*computepb.NetworkInterface{
				{
					AccessConfigs: []*computepb.AccessConfig{
						{
							Type:        proto.String(computepb.AccessConfig_ONE_TO_ONE_NAT.String()),
							Name:        proto.String("External NAT"),
							NetworkTier: proto.String(computepb.AccessConfig_PREMIUM.String()),
							NatIP:       proto.String(ipAddress),
						},
					},
				},
			},
		},
	}

	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, "Static address %s assigned to new VM", ipAddress)

	return nil
}

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Address.NetworkTier;
import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.GetInstanceRequest;
import com.google.cloud.compute.v1.ImagesClient;
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 java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AssignStaticExternalNewVmAddress {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Instance ID of the Google Cloud project you want to use.
    String instanceId = "your-instance-id";
    // Name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "your-zone-id";
    // machine type of the VM being created. This value uses the
    // following format: "zones/{zone}/machineTypes/{type_name}".
    // For example: "zones/europe-west3-c/machineTypes/f1-micro"
    String machineType = String.format("zones/%s/machineTypes/{your-machineType-id}", zone);
    // boolean flag indicating if the instance should have an external IPv4 address assigned.
    boolean externalAccess = true;
    // 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.
    String externalIpv4 = "your-externalIpv4-id";

    assignStaticExternalNewVmAddress(projectId, instanceId, zone,
            externalAccess, machineType, externalIpv4);
  }

  // Create a new VM instance with assigned static external IP address.
  public static Instance assignStaticExternalNewVmAddress(String projectId, String instanceName,
                                                          String zone, boolean externalAccess,
                                                          String machineType, String externalIpv4)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    String sourceImage;
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (ImagesClient imagesClient = ImagesClient.create()) {
      sourceImage = imagesClient.getFromFamily("debian-cloud", "debian-11").getSelfLink();
    }
    AttachedDisk attachedDisk = buildAttachedDisk(sourceImage, zone);

    return createInstance(projectId, instanceName, zone,
            attachedDisk, machineType, externalAccess, externalIpv4);
  }

  private static AttachedDisk buildAttachedDisk(String sourceImage, String zone) {
    AttachedDiskInitializeParams initializeParams = AttachedDiskInitializeParams.newBuilder()
            .setSourceImage(sourceImage)
            .setDiskSizeGb(10)
            .setDiskType(String.format("zones/%s/diskTypes/pd-standard", zone))
            .build();

    return AttachedDisk.newBuilder()
            .setInitializeParams(initializeParams)
            // Remember to set auto_delete to True if you want the disk to be deleted
            // when you delete your VM instance.
            .setAutoDelete(true)
            .setBoot(true)
            .build();
  }

  // Send an instance creation request to the Compute Engine API and wait for it to complete.
  private static Instance createInstance(String projectId, String instanceName,
                                         String zone, AttachedDisk disks,
                                         String machineType, boolean externalAccess,
                                         String externalIpv4)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (InstancesClient client = InstancesClient.create()) {
      Instance instanceResource =
              buildInstanceResource(instanceName, disks, machineType, externalAccess, externalIpv4);

      InsertInstanceRequest build = InsertInstanceRequest.newBuilder()
              .setProject(projectId)
              .setRequestId(UUID.randomUUID().toString())
              .setZone(zone)
              .setInstanceResource(instanceResource)
              .build();
      client.insertCallable().futureCall(build).get(60, TimeUnit.SECONDS);

      GetInstanceRequest getInstanceRequest = GetInstanceRequest.newBuilder()
              .setInstance(instanceName)
              .setProject(projectId)
              .setZone(zone)
              .build();

      return client.get(getInstanceRequest);
    }
  }

  private static Instance buildInstanceResource(String instanceName, AttachedDisk disk,
                                                String machineType, boolean externalAccess,
                                                String externalIpv4) {
    NetworkInterface networkInterface =
            networkInterface(externalAccess, externalIpv4);

    return Instance.newBuilder()
            .setName(instanceName)
            .addDisks(disk)
            .setMachineType(machineType)
            .addNetworkInterfaces(networkInterface)
            .build();
  }

  private static NetworkInterface networkInterface(boolean externalAccess, String externalIpv4) {
    NetworkInterface.Builder build = NetworkInterface.newBuilder()
            .setNetwork("global/networks/default");
    if (externalAccess) {
      AccessConfig.Builder accessConfig = AccessConfig.newBuilder()
              .setType(Type.ONE_TO_ONE_NAT.name())
              .setName("External NAT")
              .setNetworkTier(NetworkTier.PREMIUM.name());
      if (externalIpv4 != null) {
        accessConfig.setNatIP(externalIpv4);
      }
      build.addAccessConfigs(accessConfig.build());
    }

    return build.build();
  }
}

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 assign_static_external_ip_to_new_vm(
    project_id: str, zone: str, instance_name: str, ip_address: str
) -> compute_v1.Instance:
    """
    Create a new VM instance with assigned static external IP address.

    Args:
        project_id (str): project ID or project number of the Cloud project you want to use.
        zone (str): name of the zone to create the instance in. For example: "us-west3-b"
        instance_name (str): name of the new virtual machine (VM) instance.
        ip_address(str): external address to be assigned to this instance. It must live in the same
        region as the zone of the instance and be precreated before function called.

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

既存の VM に対して外部 IP アドレスの変更または割り当てを行う

既存の VM に対して、エフェメラルまたは静的外部 IP アドレスの変更または割り当てを行うことができます。

VM は複数のインターフェースを持つことができ、各インターフェースは外部 IP アドレスを持つことができます。VM にすでに外部 IP アドレスがある場合は、まずそのアドレスを削除する必要があります。その後、既存の VM に新しい外部 IP アドレスを割り当てることができます。

コンソール

  1. Google Cloud コンソールで [VM インスタンス] ページに移動します。

    [VM インスタンス] に移動

  2. 外部 IP を割り当てる VM の名前をクリックします。[インスタンスの詳細] ページが表示されます。
  3. [インスタンスの詳細] ページで、次の手順を実行します。

    1. [編集] をクリックします。
    2. [ネットワーク インターフェース] を開きます。
    3. VM に割り当てることを必要とする外部 IP アドレスを選択します。
      1. [外部 IPv4 アドレス] に、[エフェメラル] または静的外部 IPv4 アドレスを選択します。
      2. [外部 IPv6 アドレス] に、[エフェメラル] または静的外部 IPv6 アドレスを選択します。
    4. [完了] をクリックします。
  4. [保存] をクリックします。

gcloud

  1. (省略可)静的外部 IP アドレスを予約します。

    静的外部 IP アドレスを割り当てる場合は、アドレスを予約し、そのアドレスが別のリソースで使用されていないことを確認する必要があります。必要であれば、手順に沿って新しい静的外部 IP アドレスを予約するか、静的外部 IP アドレスの割り当てを解除します。

    エフェメラル外部 IP アドレスを使用する場合は、この手順をスキップします。エフェメラル外部 IP アドレスは Compute Engine によってランダムに割り当てられます。

  2. 静的外部 IP アドレスの割り当てを解除するで説明されているように、既存の IP アドレス割り当てを削除します。

  3. 新しい外部 IP アドレスを割り当てます。

    • IPv4 アドレスを割り当てるには、instances add-access-config サブコマンドを使用します。

      注: IP_ADDRESS を静的 IP の名前に置き換えないでください。実際の IP アドレスを使用する必要があります。
      gcloud compute instances add-access-config VM_NAME \
        --access-config-name="ACCESS_CONFIG_NAME" --address=IP_ADDRESS
      

      次のように置き換えます。

      • VM_NAME: VM の名前。
      • ACCESS_CONFIG_NAME: このアクセス構成ファイルの名前。引用符の中に完全な名前を指定してください。
      • IP_ADDRESS: 追加する IP アドレス。

      Compute Engine で静的外部 IP アドレスを使用せずにエフェメラル外部 IP アドレスを割り当てる場合は、--address IP_ADDRESS プロパティを省略します。

      gcloud compute instances add-access-config VM_NAME \
        --access-config-name="ACCESS_CONFIG_NAME"
      
    • IPv6 アドレス範囲を割り当てるには、instance network-interfaces update サブコマンドを使用します。

      gcloud compute instances network-interfaces update VM_NAME \
        --network-interface=NIC \
        --ipv6-network-tier=PREMIUM \
        --stack-type=IPV4_IPV6 \
        --external-ipv6-address=IPV6_ADDRESS \
        --external-ipv6-prefix-length=96 \
        --zone=ZONE
      

      次のように置き換えます。

      • VM_NAME: VM の名前。
      • NIC: ネットワーク インターフェースの名前。
      • IPV6_ADDRESS: VM に割り当てる IPv6 アドレス。/96 範囲に存在する最初の IPv6 アドレスを指定します。
      • ZONE: VM のゾーン。

REST

VM の外部 IPv4 アドレスまたは外部 IPv6 アドレスを変更するには、その VM に新しいアクセス構成を追加します。

  1. 静的外部 IP アドレスの割り当てを解除するで説明されているように、既存の IP アドレス割り当てを削除します。

  2. 既存のアクセス構成を削除するには、instances.deleteAccessConfig メソッドPOST リクエストを行います。

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME/deleteAccessConfig
    
  3. instances.addAccessConfig メソッドPOST リクエストを発行し、VM インスタンスのネットワーク インターフェースに新しいアクセス構成を追加します。

Go

import (
	"context"
	"fmt"
	"io"

	"google.golang.org/protobuf/proto"

	compute "cloud.google.com/go/compute/apiv1"
	"cloud.google.com/go/compute/apiv1/computepb"
)

// assignStaticAddressToExistingVM assigns a static external IP address to an existing VM instance.
// Note: VM and assigned IP must be in the same region.
func assignStaticAddressToExistingVM(w io.Writer, projectID, zone, instanceName, IPAddress, networkInterfaceName string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// IPAddress := "34.111.222.333"
	// networkInterfaceName := "nic0"

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

	reqGet := &computepb.GetInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
	}

	instance, err := instancesClient.Get(ctx, reqGet)
	if err != nil {
		return fmt.Errorf("could not get instance: %w", err)
	}

	var networkInterface *computepb.NetworkInterface
	for _, ni := range instance.NetworkInterfaces {
		if *ni.Name == networkInterfaceName {
			networkInterface = ni
			break
		}
	}

	if networkInterface == nil {
		return fmt.Errorf("No network interface named '%s' found on instance %s", networkInterfaceName, instanceName)
	}

	var accessConfig *computepb.AccessConfig
	for _, ac := range networkInterface.AccessConfigs {
		if *ac.Type == computepb.AccessConfig_ONE_TO_ONE_NAT.String() {
			accessConfig = ac
			break
		}
	}

	if accessConfig != nil {
		// network interface is immutable - deletion stage is required in case of any assigned ip (static or ephemeral).
		reqDelete := &computepb.DeleteAccessConfigInstanceRequest{
			Project:          projectID,
			Zone:             zone,
			Instance:         instanceName,
			AccessConfig:     *accessConfig.Name,
			NetworkInterface: networkInterfaceName,
		}

		opDelete, err := instancesClient.DeleteAccessConfig(ctx, reqDelete)
		if err != nil {
			return fmt.Errorf("unable to delete access config: %w", err)
		}

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

	reqAdd := &computepb.AddAccessConfigInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
		AccessConfigResource: &computepb.AccessConfig{
			NatIP: &IPAddress,
			Type:  proto.String(computepb.AccessConfig_ONE_TO_ONE_NAT.String()),
		},
		NetworkInterface: networkInterfaceName,
	}

	opAdd, err := instancesClient.AddAccessConfig(ctx, reqAdd)
	if err != nil {
		return fmt.Errorf("unable to add access config: %w", err)
	}

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

	fmt.Fprintf(w, "Static address %s assigned to the instance %s\n", IPAddress, instanceName)

	return nil
}

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AssignStaticExistingVm {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Instance ID of the Google Cloud project you want to use.
    String instanceId = "your-instance-id";
    // Name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "your-zone-id";
    // Name of the network interface to assign.
    String netInterfaceName = "your-netInterfaceName-id";

    assignStaticExistingVmAddress(projectId, instanceId, zone, netInterfaceName);
  }

  // Updates or creates an access configuration for a VM instance to assign a static external IP.
  // As network interface is immutable - deletion stage is required
  // in case of any assigned ip (static or ephemeral).
  // VM and ip address must be created before calling this function.
  // IMPORTANT: VM and assigned IP must be in the same region.
  public static Instance assignStaticExistingVmAddress(String projectId, String instanceId,
                                                       String zone, String netInterfaceName)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (InstancesClient client = InstancesClient.create()) {
      Instance instance = client.get(projectId, zone, instanceId);

      NetworkInterface networkInterface = null;
      for (NetworkInterface netInterface : instance.getNetworkInterfacesList()) {
        if (netInterface.getName().equals(netInterfaceName)) {
          networkInterface = netInterface;
          break;
        }
      }

      if (networkInterface == null) {
        throw new IllegalArgumentException(
                String.format(
                        "No '{network_interface_name}' variable found on instance %s.",
                        instanceId)
        );
      }
      AccessConfig accessConfig = null;
      for (AccessConfig config : networkInterface.getAccessConfigsList()) {
        if (config.getType().equals(Type.ONE_TO_ONE_NAT.name())) {
          accessConfig = config;
          break;
        }
      }

      if (accessConfig != null) {
        // Delete the existing access configuration first
        client.deleteAccessConfigAsync(projectId, zone, instanceId,
                        accessConfig.getName(), netInterfaceName)
                .get(30, TimeUnit.SECONDS);
      }

      // Add a new access configuration with the new IP
      AccessConfig newAccessConfig = AccessConfig.newBuilder()
              // Leave this field undefined to use an IP from a shared ephemeral IP address pool
              // .setNatIP(ipAddress)
              .setType(Type.ONE_TO_ONE_NAT.name())
              .setName("external-nat")
              .build();

      client.addAccessConfigAsync(projectId, zone, instanceId, netInterfaceName, newAccessConfig)
              .get(30, TimeUnit.SECONDS);

      // return updated instance
      return client.get(projectId, zone, instanceId);
    }
  }
}

Python

import uuid

from google.cloud.compute_v1 import InstancesClient
from google.cloud.compute_v1.types import AccessConfig
from google.cloud.compute_v1.types import AddAccessConfigInstanceRequest
from google.cloud.compute_v1.types import DeleteAccessConfigInstanceRequest


def assign_static_ip_to_existing_vm(
    project_id: str,
    zone: str,
    instance_name: str,
    ip_address: str,
    network_interface_name: str = "nic0",
):
    """
    Updates or creates an access configuration for a VM instance to assign a static external IP.
    As network interface is immutable - deletion stage is required in case of any assigned ip (static or ephemeral).
    VM and ip address must be created before calling this function.
    IMPORTANT: VM and assigned IP must be in the same region.

    Args:
        project_id (str): Project ID.
        zone (str): Zone where the VM is located.
        instance_name (str): Name of the VM instance.
        ip_address (str): New static external IP address to assign to the VM.
        network_interface_name (str): Name of the network interface to assign.

    Returns:
        google.cloud.compute_v1.types.Instance: Updated instance object.
    """
    client = InstancesClient()
    instance = client.get(project=project_id, zone=zone, instance=instance_name)
    network_interface = next(
        (ni for ni in instance.network_interfaces if ni.name == network_interface_name),
        None,
    )

    if network_interface is None:
        raise ValueError(
            f"No network interface named '{network_interface_name}' found on instance {instance_name}."
        )

    access_config = next(
        (ac for ac in network_interface.access_configs if ac.type_ == "ONE_TO_ONE_NAT"),
        None,
    )

    if access_config:
        # Delete the existing access configuration first
        delete_request = DeleteAccessConfigInstanceRequest(
            project=project_id,
            zone=zone,
            instance=instance_name,
            access_config=access_config.name,
            network_interface=network_interface_name,
            request_id=str(uuid.uuid4()),
        )
        delete_operation = client.delete_access_config(delete_request)
        delete_operation.result()

    # Add a new access configuration with the new IP
    add_request = AddAccessConfigInstanceRequest(
        project=project_id,
        zone=zone,
        instance=instance_name,
        network_interface="nic0",
        access_config_resource=AccessConfig(
            nat_i_p=ip_address, type_="ONE_TO_ONE_NAT", name="external-nat"
        ),
        request_id=str(uuid.uuid4()),
    )
    add_operation = client.add_access_config(add_request)
    add_operation.result()

    updated_instance = client.get(project=project_id, zone=zone, instance=instance_name)
    return updated_instance

外部 IP アドレスを特定の VM に制限する

特定のワークロードでは、セキュリティやネットワークに関する制限など、基本的な要件が必要になることがあります。たとえば、特定の VM のみが外部 IP アドレスを使用できるように、外部 IP アドレスを制限できます。このオプションは、データの引き出しの防止や、ネットワーク分離の維持に役立ちます。組織ポリシーを使用すると、外部 IP アドレスを特定の VM に制限し、組織内またはプロジェクト内の VM に対する外部 IP アドレスの使用を制御できます。

VM の外部 IP アドレスを制御するための制約は次のとおりです。

constraints/compute.vmExternalIpAccess

制約を使用するには、外部 IP アドレスを持つことができる VM が allowedList に設定されたポリシーを指定します。ポリシーを指定しない場合は、すべての VM ですべての外部 IP アドレスが許可されます。ポリシーを指定すると、allowedValues リストに含まれる VM にのみ、エフェメラルまたは静的な外部 IP アドレスを割り当てることができます。ポリシーで明示的に定義されていない組織内またはプロジェクト内の他の Compute Engine VM では、外部 IP アドレスの使用が禁止されています。

許可リストと拒否リストでは、次のような VM の URI を使用して VM を指定します。

projects/PROJECT_ID/zones/ZONE/instances/VM_NAME

外部 IP アドレスを制限するための仕様

  • このリスト型制約は VM にのみ適用できます。
  • 過去にさかのぼって制約を適用することはできません。ポリシーを有効にする前から外部 IP アドレスを持つすべての VM は、外部 IP アドレスを保持します。
  • この制約には、allowedList または deniedList のいずれか一方を指定できます。両方を同一のポリシーに指定することはできません。
  • VM のライフサイクルと完全性の管理と維持は、必要な権限を持つユーザーまたは管理者の責任です。制約によって VM の URI のみが検証され、許可リスト内の VM の変更、削除、再作成を回避することはできません。

外部 IP アドレスの制限に必要な権限

制約をプロジェクトまたは組織レベルで設定するには、組織での orgpolicy.policyAdmin ロールが付与されている必要があります。

組織レベルでポリシー制約を設定する

コンソール

  1. [組織のポリシー] ページに移動します。

    [組織のポリシー] に移動

  2. 必要に応じて、組織をプロジェクト プルダウン メニューから選択します。
  3. [VM インスタンスに対して許可されている外部 IP を定義する] をクリックします。
  4. [編集] をクリックして外部 IP ポリシーを編集します。[編集] ツールにアクセスできない場合は、正しい権限を付与されていません。
  5. [カスタマイズ] を選択し、特定の VM に組織のポリシーを設定します。

    組織のポリシーの編集ページのカスタマイズ オプション。

  6. 必要な [ポリシーの適用] と [ポリシーの種類] を選択します。

  7. [ポリシーの値] で [カスタム] を選択します。

  8. VM の URI を入力し、Enter キーを押します。URI は、次の形式にする必要があります。

    projects/PROJECT_ID/zones/ZONE/instances/VM_NAME
    
  9. [新しいポリシーの値] をクリックし、必要に応じて VM の URI を入力します。

  10. [保存] をクリックして、制約を適用します。

gcloud

外部 IP アクセスの制約を設定するには、組織 ID が必要です。組織 ID を確認するには、organizations list コマンドを実行して、そのレスポンスで数値 ID を探します。

gcloud organizations list

gcloud CLI は、組織のリストを次の形式で返します。

DISPLAY_NAME               ID
example-organization1      29252605212
example-organization2      1234567890

gcloud resource-manager org-policies set-policy コマンドを使用してポリシーを設定します。JSON ファイルでポリシーを指定する必要があります。次の形式の JSON ファイルを作成します。

{
"constraint": "constraints/compute.vmExternalIpAccess",
"listPolicy": {
  "allowedValues": [
     "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME",
     "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME",
     "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME"
  ]
 }
}

次のように置き換えます。

  • PROJECT_ID。このリクエストのプロジェクト ID(example-project など)。これは、組織のポリシーを設定するときとは異なります。組織のポリシーの場合は組織の数値 ID が必要です。
  • ZONE: VM のゾーン
  • VM_NAME: VM の名前

または、外部 IP アドレスの取得を明示的に禁止する VM を示す deniedValues リストを指定できます。このリストに含まれない VM は、外部 IP アドレスを持つことが暗黙的に許可されます。allowedValues または deniedValues のどちらか一方だけ指定できます。

次に、リクエストでこのファイルを渡します。

gcloud resource-manager org-policies set-policy MY_POLICY.JSON --organization=ORGANIZATION_ID

ORGANIZATION_ID は、組織の数値 ID に置き換えます。

外部 IP アクセスを必要としない VM の場合は、allValuesDENY に設定したポリシーを設定できます。

{
  "constraint": "constraints/compute.vmExternalIpAccess",
  "listPolicy": {
    "allValues": "DENY"
  }
}

REST

setOrgPolicy() API を使用して制約を定義します。allowedValue リストに指定した VM は、外部 IP アドレスを持つことが許可されます。また、外部 IP アドレスの取得を明示的に禁止する VM を示す deniedValues リストを指定できます。このリストに含まれない VM は、外部 IP アドレスを持つことが暗黙的に許可されます。allowedValues または deniedValues のどちらか一方だけ指定できます。

たとえば、以下に示すのは、組織内の特定のプロジェクトの VM が外部 IP アドレスを持つことができるように、compute.vmExternalIpAccess 制約を組織に適用するリクエストです。

POST https://cloudresourcemanager.googleapis.com/v1/organizations/ORGANIZATION_ID:setOrgPolicy

ORGANIZATION_ID は組織の数値 ID です。

次に、リクエスト本文で、この制約のポリシーを指定します。

{
  "policy": {
    "constraint": "constraints/compute.vmExternalIpAccess",
    "listPolicy": {
      "allowedValues": [
        "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME",
        "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME",
        "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME"
        ]
      }
    }
 }

外部 IP アクセスを必要としない VM の場合は、allValuesDENY に設定したポリシーを設定できます。

{
  "policy": {
    "constraint": "constraints/compute.vmExternalIpAccess",
    "listPolicy": {
      "allValues": "DENY"
      }
    }
 }

プロジェクト レベルでのポリシーの設定

プロジェクト レベルでポリシーを設定すると、そのポリシーは組織レベルのポリシーよりも優先されます。たとえば、組織レベルでは allowedValues リストに example-vm-1 があり、プロジェクト レベルのポリシーで同じ VM が deniedValues リストにある場合、VM に外部 IP アドレスを割り当てることはできません。

コンソール

組織レベルでのポリシー制約の設定と同じ手順を行いますが、組織ではなくプロジェクト セレクタでプロジェクトを選択してください。

プロジェクト セレクタ。

gcloud

gcloud resource-manager org-policies set-policy コマンドを使用してポリシーを設定します。JSON ファイルでポリシーを指定する必要があります。次の形式の JSON ファイルを作成します。

{
 "constraint": "constraints/compute.vmExternalIpAccess",
 "listPolicy": {
  "allowedValues": [
   "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME"
  ]
 }
}

次のように置き換えます。

  • PROJECT_ID。このリクエストのプロジェクト ID(example-project など)。これは、組織のポリシーを設定するときとは異なります。組織のポリシーの場合は組織の数値 ID が必要です。
  • ZONE: VM のゾーン。
  • VM_NAME: VM の名前。

また、外部 IP アドレスの取得を明示的に禁止する VM の deniedValues リストを指定できます。このリストに含まれない VM は、外部 IP アドレスを持つことが暗黙的に許可されます。allowedValues または deniedValues のどちらか一方だけ指定できます。

次に、リクエストでこのファイルを渡します。

gcloud resource-manager org-policies set-policy MY_POLICY.JSON --project=example-project

REST

setOrgPolicy API を使用して制約を定義します。allowedValue リストに指定した VM は、外部 IP アドレスを持つことが許可されます。また、外部 IP アドレスの取得を明示的に禁止する VM を示す deniedValues リストを指定できます。このリストに含まれない VM は、外部 IP アドレスを持つことが暗黙的に許可されます。allowedValues または deniedValues のどちらか一方だけ指定できます。

次の例は、特定の VM が外部 IP アドレスを持つことを許可するように compute.vmExternalIpAccess 制約をプロジェクトに設定するリクエストです。

POST https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:setOrgPolicy

PROJECT_ID は、このリクエストのプロジェクト ID で置き換えます。

リクエストの本文にはこの制約のポリシーを格納します。

{
  "policy": {
    "constraint": "constraints/compute.vmExternalIpAccess",
    "listPolicy": {
      "allowedValues": [
        "projects/PROJECT_ID/zones/ZONE/instances/VM_NAME"
      ]
    }
  }
}

外部 IP アドレスの制限に関するベスト プラクティス

  • この制約では deniedValues リストを使用しないでください。deniedValues リストで値を定義した場合は、deniedValues リストにある VM のみが外部 IP アドレスの使用を制限されます。外部 IP アドレスの使用が許可される VM を正確に制御したい場合、これはセキュリティ上の問題になる可能性があります。特定の VM を allowedValues リストから削除する場合は、deniedValues リストに VM を配置するのではなく、allowedList から VM を削除するように既存のポリシーを更新します。

  • リソース階層の大部分にポリシーを設定し、特定のプロジェクトを除外する場合は、setOrgPolicy メソッドを使用してデフォルトのポリシーを復元します。restoreDefault オブジェクトを指定して、そのプロジェクト内のすべての VM に外部 IP アドレスとの関連付けを許可します。プロジェクトの現在のポリシーは、デフォルト設定の影響を受けません。

  • この組織のポリシーと IAM のロールを組み合わせて使用することにより、環境をより適切に管理できます。このポリシーは VM にのみ適用されますが、ネットワーク デバイスの外部 IP アドレスをより適切に制御して制限するには、compute.networkAdmin ロールを適切な関係者に付与します。

  • ポリシーが有効になっている組織またはプロジェクト内の Compute Engine 上で実行されるすべてのサービスとプロダクトは、この組織ポリシーの影響を受けます。特に、Google Kubernetes Engine、Dataflow、Dataproc、Cloud SQL などのサービスは、このポリシーの影響を受けます。これによって問題が生じた場合は、組織のポリシーが適用されない別のプロジェクト内に別のサービスまたはプロダクトをセットアップし、必要に応じて共有 VPC を使用することをおすすめします。

静的外部 IP アドレスを管理する

以降のセクションでは、VM の静的外部 IP アドレスを管理する方法について説明します。

内部 IP アドレスがエフェメラルか静的かを判別する

静的内部 IP アドレスとエフェメラル内部 IP アドレスは、ほとんどのコンテキストで同じように動作します。ただし、静的内部 IP アドレスを使用すると、リソースを削除して再作成した場合でも、同じリソースには同じ IP アドレスを使用できます。通常、特定のリソースを停止または削除すると、エフェメラル IP アドレスが 1 つ解放されます。

アドレスが静的かエフェメラルかを判別するには、次のようにします。

  1. Google Cloud コンソールで、[IP アドレス] ページに移動します。

    [IP アドレス] に移動

  2. リストからアドレスを探し、[タイプ] 列で IP アドレスのタイプを確認します。

静的外部 IP アドレスの割り当てを解除する

IP アドレスの割り当てを解除すると、その IP アドレスはリソースから削除されますが、予約されたままになります。IP アドレスの割り当てを解除したら、その IP アドレスを別のリソースに再割り当てできます。

VM を削除して、IPv4 アドレスまたは IPv6 アドレスの割り当てを解除することもできます。

コンソール

  1. Google Cloud コンソールで、[IP アドレス] ページに移動します。

    [IP アドレス] に移動

  2. [外部 IP アドレス] をクリックします。

  3. 割り当てを解除する静的 IP アドレスを選択します。

  4. [アクションを表示] をクリックし、[別のリソースに再割り当て] オプションを選択します。

  5. [接続先] プルダウン リストから [なし] を選択します。

  6. [OK] をクリックします。

gcloud

  1. gcloud compute addresses list コマンドを使用して、静的 IP アドレスが使用されているかどうかを確認します。

    gcloud compute addresses list
    

    出力は次のようになります。

    NAME                      REGION    ADDRESS                  STATUS
    example-address-ipv4      REGION    198.51.100.1             RESERVED
    example-address-new-ipv4  REGION    203.0.113.1              IN_USE
    example-address-ipv6      REGION    2001:db8:1:1:1:1:1:1     RESERVED
    example-address-new-ipv6  REGION    2001:db8:4:4:4:4:4:4     IN_USE
    
    • IP アドレスが使用されていない場合、ステータスは RESERVED です。
    • IP アドレスが使用中の場合、ステータスは IN_USE です。
  2. IP アドレスを使用している VM の名前を取得します。

    gcloud compute addresses describe ADDRESS_NAME \
      --region=REGION
    

    次のように置き換えます。

    • ADDRESS_NAME: IPv6 アドレス リソースの名前。
    • REGION: IPv6 アドレス リソースのリージョン。

    出力は次のようになります。

    address: IP_ADDRESS
    addressType: EXTERNAL
    ...
    region: https://www.googleapis.com/compute/v1/projects/PROJECT/regions/REGION
    selfLink: https://www.googleapis.com/compute/v1/projects/PROJECT/regions/REGION/addresses/ADDRESS_NAME
    status: IN_USE
    subnetwork: https://www.googleapis.com/compute/v1/projects/PROJECT/regions/REGION/subnetworks/SUBNET
    users:
    - https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/VM_NAME
    

    users フィールドに、IP アドレスを使用している VM の名前が表示されます。

  3. VM から IP アドレスの割り当てを解除します。

    • IPv4 アドレスの割り当てを解除するには、VM のアクセス構成ファイルを削除します。

      1. 削除するアクセス構成の名前を取得します。名前を取得するには、gcloud compute instances describe コマンドを使用します。VM_NAME は VM の名前に置き換えます。

        gcloud compute instances describe VM_NAME
        

        アクセス構成は次の形式で表示されます。

        networkInterfaces:
          - accessConfigs:
            - kind: compute#accessConfig
              name: external-nat
              natIP: 203.0.113.1
              type: ONE_TO_ONE_NAT
        
      2. gcloud compute instances delete-access-config コマンドを使用して、アクセス構成を削除します。

        gcloud compute instances delete-access-config VM_NAME \
          --access-config-name="ACCESS_CONFIG_NAME"
        

        次のように置き換えます。

        • VM_NAME: VM の名前。
        • ACCESS_CONFIG_NAME: 削除するアクセス構成ファイルの名前。引用符の中に完全な名前を指定してください。
    • IPv6 アドレス範囲の割り当てを解除するには、instance network-interfaces update コマンドを使用します。

      gcloud compute instances network-interfaces update VM_NAME \
        --network-interface=nic0 \
        --stack-type=IPV4_ONLY \
        --zone=ZONE
      

      次のように置き換えます。

      • VM_NAME: IP アドレスを使用している VM の名前。
      • ZONE: VM のゾーン。
  4. 静的外部 IP アドレスのステータスが IN_USE から RESERVED に変わり、使用可能になったことを確認します。

    gcloud compute addresses list \
      --filter="ADDRESS_NAME AND region=REGION"
    

    次のように置き換えます。

    • ADDRESS_NAME: IP アドレス リソースの名前。
    • REGION: IP アドレス リソースのリージョン。

これで静的外部 IP アドレスが使用可能になったため、別の VM に割り当てることができます。

REST

静的外部 IPv4 アドレスまたは静的外部 IPv6 アドレスの割り当てを解除するには、次の手順を行います。

  • IPv4 アドレスの場合、そのアドレスを使用している VM に接続されたアクセス構成を削除します。

    1. VM のアクセス構成の詳細を確認するには、instances.get メソッドGET リクエストを発行します。

      GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME
      
    2. 既存のアクセス構成を削除するには、instances.deleteAccessConfig メソッドPOST リクエストを行います。

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

      次のように置き換えます。

      • PROJECT_ID: このリクエストのプロジェクト ID
      • ZONE: VM を配置するゾーン
      • VM_NAME: VM の名前
  • IPv6 アドレスの場合は、IPv6 アドレスが割り当てられている VM のネットワーク インターフェースのスタックタイプを更新します。

    1. instances.updateNetworkInterface メソッドPATCH リクエストを送信します。

    2. リクエストの本文で、stackType フィールドの値を IPV4_ONLY に更新します。

      例:

      PATCH https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME/updateNetworkInterface
      
      {
        "networkInterfaces": [{
          ...
          "stackType" : "IPV4_ONLY"
          ...
          }]
      }
      

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class UnassignStaticIpAddress {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Instance ID of the Google Cloud project you want to use.
    String instanceId = "your-instance-id";
    // Name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "your-zone";
    // Name of the network interface to assign.
    String netInterfaceName = "your-netInterfaceName";

    unassignStaticIpAddress(projectId, instanceId, zone, netInterfaceName);
  }

  public static Instance unassignStaticIpAddress(String projectId, String instanceId,
                                                 String zone, String netInterfaceName)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (InstancesClient client = InstancesClient.create()) {
      Instance instance = client.get(projectId, zone, instanceId);
      NetworkInterface networkInterface = null;
      for (NetworkInterface netIterface : instance.getNetworkInterfacesList()) {
        if (netIterface.getName().equals(netInterfaceName)) {
          networkInterface = netIterface;
          break;
        }
      }

      if (networkInterface == null) {
        throw new IllegalArgumentException(
                String.format(
                        "No '{network_interface_name}' variable found on instance %s.",
                        instanceId)
        );
      }

      AccessConfig accessConfig = null;
      for (AccessConfig config : networkInterface.getAccessConfigsList()) {
        if (config.getType().equals(Type.ONE_TO_ONE_NAT.name())) {
          accessConfig = config;
          break;
        }
      }

      if (accessConfig != null) {
        // Delete the existing access configuration first
        client.deleteAccessConfigAsync(projectId, zone, instanceId,
                        accessConfig.getName(), netInterfaceName).get(30, TimeUnit.SECONDS);
      }

      // return updated instance
      return client.get(projectId, zone, instanceId);
    }
  }
}

Python

import uuid

from google.cloud.compute_v1 import InstancesClient
from google.cloud.compute_v1.types import DeleteAccessConfigInstanceRequest


def unassign_static_ip_from_existing_vm(
    project_id: str,
    zone: str,
    instance_name: str,
    network_interface_name: str = "nic0",
):
    """
    Updates access configuration for a VM instance to unassign a static external IP.
    VM (and IP address in case of static IP assigned) must be created before calling this function.

    Args:
        project_id (str): Project ID.
        zone (str): Zone where the VM is located.
        instance_name (str): Name of the VM instance.
        network_interface_name (str): Name of the network interface to unassign.
    """
    client = InstancesClient()
    instance = client.get(project=project_id, zone=zone, instance=instance_name)
    network_interface = next(
        (ni for ni in instance.network_interfaces if ni.name == network_interface_name),
        None,
    )

    if network_interface is None:
        raise ValueError(
            f"No network interface named '{network_interface_name}' found on instance {instance_name}."
        )

    access_config = next(
        (ac for ac in network_interface.access_configs if ac.type_ == "ONE_TO_ONE_NAT"),
        None,
    )

    if access_config:
        # Delete the existing access configuration
        delete_request = DeleteAccessConfigInstanceRequest(
            project=project_id,
            zone=zone,
            instance=instance_name,
            access_config=access_config.name,
            network_interface=network_interface_name,
            request_id=str(uuid.uuid4()),
        )
        delete_operation = client.delete_access_config(delete_request)
        delete_operation.result()

    updated_instance = client.get(project=project_id, zone=zone, instance=instance_name)
    return updated_instance

静的外部 IP アドレスを解放する

静的外部 IPv4 アドレスや静的外部 IPv6 アドレスが不要になったら、IP アドレス リソースを削除して IP アドレスを解放できます。VM を削除しても、静的外部 IP アドレスは自動的に解放されません。静的外部 IP アドレスが不要になったら手動で解放する必要があります。

静的外部 IP アドレスを解放するには、VPC ドキュメントの静的外部 IP アドレスを解放するをご覧ください。

次のステップ