カスタム イメージを作成する


ソースディスク、イメージ、スナップショット、Cloud Storage に保存されているイメージからカスタム イメージを作成し、そのイメージを使用して仮想マシン(VM)インスタンスを作成できます。カスタム イメージは、永続ブートディスクまたは特定のイメージを作成して特定の状態に変更し、その状態を保存して VM を作成する場合に理想的です。

あるいは、仮想ディスク インポート ツールを使用して、既存のシステムから Compute Engine にブートディスク イメージをインポートし、それらのイメージをカスタム イメージリストに追加することもできます。

始める前に

  • Images ドキュメントを確認します。
  • まだ設定していない場合は、認証を設定します。認証とは、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. Go

      ローカル開発環境でこのページの Go サンプルを使用するには、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 をご覧ください。

      Java

      ローカル開発環境でこのページの Java サンプルを使用するには、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 をご覧ください。

      Node.js

      ローカル開発環境でこのページの Node.js サンプルを使用するには、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 をご覧ください。

      Python

      ローカル開発環境でこのページの Python サンプルを使用するには、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 を使用して認証するをご覧ください。

カスタム イメージの作成

このセクションでは、Linux VM でカスタム イメージを作成する方法について説明します。Windows イメージの作成については、Windows イメージを作成するをご覧ください。

イメージの保存ロケーションの選択

カスタム イメージを作成する場合、デュアルリージョンのロケーションを除く、イメージの Cloud Storage のロケーションを指定できます。イメージの保存ロケーションを指定すると、リージョン全体の冗長性を確保することで、データの局所性に関する規制およびコンプライアンスの要件と、高可用性のニーズを満たすことができます。Cloud Storage に保存されるイメージを作成、変更、削除するには、roles/compute.storageAdmin が必要です。

保存ロケーション機能はオプションです。ロケーションを選択しない場合、Compute Engine はイメージソースに最も近いマルチリージョンにイメージを保存します。たとえば、us-central1 にあるソースディスクからイメージを作成する場合、カスタム イメージのロケーションを指定しないと、Compute Engine はイメージを us マルチリージョンに保存します。

VM を作成しようとするリージョンでイメージを使用できない場合、Compute Engine は、VM の初回作成時に、そのリージョンのイメージをキャッシュに保存します。

イメージが保存されているロケーションを確認するには、gcloud compute から images describe コマンドを使用します。

gcloud compute images describe IMAGE_NAME \
    --project=PROJECT_ID

以下を置き換えます。

  • IMAGE_NAME: イメージの名前。

  • PROJECT_ID: イメージが属するプロジェクト ID。

この機能のリリース前に存在するイメージはすべて元の場所に残ります。唯一の変更点は、すべてのイメージについてイメージのロケーションを確認できる点です。移動する既存のイメージがある場合は、新しいロケーションに再作成する必要があります。

イメージに対する VM の準備

実行中の VM にアタッチされている状態のディスクからでもイメージを作成できます。ただし、イメージをキャプチャしやすい状態に VM を調整することで、イメージの信頼性が向上します。このセクションでは、ブートディスクをイメージ用に準備する方法について説明します。

永続ディスクへのデータ書き込みを最小限に抑える

ディスクの書き込みを減らすには、次のいずれかのプロセスを使用します。

  • VM を停止してシャットダウンできるようにし、永続ディスクへのデータの書き込みを停止します。

  • イメージを作成する前に VM を停止できない場合は、ディスクへの書き込み量を最小限に抑え、ファイル システムを同期してください。永続ディスクへの書き込みを最小限に抑えるには、次の手順を行います。

    1. 永続ディスクにデータを書き込むアプリやオペレーティング システムのプロセスを一時停止します。
    2. 必要に応じて、アプリでディスクへのフラッシュを実行します。たとえば、MySQL では FLUSH ステートメントを使用します。他のアプリにも同様のプロセスがある場合があります。
    3. アプリの永続ディスクへの書き込みを停止します。
    4. sudo sync を実行します。

ディスクの自動削除オプションを無効にする

デフォルトでは、ブートディスクで自動削除オプションが有効になっています。ディスクからイメージを作成する前に、自動削除を無効にして、VM の削除時にディスクが自動的に削除されないようにします。

ディスクの自動削除を無効にするには、次のいずれかの方法を使用します。

コンソール

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

    [VM インスタンス] ページに移動

  2. イメージの作成元として使用している VM の名前をクリックします。

    [VM インスタンスの詳細] ページが表示されます。

  3. [編集] をクリックします。

  4. [削除ルール] の [ブートディスク] セクションで、[ディスクを維持] オプションが選択されていることを確認します。

  5. [保存] をクリックします。

gcloud

Google Cloud CLI で gcloud compute instances set-disk-auto-delete コマンドを使用して、ディスクの自動削除オプションを無効にします。

gcloud compute instances set-disk-auto-delete VM_NAME \
    --no-auto-delete \
    --disk=SOURCE_DISK

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

  • VM_NAME: VM インスタンスの名前。
  • SOURCE_DISK: イメージを作成するディスクの名前。

Go

Go

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Go の設定手順に沿って操作します。詳細については、Compute Engine Go API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。

import (
	"context"
	"fmt"
	"io"

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

// setDiskAutodelete sets the autodelete flag of a disk to given value.
func setDiskAutoDelete(
	w io.Writer,
	projectID, zone, instanceName, diskName string, autoDelete bool,
) error {
	// projectID := "your_project_id"
	// zone := "us-west3-b"
	// instanceName := "your_instance_name"
	// diskName := "your_disk_name"
	// autoDelete := true

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

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

	instance, err := instancesClient.Get(ctx, getInstanceReq)
	if err != nil {
		return fmt.Errorf("unable to get instance: %w", err)
	}

	diskExists := false

	for _, disk := range instance.GetDisks() {
		if disk.GetDeviceName() == diskName {
			diskExists = true
			break
		}
	}

	if !diskExists {
		return fmt.Errorf(
			"instance %s doesn't have a disk named %s attached",
			instanceName,
			diskName,
		)
	}

	req := &computepb.SetDiskAutoDeleteInstanceRequest{
		Project:    projectID,
		Zone:       zone,
		Instance:   instanceName,
		DeviceName: diskName,
		AutoDelete: autoDelete,
	}

	op, err := instancesClient.SetDiskAutoDelete(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to set disk autodelete field: %w", err)
	}

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

	fmt.Fprintf(w, "disk autoDelete field updated.\n")

	return nil
}

Java

Java

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Java の設定手順に沿って操作します。詳細については、Compute Engine Java API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。


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

public class SetDiskAutodelete {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.

    // Project ID or project number of the Cloud project you want to use.
    String projectId = "YOUR_PROJECT_ID";

    // The zone of the disk that you want to modify.
    String zone = "europe-central2-b";

    // Name of the instance the disk is attached to.
    String instanceName = "YOUR_INSTANCE_NAME";

    // The name of the disk for which you want to modify the autodelete flag.
    String diskName = "YOUR_DISK_NAME";

    // The new value of the autodelete flag.
    boolean autoDelete = true;

    setDiskAutodelete(projectId, zone, instanceName, diskName, autoDelete);
  }

  // Sets the autodelete flag of a disk to given value.
  public static void setDiskAutodelete(String projectId, String zone, String instanceName,
      String diskName, boolean autoDelete)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the `instancesClient.close()` method on the client to safely
    // clean up any remaining background resources.
    try (InstancesClient instancesClient = InstancesClient.create()) {

      // Retrieve the instance given by the instanceName.
      Instance instance = instancesClient.get(projectId, zone, instanceName);

      // Check if the instance contains a disk that matches the given diskName.
      boolean diskNameMatch = instance.getDisksList()
          .stream()
          .anyMatch(disk -> disk.getDeviceName().equals(diskName));

      if (!diskNameMatch) {
        throw new Error(
            String.format("Instance %s doesn't have a disk named %s attached", instanceName,
                diskName));
      }

      // Create the request object.
      SetDiskAutoDeleteInstanceRequest request = SetDiskAutoDeleteInstanceRequest.newBuilder()
          .setProject(projectId)
          .setZone(zone)
          .setInstance(instanceName)
          .setDeviceName(diskName)
          // Update the autodelete property.
          .setAutoDelete(autoDelete)
          .build();

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

      if (response.hasError()) {
        System.out.println("Failed to update Disk autodelete field!" + response);
        return;
      }
      System.out.println(
          "Disk autodelete field updated. Operation Status: " + response.getStatus());
    }
  }
}

Node.js

Node.js

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Node.js の設定手順に沿って操作します。詳細については、Compute Engine Node.js API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。

/**
 * 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 diskName = 'YOUR_DISK_NAME';
// const autoDelete = true;

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

async function setDiskAutodelete() {
  const instancesClient = new compute.InstancesClient();

  const [instance] = await instancesClient.get({
    project: projectId,
    zone,
    instance: instanceName,
  });

  if (!instance.disks.some(disk => disk.deviceName === diskName)) {
    throw new Error(
      `Instance ${instanceName} doesn't have a disk named ${diskName} attached.`
    );
  }

  const [response] = await instancesClient.setDiskAutoDelete({
    project: projectId,
    zone,
    instance: instanceName,
    deviceName: diskName,
    autoDelete,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

  console.log('Disk autoDelete field updated.');
}

setDiskAutodelete();

Python

Python

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Python の設定手順に沿って操作します。詳細については、Compute Engine Python API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。

from __future__ import annotations

import sys
from typing import Any

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


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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result


def set_disk_autodelete(
    project_id: str, zone: str, instance_name: str, disk_name: str, autodelete: bool
) -> None:
    """
    Set the autodelete flag of a disk to given value.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone in which is the disk you want to modify.
        instance_name: name of the instance the disk is attached to.
        disk_name: the name of the disk which flag you want to modify.
        autodelete: the new value of the autodelete flag.
    """
    instance_client = compute_v1.InstancesClient()
    instance = instance_client.get(
        project=project_id, zone=zone, instance=instance_name
    )

    for disk in instance.disks:
        if disk.device_name == disk_name:
            break
    else:
        raise RuntimeError(
            f"Instance {instance_name} doesn't have a disk named {disk_name} attached."
        )

    disk.auto_delete = autodelete

    operation = instance_client.update(
        project=project_id,
        zone=zone,
        instance=instance_name,
        instance_resource=instance,
    )

    wait_for_extended_operation(operation, "disk update")

REST

ディスクの自動削除オプションを設定するには、instances.setDiskAutoDelete メソッドPOST リクエストを送信します。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/VM_NAME/setDiskAutoDelete?autoDelete=false&deviceName=SOURCE_DISK

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

  • PROJECT_ID: ソース VM が属するプロジェクト ID。
  • ZONE: ソース VM を配置するゾーン。
  • VM_NAME: 移行元 VM の名前。
  • SOURCE_DISK: イメージを作成するディスクのデバイス名。

VM の準備が完了したら、イメージを作成します

イメージの作成

次のソースからディスク イメージを作成できます。

  • 永続ディスク(ディスクが VM にアタッチされている場合も含む)
  • 永続ディスクのスナップショット
  • プロジェクトの別のイメージ
  • 別のプロジェクトで共有されているイメージ
  • Cloud Storage 内の圧縮された RAW イメージ

ディスク イメージは 10 分ごとに作成できます。ディスク イメージを作成するためのリクエストを大量に発行する場合、60 分で最大 6 件のリクエストを発行できます。詳細については、スナップショットの頻度の制限をご覧ください。

Console

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

    [イメージの作成] に移動

  2. イメージの [名前] を指定します。

  3. イメージ作成元の [ソース] を指定します。永続ディスク、スナップショット、別のイメージまたは Cloud Storage 内の disk.raw ファイルが指定できます

  4. 実行中の VM にアタッチされたディスクからイメージを作成する場合、[インスタンスを実行し続ける] をオンにして、VM の実行中にイメージを作成することを確認します。イメージを作成する前に VM を準備できます。

  5. [ソースディスクのロケーションに基づく(デフォルト)] プルダウン リストで、イメージを保存するロケーションを指定します。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

  6. 省略可: イメージのプロパティを指定します。

    • ファミリー: この新しいイメージが属するイメージ ファミリー
    • 説明: カスタム イメージの説明。
    • ラベル: リソースをグループ化するラベル
  7. 暗号鍵を指定します。Google が所有、管理する鍵、Cloud Key Management Service(Cloud KMS)鍵、顧客指定の暗号鍵(CSEK)のいずれかを選択できます。暗号鍵が指定されていない場合、イメージは Google が所有、管理する鍵を使用して暗号化されます。

  8. [作成] をクリックしてイメージを作成します。

gcloud

Google Cloud CLI で gcloud compute images create コマンドを使用し、カスタム イメージを作成します。

ソースディスクからイメージを作成:

--force フラグは、実行中のインスタンスからイメージを作成するためのフラグです。このフラグは省略可能です。デフォルトでは、実行中のインスタンスからイメージを作成することはできません。このフラグは、インスタンスの実行中にイメージを作成することを確実に意図している場合にのみ指定してください。

gcloud compute images create IMAGE_NAME \
    --source-disk=SOURCE_DISK \
    --source-disk-zone=ZONE \
    [--family=IMAGE_FAMILY] \
    [--storage-location=LOCATION] \
    [--force]

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

  • IMAGE_NAME: 新しいイメージの名前
  • SOURCE_DISK: イメージ作成元のディスク
  • ZONE: ディスクが配置されているゾーン
  • IMAGE_FAMILY: 省略可。このイメージが属するイメージ ファミリーを指定するフラグ。
  • LOCATION: 省略可。イメージが格納されるリージョンまたはマルチリージョンを指定するフラグ。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

ソースイメージからイメージを作成する:

gcloud compute images create IMAGE_NAME \
  --source-image=SOURCE_IMAGE \
  [--source-image-project=IMAGE_PROJECT] \
  [--family=IMAGE_FAMILY] \
  [--storage-location=LOCATION]

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

  • IMAGE_NAME: 新しいイメージの名前。
  • SOURCE_IMAGE: 新しいイメージの作成元のイメージ。
  • IMAGE_PROJECT: 省略可。ソースイメージがあるプロジェクト。このパラメータは、別のプロジェクトからイメージをコピーする場合に使用します。
  • IMAGE_FAMILY: 省略可。この新しいイメージが属するイメージ ファミリー
  • LOCATION: 省略可。イメージを保存するリージョンまたはマルチリージョンを指定できます。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

スナップショットからイメージを作成:

gcloud compute images create IMAGE_NAME \
    --source-snapshot=SOURCE_SNAPSHOT \
    [--storage-location=LOCATION]

以下を置き換えます。

  • IMAGE_NAME: 新しいイメージの名前
  • SOURCE_SNAPSHOT: イメージ作成元のスナップショット
  • LOCATION: 省略可。イメージが格納されるリージョンまたはマルチリージョンを指定するフラグ。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

イメージのロケーションの表示

gcloud compute images describe コマンドを使用して、イメージのロケーションを表示します。

gcloud compute images describe IMAGE_NAME

IMAGE_NAME は、確認するイメージの名前に置き換えます。

Go

Go

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Go の設定手順に沿って操作します。詳細については、Compute Engine Go API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。

import (
	"context"
	"fmt"
	"io"

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

// Creates a disk image from an existing disk
func createImageFromDisk(
	w io.Writer,
	projectID, zone, sourceDiskName, imageName string,
	storageLocations []string,
	forceCreate bool,
) error {
	// projectID := "your_project_id"
	// zone := "us-central1-a"
	// sourceDiskName := "your_disk_name"
	// imageName := "my_image"
	// // If storageLocations empty, automatically selects the closest one to the source
	// storageLocations = []string{}
	// // If forceCreate is set to `true`, proceeds even if the disk is attached to
	// // a running instance. This may compromise integrity of the image!
	// forceCreate = false

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

	// Get the source disk
	source_req := &computepb.GetDiskRequest{
		Disk:    sourceDiskName,
		Project: projectID,
		Zone:    zone,
	}

	disk, err := disksClient.Get(ctx, source_req)
	if err != nil {
		return fmt.Errorf("unable to get source disk: %w", err)
	}

	// Create the image
	req := computepb.InsertImageRequest{
		ForceCreate: &forceCreate,
		ImageResource: &computepb.Image{
			Name:             &imageName,
			SourceDisk:       disk.SelfLink,
			StorageLocations: storageLocations,
		},
		Project: projectID,
	}

	op, err := imagesClient.Insert(ctx, &req)

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

	fmt.Fprintf(w, "Disk image %s created\n", imageName)

	return nil
}

Java

Java

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Java の設定手順に沿って操作します。詳細については、Compute Engine Java API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。


import com.google.cloud.compute.v1.Disk;
import com.google.cloud.compute.v1.DisksClient;
import com.google.cloud.compute.v1.Image;
import com.google.cloud.compute.v1.ImagesClient;
import com.google.cloud.compute.v1.InsertImageRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateImage {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.

    // Project ID or project number of the Cloud project you use.
    String project = "your-project-id";
    // Zone of the disk you copy from.
    String zone = "europe-central2-b";
    // Name of the source disk you copy from.
    String sourceDiskName = "source-disk-name";
    // Name of the image you want to create.
    String imageName = "your-image-name";
    // Storage location for the image. If the value is undefined,
    // function will store the image in the multi-region closest to your image's source location.
    String storageLocation = "eu";
    // Create the image even if the source disk is attached to a running instance.
    boolean forceCreate = false;

    createImage(project, zone, sourceDiskName, imageName, storageLocation, forceCreate);
  }

  // Creates a new disk image from the specified source disk.
  public static void createImage(String project, String zone, String sourceDiskName,
      String imageName, String storageLocation, boolean forceCreate)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the `client.close()` method on the client to safely
    // clean up any remaining background resources.
    try (ImagesClient imagesClient = ImagesClient.create();
        InstancesClient instancesClient = InstancesClient.create();
        DisksClient disksClient = DisksClient.create()) {

      Disk disk = disksClient.get(project, zone, sourceDiskName);

      // Getting instances where source disk is attached.
      for (String fullInstanceName : disk.getUsersList()) {
        Map<String, String> instanceInfo = parseInstanceName(fullInstanceName);
        Instance instance = instancesClient.get(instanceInfo.get("instanceProjectId"),
            instanceInfo.get("instanceZone"), instanceInfo.get("instanceName"));

        // Сheck whether the instances are stopped.
        if (!Arrays.asList("TERMINATED", "STOPPED").contains(instance.getStatus())
            && !forceCreate) {
          throw new IllegalStateException(
              String.format(
                  "Instance %s should be stopped. For Windows instances please stop the instance "
                      + "using GCESysprep command. For Linux instances just shut it down normally."
                      + " You can suppress this error and create an image of the disk by setting "
                      + "'forceCreate' parameter to true (not recommended). "
                      + "More information here: "
                      + "* https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api"
                      + "* https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#prepare_instance_for_image",
                  instanceInfo.get("instanceName")));
        }
      }

      if (forceCreate) {
        System.out.println(
            "Warning: forceCreate option compromise the integrity of your image. "
                + "Stop the instance before you create the image if possible.");
      }

      // Create Image.
      Image image = Image.newBuilder()
          .setName(imageName)
          .setSourceDisk(String.format("/zones/%s/disks/%s", zone, sourceDiskName))
          .addStorageLocations(storageLocation.isEmpty() ? "" : storageLocation)
          .build();

      InsertImageRequest insertImageRequest = InsertImageRequest.newBuilder()
          .setProject(project)
          .setForceCreate(forceCreate)
          .setImageResource(image)
          .build();

      Operation response = imagesClient.insertAsync(insertImageRequest).get(5, TimeUnit.MINUTES);

      if (response.hasError()) {
        System.out.println("Image creation failed ! ! " + response);
        return;
      }

      System.out.println("Image created.");
    }
  }


  public static Map<String, String> parseInstanceName(String name) {
    String[] parsedName = name.split("/");
    int splitLength = parsedName.length;

    if (splitLength < 5) {
      throw new IllegalArgumentException(
          "Provide correct instance name in the following format: "
              + "https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME");
    }

    return new HashMap<>() {
      {
        put("instanceName", parsedName[splitLength - 1]);
        put("instanceZone", parsedName[splitLength - 3]);
        put("instanceProjectId", parsedName[splitLength - 5]);
      }
    };
  }

}

Python

Python

このサンプルを試す前に、Compute Engine クイックスタート: クライアント ライブラリの使用に記載されている Python の設定手順に沿って操作します。詳細については、Compute Engine Python API リファレンス ドキュメントをご覧ください。

Compute Engine に対して認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。

from __future__ import annotations

import sys
from typing import Any
import warnings

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


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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result


STOPPED_MACHINE_STATUS = (
    compute_v1.Instance.Status.TERMINATED.name,
    compute_v1.Instance.Status.STOPPED.name,
)


def create_image_from_disk(
    project_id: str,
    zone: str,
    source_disk_name: str,
    image_name: str,
    storage_location: str | None = None,
    force_create: bool = False,
) -> compute_v1.Image:
    """
    Creates a new disk image.

    Args:
        project_id: project ID or project number of the Cloud project you use.
        zone: zone of the disk you copy from.
        source_disk_name: name of the source disk you copy from.
        image_name: name of the image you want to create.
        storage_location: storage location for the image. If the value is undefined,
            function will store the image in the multi-region closest to your image's
            source location.
        force_create: create the image even if the source disk is attached to a
            running instance.

    Returns:
        An Image object.
    """
    image_client = compute_v1.ImagesClient()
    disk_client = compute_v1.DisksClient()
    instance_client = compute_v1.InstancesClient()

    # Get source disk
    disk = disk_client.get(project=project_id, zone=zone, disk=source_disk_name)

    for disk_user in disk.users:
        instance_name = disk_user.split("/")[-1]
        instance = instance_client.get(
            project=project_id, zone=zone, instance=instance_name
        )
        if instance.status in STOPPED_MACHINE_STATUS:
            continue
        if not force_create:
            raise RuntimeError(
                f"Instance {disk_user} should be stopped. For Windows instances please "
                f"stop the instance using `GCESysprep` command. For Linux instances just "
                f"shut it down normally. You can supress this error and create an image of"
                f"the disk by setting `force_create` parameter to true (not recommended). \n"
                f"More information here: \n"
                f" * https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api \n"
                f" * https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#prepare_instance_for_image"
            )
        else:
            warnings.warn(
                f"Warning: The `force_create` option may compromise the integrity of your image. "
                f"Stop the {disk_user} instance before you create the image if possible."
            )

    # Create image
    image = compute_v1.Image()
    image.source_disk = disk.self_link
    image.name = image_name
    if storage_location:
        image.storage_locations = [storage_location]

    operation = image_client.insert(project=project_id, image_resource=image)

    wait_for_extended_operation(operation, "image creation from disk")

    return image_client.get(project=project_id, image=image_name)

REST

images().insert メソッドに対して POST リクエストを実行します。リクエストの本文内の URL で、イメージの作成元となるソース オブジェクトをポイントします。独自のプロジェクト ID とイメージ名を使用して、リソースへの URL を指定します。

永続ディスクからイメージを作成:

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

{
  "name": "IMAGE_NAME",
  "sourceDisk": "/zones/ZONE/disks/SOURCE_DISK",
  ("storageLocations": "LOCATION",)
  ("forceCreate": "TRUE")
}

以下を置き換えます。

  • PROJECT_ID: イメージが属するプロジェクト ID。
  • IMAGE_NAME: 作成する新しいイメージの名前。
  • ZONE: ソースディスクが配置されているゾーン。
  • SOURCE_DISK: イメージ作成元のディスク。
  • LOCATION: 省略可。イメージの保存場所。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

オプションの forceCreate パラメータを使用すると、実行中の VM からイメージを作成できます。実行中の VM からイメージを作成することを確実に意図している場合にのみ、TRUE を指定します。forceCreate のデフォルトの設定は FALSE です。

別のイメージからイメージを作成:

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

{
  "name": "IMAGE_NAME",
  "sourceImage": "/global/images/SOURCE_IMAGE",
  ("storageLocations": "LOCATION")
}

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

  • PROJECT_ID: イメージが属するプロジェクト。
  • IMAGE_NAME: 作成する新しいイメージの名前。
  • SOURCE_IMAGE: イメージの作成元のイメージ。
  • LOCATION: 省略可。イメージの保存場所。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

スナップショットからイメージを作成:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/images
{
  "name": "IMAGE_NAME",
  "sourceSnapshot": "(/SOURCE_PROJECT_ID)/global/snapshots/SOURCE_SNAPSHOT",
  ("storageLocations": "LOCATION")
}

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

  • PROJECT_ID: イメージが属するプロジェクト。
  • IMAGE_NAME: 作成する新しいイメージの名前。
  • SOURCE_PROJECT_ID: 省略可。スナップショットが配置されているプロジェクト。プロジェクト内のスナップショット リソースにアクセスするための権限が必要です。
  • SOURCE_SNAPSHOT: イメージ作成元のスナップショット。
  • LOCATION: 省略可。イメージの保存場所。たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

イメージの追加に関する詳細については、イメージ参照をご覧ください。

イメージの共有

カスタム イメージの作成後、プロジェクト間で共有できます。別のプロジェクトのユーザーにカスタム イメージの使用を許可した場合、ユーザーがリクエストでイメージ プロジェクトを指定してこれらのイメージにアクセスできます。

ゲスト オペレーティング システムの機能を有効にする

ゲスト オペレーティング システム(OS)機能を使用して、カスタム イメージに以下のネットワーキング、セキュリティ、ストレージ、OS オペレーティング システムの各オプションを構成します。これらの構成を持つカスタム イメージは、ブートディスクとして使用されます。

gcloud

既存のカスタム イメージから新しいカスタム イメージを作成するには、--guest-os-features フラグを付けて gcloud compute images create コマンドを使用します。

gcloud compute images create IMAGE_NAME \
    --source-image=SOURCE_IMAGE \
    [--source-image-project=IMAGE_PROJECT] \
    --guest-os-features="FEATURES,..." \
    [--storage-location=LOCATION]

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

  • IMAGE_NAME: 新しいイメージの名前
  • SOURCE_IMAGE: 新しいイメージの基になるイメージ
  • IMAGE_PROJECT: 省略可。ソースイメージを含むプロジェクト

    このパラメータは、別のプロジェクトからイメージをコピーする場合に使用します。

  • FEATURES: イメージから作成する VM の機能を有効にするゲスト OS タグ

    複数の値を追加する場合は、値をカンマで区切ります。次のいずれかの値に設定します。

    • VIRTIO_SCSI_MULTIQUEUE。NVMe の代わりにローカル SSD デバイス上で使用します。SCSI をサポートするイメージの詳細については、インターフェースの選択をご覧ください。

      Linux イメージの場合は、カーネル バージョン 3.17 以降のイメージでローカル SSD デバイスのマルチキュー SCSI を有効にできます。Windows イメージの場合は、Compute Engine Windows ドライバ バージョン 1.2 を使用するイメージ上のローカル SSD デバイスでマルチキュー SCSI を有効にできます。

    • WINDOWSWindows Server カスタム ブート イメージに Windows イメージのタグを付けます。
    • MULTI_IP_SUBNET/32 以外のネットマスクのインターフェースを構成します。複数のネットワーク インターフェースとその仕組みの詳細については、 複数のネットワーク インターフェースの概要と例をご覧ください。
    • UEFI_COMPATIBLE UEFI ファームウェアと以下の Shielded VM 機能を使用して起動します。
    • GVNIC 50 Gbps ~ 100 Gbps の速度のネットワーク帯域幅をサポートします。詳細については、 Google Virtual NIC の使用をご覧ください。
    • IDPFIntel Infrastructure Data Path Function(IDPF)ネットワーク インターフェースをサポートします。
    • SEV_CAPABLE または SEV_SNP_CAPABLEAMD Secure Encrypted Virtualization(SEV)または AMD Secure Encrypted Virtualization-Secure Nested Paging(SEV-SNP)をサポートする Confidential VM インスタンスでイメージを使用する場合は、これらのタグを使用します。カーネルが AMD SEV または AMD SEV-SNP をサポートしているかどうかを確認するには、 Linux カーネルの詳細をご覧ください。
    • SEV_LIVE_MIGRATABLE_V2AMD SEV で ライブ マイグレーションをサポートする Confidential VM インスタンスでイメージを使用する場合は、このタグを使用します。カーネルがライブ マイグレーションをサポートしているかどうかを確認するには、 Linux カーネルの詳細をご覧ください。
    • TDX_CAPABLEインテル Trust Domain Extensions(TDX)をサポートする Confidential VM インスタンスでイメージを使用する場合は、このタグを使用します。カーネルが Intel TDX をサポートしているかどうかを確認するには、 Linux カーネルの詳細をご覧ください。
    • SUSPEND_RESUME_COMPATIBLEVM での一時停止と再開をサポートします。詳細については、OS の互換性をご覧ください。
  • LOCATION: 省略可。イメージを保存するリージョンまたはマルチリージョン。

    たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

REST

既存のカスタム イメージから新しいカスタム イメージを作成するには、guestOsFeatures フラグを付けて images().insert メソッドを使用します。


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

{
 "name": "IMAGE_NAME",
 "sourceImage": "(projects/IMAGE_PROJECT)/global/images/SOURCE_IMAGE",
 ("storageLocations": "LOCATION",)
 "guestOsFeatures": [
  {
   "type": "FEATURES"
  }
 ]
}

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

  • PROJECT_ID: 新しいイメージを作成するプロジェクトの ID
  • IMAGE_NAME: 新しいイメージの名前
  • IMAGE_PROJECT: 省略可。ソースイメージを含むプロジェクト

    このパラメータは、別のプロジェクトからイメージをコピーする場合に使用します。

  • SOURCE_IMAGE: 新しいイメージの基になるイメージ

  • LOCATION: 省略可。イメージを保存するリージョンまたはマルチリージョン

    たとえば、イメージを us マルチリージョンに保存するには us を指定し、us-central1 リージョンに保存するには us-central1 を指定します。選択しない場合、Compute Engine はイメージのソースのロケーションに最も近いマルチリージョンにイメージを保存します。

  • FEATURES: イメージから作成する VM の機能を有効にするゲスト OS タグ

    複数の値を追加する場合は、値をカンマで区切ります。次のいずれかの値に設定します。

    • VIRTIO_SCSI_MULTIQUEUE。NVMe の代わりにローカル SSD デバイス上で使用します。SCSI をサポートするイメージの詳細については、インターフェースの選択をご覧ください。

      Linux イメージの場合は、カーネル バージョン 3.17 以降のイメージでローカル SSD デバイスのマルチキュー SCSI を有効にできます。Windows イメージの場合は、Compute Engine Windows ドライバ バージョン 1.2 を使用するイメージ上のローカル SSD デバイスでマルチキュー SCSI を有効にできます。

    • WINDOWSWindows Server カスタム ブート イメージに Windows イメージのタグを付けます。
    • MULTI_IP_SUBNET/32 以外のネットマスクのインターフェースを構成します。複数のネットワーク インターフェースとその仕組みの詳細については、 複数のネットワーク インターフェースの概要と例をご覧ください。
    • UEFI_COMPATIBLE UEFI ファームウェアと以下の Shielded VM 機能を使用して起動します。
    • GVNIC 50 Gbps ~ 100 Gbps の速度のネットワーク帯域幅をサポートします。詳細については、 Google Virtual NIC の使用をご覧ください。
    • IDPFIntel Infrastructure Data Path Function(IDPF)ネットワーク インターフェースをサポートします。
    • SEV_CAPABLE または SEV_SNP_CAPABLEAMD Secure Encrypted Virtualization(SEV)または AMD Secure Encrypted Virtualization-Secure Nested Paging(SEV-SNP)をサポートする Confidential VM インスタンスでイメージを使用する場合は、これらのタグを使用します。カーネルが AMD SEV または AMD SEV-SNP をサポートしているかどうかを確認するには、 Linux カーネルの詳細をご覧ください。
    • SEV_LIVE_MIGRATABLE_V2AMD SEV で ライブ マイグレーションをサポートする Confidential VM インスタンスでイメージを使用する場合は、このタグを使用します。カーネルがライブ マイグレーションをサポートしているかどうかを確認するには、 Linux カーネルの詳細をご覧ください。
    • TDX_CAPABLEこのタグは、インテル Trust Domain Extensions(TDX)をサポートする Confidential VM インスタンスでイメージを使用する場合に使用します。カーネルが Intel TDX をサポートしているかどうかを確認するには、 Linux カーネルの詳細をご覧ください。
    • SUSPEND_RESUME_COMPATIBLEVM での一時停止と再開をサポートします。詳細については、OS の互換性をご覧ください。

UEFI 変数に機密情報を含めない

Unified Extensible Firmware Interface(UEFI)変数は、起動時に UEFI ファームウェアが VM のオペレーティング システムを起動するために使用する Key-Value ペア変数です。変数がハードウェア チップに保存される物理マシンとは異なり、Compute Engine ではこれらの変数のストレージが仮想化されます。そのため、多くのオペレーティング システムでは、すべてのアプリケーションとユーザーがこれらの変数にアクセスして情報を取得できます。

このため、パスワードや秘密鍵などの機密情報や個人を特定できる情報を UEFI 変数に書き込んだり保存したりしないことを強くおすすめします。

Arm イメージに関する考慮事項

Google は、Arm CPU プラットフォームで動作する C4A と Tau T2A マシンシリーズを提供しています。これらのマシンシリーズのいずれかを使用して VM を起動し、そのソース VM を使用して Arm イメージを作成できます。カスタム Arm イメージを作成するプロセスは、x86 イメージを作成するプロセスと同じです。

ユーザーが Arm イメージと x86 イメージを区別できるように、Arm イメージの architecture フィールドは ARM64 に設定されます。このフィールドに指定できる値は次のとおりです。

  • ARCHITECTURE_UNSPECIFIED
  • X86_64
  • ARM64

イメージのユーザーは、このフィールドでフィルタして、x86 イメージまたは Arm ベースのイメージを確認できます。

次のステップ