建立採用自訂機型的 VM

Compute Engine 提供預先定義機型,可在建立 VM 執行個體時使用。預先定義機型有預設的 vCPU 數量和記憶體容量,並有固定價格。如果預先定義的 VM 不符合需求,您可以建立 VM 執行個體,並自訂虛擬化硬體設定。具體來說,您可以建立具有自訂 vCPU 數量和記憶體容量的 VM 執行個體,有效使用自訂機型。自訂機型適用於:

自訂 VM 適合下列情境:

  • 不適合預先定義 VM 類型的工作負載。
  • 需要更多處理效能或記憶體,但不需要新一代機型所有升級功能的工作負載。
  • 工作負載的軟體授權費用是按 CPU 計算,您可以自訂 vCPU 數量,避免為未使用的處理能力支付授權費用,或配合可用的軟體授權數量。

事前準備

  • 參閱機器家族說明文件。
  • 如果尚未設定驗證,請先完成設定。驗證程序會確認您的身分,以便授予 Google Cloud 服務和 API 的存取權。如要從本機開發環境執行程式碼或範例,您可以選取下列其中一個選項,向 Compute Engine 進行驗證:

    請根據您打算如何使用本頁範例,選取對應的分頁標籤:

    控制台

    使用 Google Cloud 控制台存取 Google Cloud 服務和 API 時,不需要設定驗證機制。

    gcloud

    1. 安裝 Google Cloud CLI。 安裝完成後,請執行下列指令,初始化 Google Cloud CLI:

      gcloud init

      如果採用外部識別資訊提供者 (IdP),必須先 使用聯合身分登入 gcloud CLI。

  • 設定預設區域和可用區。
  • Terraform

    如要在本機開發環境中使用本頁的 Terraform 範例,請安裝並初始化 gcloud CLI,然後使用使用者憑證設定應用程式預設憑證。

    1. 安裝 Google Cloud CLI。

    2. 若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。

    3. 如果您使用的是本機殼層,請為使用者帳戶建立本機驗證憑證:

      gcloud auth application-default login

      如果您使用的是 Cloud Shell,則不必執行這項操作。

      如果系統傳回驗證錯誤,且您使用的是外部識別資訊提供者 (IdP),請確認您已 使用聯合身分登入 gcloud CLI。

    詳情請參閱「 為本機開發環境設定驗證機制」。

    Go

    如要在本機開發環境中使用本頁的 Go 範例,請安裝並初始化 gcloud CLI,然後使用使用者憑證設定應用程式預設憑證。

    1. 安裝 Google Cloud CLI。

    2. 若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。

    3. 如果您使用的是本機殼層,請為使用者帳戶建立本機驗證憑證:

      gcloud auth application-default login

      如果您使用的是 Cloud Shell,則不必執行這項操作。

      如果系統傳回驗證錯誤,且您使用的是外部識別資訊提供者 (IdP),請確認您已 使用聯合身分登入 gcloud CLI。

    詳情請參閱「 為本機開發環境設定驗證機制」。

    Java

    如要在本機開發環境中使用本頁的 Java 範例,請安裝並初始化 gcloud CLI,然後使用使用者憑證設定應用程式預設憑證。

    1. 安裝 Google Cloud CLI。

    2. 若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。

    3. 如果您使用的是本機殼層,請為使用者帳戶建立本機驗證憑證:

      gcloud auth application-default login

      如果您使用的是 Cloud Shell,則不必執行這項操作。

      如果系統傳回驗證錯誤,且您使用的是外部識別資訊提供者 (IdP),請確認您已 使用聯合身分登入 gcloud CLI。

    詳情請參閱「 為本機開發環境設定驗證機制」。

    Node.js

    如要在本機開發環境中使用本頁的 Node.js 範例,請安裝並初始化 gcloud CLI,然後使用使用者憑證設定應用程式預設憑證。

    1. 安裝 Google Cloud CLI。

    2. 若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。

    3. 如果您使用的是本機殼層,請為使用者帳戶建立本機驗證憑證:

      gcloud auth application-default login

      如果您使用的是 Cloud Shell,則不必執行這項操作。

      如果系統傳回驗證錯誤,且您使用的是外部識別資訊提供者 (IdP),請確認您已 使用聯合身分登入 gcloud CLI。

    詳情請參閱「 為本機開發環境設定驗證機制」。

    Python

    如要在本機開發環境中使用本頁的 Python 範例,請安裝並初始化 gcloud CLI,然後使用使用者憑證設定應用程式預設憑證。

    1. 安裝 Google Cloud CLI。

    2. 若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。

    3. 如果您使用的是本機殼層,請為使用者帳戶建立本機驗證憑證:

      gcloud auth application-default login

      如果您使用的是 Cloud Shell,則不必執行這項操作。

      如果系統傳回驗證錯誤,且您使用的是外部識別資訊提供者 (IdP),請確認您已 使用聯合身分登入 gcloud CLI。

    詳情請參閱「 為本機開發環境設定驗證機制」。

    REST

    如要在本機開發環境中使用本頁的 REST API 範例,請使用您提供給 gcloud CLI 的憑證。

      安裝 Google Cloud CLI。

      如果採用外部識別資訊提供者 (IdP),必須先 使用聯合身分登入 gcloud CLI。

    詳情請參閱 Google Cloud 驗證說明文件中的「使用 REST 進行驗證」一節。

必要的角色

如要取得建立自訂機型 VM 所需的權限,請要求管理員授予您專案的 Compute 執行個體管理員 (v1) (roles/compute.instanceAdmin.v1) IAM 角色。如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

這個預先定義的角色具備建立自訂機型 VM 所需的權限。如要查看確切的必要權限,請展開「Required permissions」(必要權限) 部分:

所需權限

您必須具備下列權限,才能使用自訂機型建立 VM:

  • 如要為現有 VM 新增擴充記憶體,請在 VM 上執行 compute.instances.setMachineType
  • 如要建立採用自訂機型的 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
    • 如要在使用虛擬私有雲網路時,為 VM 指派外部 IP 位址,請在專案或所選子網路上,指派 compute.subnetworks.useExternalIp 角色
    • 如要為專案中的 VM compute.instances.setMetadata 設定 VM 執行個體中繼資料,請按照下列步驟操作:
    • 如要設定 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

您或許還可透過自訂角色或其他預先定義的角色取得這些權限。

限制

  • 如果 VM 具有本機 SSD 磁碟,則無法變更 vCPU 和記憶體設定。
  • N4、N4A、N4D、N2、N2D 和 N1 自訂機型提供擴充記憶體。如要瞭解擴充記憶體的限制,請參閱「為機型新增擴充記憶體」。

    預先定義機型,以及 G2 和 E2 自訂機型,不支援擴充記憶體。

  • 擴充記憶體不適用依資源計算的承諾使用折扣。

  • 每個機型都有特定的 vCPU 和記憶體範圍和值,如下表所示:

機器系列 vCPU 數量下限 vCPU 數量上限 允許的 vCPU 每個 vCPU 的記憶體下限 (GB) 每個 vCPU 的記憶體上限 (GB) 步距 (MB) 擴充記憶體
N4 2 80 2 的任何倍數 2 8 256 是
N4D 2 96 2、4、8、16、32、48、64、80、96 0.5 8 256 是
N4A 1 64 不限 2 8 256 是
N2 2 80 2 的倍數 (最多 32) 或 4 的倍數 (32 至 80) 0.5 8 256 是
N2D 2 96 2、4、8、16、32、48、64、80、96 0.5 8 256 是
N1 1 96 1 或 2 的任何倍數 0.9 (1 或 2 個 vCPU 為 1) 6.5 256 是
E2 2 32 2 的任何倍數 0.5 8 256 否
E2 共用核心 0.25 1 0.25、0.5、1 總共 1 個 8 (微型總計 2 個,小型總計 4 個,中型總計 8 個) 256 否

以 GB 或 MB 表示記憶體

基於歷史原因, Google Cloud 工具和說明文件會以十進位 MB 和 GB 表示機型記憶體。不過,這些單位代表二進位 GiB 和 MiB,其中 1 GB 為 230 位元組,或 1,024 MB。

為自訂機型設定記憶體時,單位要求和轉換方式取決於您使用的工具:

  • 在 Google Cloud 控制台中,您必須以 GB 為單位指定記憶體。舉例來說,如果系統需要 1,024 MB 的記憶體,請在 Google Cloud 控制台中選取 1 GB。
  • 在 Compute Engine API 中,您必須以 MB 為單位提供記憶體,且必須是 256 MB 的整數倍數 (G2 VM 則為 1,024 MB)。舉例來說,如果您在 API 要求中指定 5,000 MB,嘗試佈建 5 GB 的記憶體,API 會傳回錯誤,因為 5,000 不是 256 的倍數 (5 GB 為 5,120 MB)。
  • 在 Google Cloud CLI 中,您可以指定 VM 的總記憶體,單位為 GB 或 MB:
    • 如果省略單位,--custom-memory 旗標預設為 GB。如要以 MB 為單位指定記憶體,必須加上 MB 單位後置字元。舉例來說,如果您需要 2,048 MB (2 GB) 的記憶體,並指定 --custom-memory=2048 旗標,但未指定單位,gcloud CLI 會要求 2,048 GB 的記憶體,而非 2,048 MB。
    • 傳遞至 --custom-memory 的無單位值必須是整數。如要以 0.25 GB (256 MB) 為單位增減 (例如 5.75 GB),請將值轉換為以 MB 為單位的整數 (--custom-memory=5888MB),或加上 GB 單位後置字串 (--custom-memory=5.75GB)。
    • 使用 --machine-type 旗標時,您必須以 MB 為單位指定記憶體,並以不含單位尾碼的整數表示,例如 --machine-type=n2-custom-2-5120。

自訂機型定價

Compute Engine 會根據 VM 使用的 vCPU 數量和記憶體時數,向自訂 VM 收費。這種定價模式與 Compute Engine 對預先定義機型的收費方式不同。自訂機型的隨選價格會比預先定義機型的隨選價格多出 5% 的附加費率。

  • 使用自訂機型時,如果記憶體不超過每個 vCPU 的預設量,則會按照機器家族自訂機型價格計費。E2 自訂機器和 E2 共用核心自訂機型採用相同的計價方案。

  • 如果您使用承諾使用合約執行自訂機型,Compute Engine 會在承諾使用合約的價格上加收 5% 的附加費率。在您執行這些自訂機型 VM 的承諾使用合約期間,Compute Engine 會針對您使用的部分收取這筆附加費率。

如要依機器系列查看定價資訊,請參閱「VM 執行個體定價」。

自訂 VM 與其他執行個體一樣,最低收費時間為 1 分鐘,但自訂機型的續用折扣計算方式不同。詳情請參閱自訂 VM 的續用折扣。

擴充記憶體定價

如果記憶體超過 vCPU 數量設定為擴充記憶體的範圍上限,Compute Engine 會根據機器家族擴充自訂記憶體定價,收取額外費用。擴充記憶體的價格高於範圍上限內的記憶體價格。

擴充記憶體價格取決於區域。透過擴充記憶體執行的執行個體,與其他所有執行個體同樣皆遵循 1 分鐘最低收費的規範。擴充記憶體不符合依資源計算的承諾使用折扣資格,但符合運算彈性承諾使用折扣和續用折扣資格。

為機型新增擴充記憶體

每個自訂機型機器系列都有預設的每個 vCPU RAM 上限。對某些工作負載來說,這個預設上限可能不足以滿足每個 vCPU 的記憶體需求。您可以額外付費,讓每個 vCPU 取得超出預設上限的記憶體容量,最多可達機器系列上限,這稱為「擴充記憶體」。下表列出各支援機器系列的 vCPU 和擴充記憶體限制:

機器系列 vCPU 限制 記憶體限制
N4 80 640 GB
N4D 96 768 GB
N4A 64 512 GB
N2 80 864 GB
N2D 96 768 GB
N1 96 624 GB

如需更高的 RAM 與 vCPU 比率,請參閱記憶體最佳化機型。

判斷是否需要擴充記憶體

某些工作負載會需要每個 vCPU 具備超過預設容量的記憶體,方可獲得最佳效果。這類工作負載是以記憶體內高效能分析資料庫為基礎,包括關聯式和 NoSQL 資料庫,例如 Microsoft SQL Server、MongoDB、Memcached 或 Redis。此外,作業系統和軟體堆疊採用以 vCPU 為基礎的授權模式,因此使用預先定義的機型時,更難選擇最佳 VM 記憶體設定。使用擴充記憶體,即可視需要為 VM 新增記憶體,享有最佳成本效益。

使用自訂機型建立 VM

建立自訂 VM 執行個體前,請先參閱自訂規格,瞭解如何建立這類機型。

控制台

  1. 前往 Google Cloud 控制台的「Create an instance」(建立執行個體) 頁面。

    前往「Create an instance」(建立執行個體)

  2. 在「機器設定」窗格中,執行下列操作:

    1. 選取要託管執行個體的「Region」(區域) 和「Zone」(可用區)。
    2. 選取執行個體的機器設定:
      • 如要建立一般用途自訂 VM,請選取「一般用途」,然後在「系列」部分選取「N4」、「N4A」、「N4D」、「N2」、「N2D」、「E2」或「N1」。
      • 如要建立附加 GPU 的自訂 VM,請選取「GPU」,然後執行下列操作:
        1. 在「GPU type」(GPU 類型) 清單中,選取要使用的機器系列 GPU:
          • 如果是 G2 VM,請選取「NVIDIA L4」。
          • 如果是 N1 VM,請選取「NVIDIA T4」、「NVIDIA V100」或「NVIDIA Tesla P4」。
        2. 在「Number of GPUs」(GPU 數量) 清單中,選取 GPU 數量。
    3. 在「Machine type」(機器類型) 區段中,選取「Custom」(自訂)。
    4. 如要指定執行個體的 vCPU 數量和記憶體容量,請拖曳「Cores」(核心) 和「Memory」(記憶體) 滑桿,或在欄位中輸入值。變更 vCPU 數量和記憶體容量時,控制台會顯示執行個體的預估費用。
  3. 選用:指定其他設定選項。詳情請參閱「建立執行個體時的設定選項」。

  4. 如要建立並啟動執行個體,請按一下「Create」(建立)。

gcloud

使用 gcloud compute instances create 指令搭配 --machine-type 旗標,建立自訂機型:

gcloud compute instances create INSTANCE_NAME \
    --zone=ZONE \
    --machine-type=MACHINE_SERIES-custom-NUMBER_OF_VCPUS-AMOUNT_OF_MEMORY_MB

更改下列內容:

  • INSTANCE_NAME:執行個體的名稱。
  • ZONE:要建立執行個體的可用區。
  • MACHINE_SERIES:小寫機器系列,例如 n4、n4d、n4a、n2、n2d、e2 或 g2。如果是 N1,請省略 MACHINE_SERIES-,並從 custom- 開始。
  • NUMBER_OF_VCPUS:vCPU 數量。
  • AMOUNT_OF_MEMORY_MB:記憶體總量,以 MB 為單位。這個值必須是 256 MB 的整數倍數 (G2 VM 則為 1,024 MB)。

如要在可用區 us-central1-a 建立具有 4 個 vCPU 和 19 GB 記憶體的 G2 VM,請執行下列指令:

gcloud compute instances create example-instance \
    --zone=us-central1-a \
    --machine-type=g2-custom-4-19456 \
    --maintenance-policy=TERMINATE

如果是 G2 VM,記憶體必須是 1,024 MB 的倍數,且在支援的記憶體範圍內。如要進一步瞭解如何建立 G2 VM,請參閱「建立 G2 或 G4 執行個體」。

下列範例會在可用區 us-central1-a 建立 N2 自訂機型,配備 48 個 vCPU 和 310 GB (317,440 MB) 記憶體:

gcloud compute instances create example-instance \
    --zone=us-central1-a \
    --machine-type=n2-custom-48-317440

如果是 N4 或 N2 等支援的機器系列,您可以設定擴充記憶體,指定高於預設記憶體與 vCPU 最大比率的記憶體容量。如要設定擴充記憶體,請提高 AMOUNT_OF_MEMORY_MB 的值,並在機型名稱後方附加 -ext,例如 --machine-type=n2-custom-48-720896-ext。

或者,您也可以使用 --custom-cpu、--custom-memory 和 --custom-vm-type 旗標指定自訂機型 (如果要設定擴充記憶體,請加入 --custom-extensions 旗標):

gcloud compute instances create INSTANCE_NAME \
    --zone=ZONE \
    --custom-cpu=NUMBER_OF_VCPUS \
    --custom-memory=AMOUNT_OF_MEMORY \
    --custom-vm-type=MACHINE_SERIES

更改下列內容:

  • INSTANCE_NAME:執行個體的名稱。
  • ZONE:要建立執行個體的可用區。
  • NUMBER_OF_VCPUS:vCPU 數量。
  • AMOUNT_OF_MEMORY:記憶體總量,後置字串為單位 (MB 或 GB),如省略單位,則以 GB 為單位。
  • MACHINE_SERIES:小寫機器系列,例如 n4、n4d、n4a、n2、n2d、e2 或 n1。

下列範例使用 --custom-cpu、--custom-memory 和 --custom-vm-type 旗標,建立具有 48 個 vCPU 和 310 GB 記憶體的 N2 自訂機型:

gcloud compute instances create example-instance \
    --zone=us-central1-a \
    --custom-cpu=48 \
    --custom-memory=317440MB \
    --custom-vm-type=n2

使用 --custom-memory 旗標時,請以 GB 或 MB 為單位指定記憶體總量。無單位的值必須是整數。如要以 0.25 GB (256 MB) 為單位指定記憶體,請將總記憶體轉換為以 MB 為單位的整數 (--custom-memory=5888MB),或加入 GB 單位尾碼 (--custom-memory=5.75GB)。

如果是 E2 共用核心自訂機型,請使用 gcloud compute instances create 指令,並加入共用核心機器大小 (micro、small 或 medium):

gcloud compute instances create INSTANCE_NAME \
    --zone=ZONE \
    --machine-type=e2-custom-SHARED_CORE_SIZE-AMOUNT_OF_MEMORY_MB

更改下列內容:

  • INSTANCE_NAME:執行個體的名稱。
  • ZONE:要建立執行個體的可用區。
  • SHARED_CORE_SIZE:E2 共用核心大小 (micro、small 或 medium)。
  • AMOUNT_OF_MEMORY_MB:記憶體總量,以 MB 為單位。這個值必須是 256 MB 的整數倍,且在共用核心大小的允許範圍內。

下列範例會建立 E2 共用核心 small 自訂機型,具有 0.5 個 vCPU 和 2.25 GB (2,304 MB) 的記憶體:

gcloud compute instances create example-instance \
    --zone=us-central1-a \
    --machine-type=e2-custom-small-2304

Terraform

如要產生 Terraform 程式碼,您可以使用 Google Cloud 控制台中的「Equivalent code」(對等程式碼) 元件。
  1. 前往 Google Cloud 控制台的「VM instances」(VM 執行個體) 頁面。

    前往 VM 執行個體

  2. 點選「建立執行個體」。
  3. 指定所需參數。
  4. 按一下頁面頂端或底部的「Equivalent code」(對等程式碼),然後點選「Terraform」分頁標籤,即可查看 Terraform 程式碼。

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"
	"google.golang.org/protobuf/proto"
)

func customMachineTypeURI(zone, cpuSeries string, coreCount, memory int) (string, error) {
	const (
		n1       = "custom"
		n2       = "n2-custom"
		n2d      = "n2d-custom"
		e2       = "e2-custom"
		e2Micro  = "e2-custom-micro"
		e2Small  = "e2-custom-small"
		e2Medium = "e2-custom-medium"
	)

	type typeLimit struct {
		allowedCores     []int
		minMemPerCore    int
		maxMemPerCore    int
		allowExtraMemory bool
		extraMemoryLimit int
	}

	makeRange := func(start, end, step int) []int {
		if step <= 0 || end < start {
			return []int{}
		}
		s := make([]int, 0, 1+(end-start)/step)
		for start <= end {
			s = append(s, start)
			start += step
		}
		return s
	}

	containsString := func(s []string, str string) bool {
		for _, v := range s {
			if v == str {
				return true
			}
		}

		return false
	}

	containsInt := func(nums []int, n int) bool {
		for _, v := range nums {
			if v == n {
				return true
			}
		}

		return false
	}

	var (
		cpuSeriesE2Limit = typeLimit{
			allowedCores:  makeRange(2, 33, 2),
			minMemPerCore: 512,
			maxMemPerCore: 8192,
		}
		cpuSeriesE2MicroLimit  = typeLimit{minMemPerCore: 1024, maxMemPerCore: 2048}
		cpuSeriesE2SmallLimit  = typeLimit{minMemPerCore: 2048, maxMemPerCore: 4096}
		cpuSeriesE2MeidumLimit = typeLimit{minMemPerCore: 4096, maxMemPerCore: 8192}
		cpuSeriesN2Limit       = typeLimit{
			allowedCores:  append(makeRange(2, 33, 2), makeRange(36, 129, 4)...),
			minMemPerCore: 512, maxMemPerCore: 8192,
			allowExtraMemory: true,
			extraMemoryLimit: 624 << 10,
		}
		cpuSeriesN2DLimit = typeLimit{
			allowedCores:  []int{2, 4, 8, 16, 32, 48, 64, 80, 96},
			minMemPerCore: 512, maxMemPerCore: 8192,
			allowExtraMemory: true,
			extraMemoryLimit: 768 << 10,
		}
		cpuSeriesN1Limit = typeLimit{
			allowedCores:     append([]int{1}, makeRange(2, 97, 2)...),
			minMemPerCore:    922,
			maxMemPerCore:    6656,
			allowExtraMemory: true,
			extraMemoryLimit: 624 << 10,
		}
	)

	typeLimitsMap := map[string]typeLimit{
		n1:       cpuSeriesN1Limit,
		n2:       cpuSeriesN2Limit,
		n2d:      cpuSeriesN2DLimit,
		e2:       cpuSeriesE2Limit,
		e2Micro:  cpuSeriesE2MicroLimit,
		e2Small:  cpuSeriesE2SmallLimit,
		e2Medium: cpuSeriesE2MeidumLimit,
	}

	if !containsString([]string{e2, n1, n2, n2d}, cpuSeries) {
		return "", fmt.Errorf("incorrect cpu type: %v", cpuSeries)
	}

	tl := typeLimitsMap[cpuSeries]

	// Check whether the requested parameters are allowed.
	// Find more information about limitations of custom machine types at:
	// https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types

	// Check the number of cores
	if len(tl.allowedCores) > 0 && !containsInt(tl.allowedCores, coreCount) {
		return "", fmt.Errorf(
			"invalid number of cores requested. Allowed number of cores for %v is: %v",
			cpuSeries,
			tl.allowedCores,
		)
	}

	// Memory must be a multiple of 256 MB
	if memory%256 != 0 {
		return "", fmt.Errorf("requested memory must be a multiple of 256 MB")
	}

	// Check if the requested memory isn't too little
	if memory < coreCount*tl.minMemPerCore {
		return "", fmt.Errorf(
			"requested memory is too low. Minimal memory for %v is %v MB per core",
			cpuSeries,
			tl.minMemPerCore,
		)
	}

	// Check if the requested memory isn't too much
	if memory > coreCount*tl.maxMemPerCore && !tl.allowExtraMemory {
		return "", fmt.Errorf(
			"requested memory is too large.. Maximum memory allowed for %v is %v MB per core",
			cpuSeries,
			tl.maxMemPerCore,
		)
	}
	if memory > tl.extraMemoryLimit && tl.allowExtraMemory {
		return "", fmt.Errorf(
			"requested memory is too large.. Maximum memory allowed for %v is %v MB",
			cpuSeries,
			tl.extraMemoryLimit,
		)
	}

	// Return the custom machine type in form of a string acceptable by Compute Engine API.
	if containsString([]string{e2Small, e2Micro, e2Medium}, cpuSeries) {
		return fmt.Sprintf("zones/%v/machineTypes/%v-%v", zone, cpuSeries, memory), nil
	}

	if memory > coreCount*tl.maxMemPerCore {
		return fmt.Sprintf(
			"zones/%v/machineTypes/%v-%v-%v-ext",
			zone,
			cpuSeries,
			coreCount,
			memory,
		), nil
	}

	return fmt.Sprintf("zones/%v/machineTypes/%v-%v-%v", zone, cpuSeries, coreCount, memory), nil
}

// createInstanceWithCustomMachineTypeWithHelper creates a new VM instance with a custom machine type.
func createInstanceWithCustomMachineTypeWithHelper(
	w io.Writer,
	projectID, zone, instanceName, cpuSeries string,
	coreCount, memory int,
) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// cpuSeries := "e2-custom-micro" // the type of CPU you want to use"
	// coreCount := 2 // number of CPU cores you want to use.
	// memory := 256 // the amount of memory for the VM instance, in megabytes.

	machineType, err := customMachineTypeURI(zone, cpuSeries, coreCount, memory)
	if err != nil {
		return fmt.Errorf("unable to create custom machine type string: %w", err)
	}

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

	req := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name: proto.String(instanceName),
			Disks: []*computepb.AttachedDisk{
				{
					InitializeParams: &computepb.AttachedDiskInitializeParams{
						DiskSizeGb: proto.Int64(10),
						SourceImage: proto.String(
							"projects/debian-cloud/global/images/family/debian-12",
						),
					},
					AutoDelete: proto.Bool(true),
					Boot:       proto.Bool(true),
				},
			},
			MachineType: proto.String(machineType),
			NetworkInterfaces: []*computepb.NetworkInterface{
				{
					Name: proto.String("global/networks/default"),
				},
			},
		},
	}

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

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

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

	return nil
}

Java

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Java 設定操作說明進行操作。詳情請參閱 Compute Engine Java API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。


import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import com.google.cloud.compute.v1.Operation;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.IntStream;

public class CreateWithHelper {

  // This class defines the configurable parameters for a custom VM.
  static final class TypeLimits {

    int[] allowedCores;
    int minMemPerCore;
    int maxMemPerCore;
    int extraMemoryLimit;
    boolean allowExtraMemory;

    TypeLimits(int[] allowedCores, int minMemPerCore, int maxMemPerCore, boolean allowExtraMemory,
        int extraMemoryLimit) {
      this.allowedCores = allowedCores;
      this.minMemPerCore = minMemPerCore;
      this.maxMemPerCore = maxMemPerCore;
      this.allowExtraMemory = allowExtraMemory;
      this.extraMemoryLimit = extraMemoryLimit;
    }
  }

  public enum CpuSeries {
    N1("custom"),
    N2("n2-custom"),
    N2D("n2d-custom"),
    E2("e2-custom"),
    E2_MICRO("e2-custom-micro"),
    E2_SMALL("e2-custom-small"),
    E2_MEDIUM("e2-custom-medium");

    private static final Map<String, CpuSeries> ENUM_MAP;

    static {
      ENUM_MAP = init();
    }

    // Build an immutable map of String name to enum pairs.
    public static Map<String, CpuSeries> init() {
      Map<String, CpuSeries> map = new ConcurrentHashMap<>();
      for (CpuSeries instance : CpuSeries.values()) {
        map.put(instance.getCpuSeries(), instance);
      }
      return Collections.unmodifiableMap(map);
    }

    private final String cpuSeries;

    CpuSeries(String cpuSeries) {
      this.cpuSeries = cpuSeries;
    }

    public static CpuSeries get(String name) {
      return ENUM_MAP.get(name);
    }

    public String getCpuSeries() {
      return this.cpuSeries;
    }
  }

  // This enum correlates a machine type with its limits.
  // The limits for various CPU types are described in:
  // https://cloud.google.com/compute/docs/general-purpose-machines
  enum Limits {
    CPUSeries_E2(new TypeLimits(getNumsInRangeWithStep(2, 33, 2), 512, 8192, false, 0)),
    CPUSeries_E2MICRO(new TypeLimits(new int[]{}, 1024, 2048, false, 0)),
    CPUSeries_E2SMALL(new TypeLimits(new int[]{}, 2048, 4096, false, 0)),
    CPUSeries_E2MEDIUM(new TypeLimits(new int[]{}, 4096, 8192, false, 0)),
    CPUSeries_N2(
        new TypeLimits(concat(getNumsInRangeWithStep(2, 33, 2), getNumsInRangeWithStep(36, 129, 4)),
            512, 8192, true, gbToMb(624))),
    CPUSeries_N2D(
        new TypeLimits(new int[]{2, 4, 8, 16, 32, 48, 64, 80, 96}, 512, 8192, true, gbToMb(768))),
    CPUSeries_N1(
        new TypeLimits(concat(new int[]{1}, getNumsInRangeWithStep(2, 97, 2)), 922, 6656, true,
            gbToMb(624)));

    private final TypeLimits typeLimits;

    Limits(TypeLimits typeLimits) {
      this.typeLimits = typeLimits;
    }

    public TypeLimits getTypeLimits() {
      return typeLimits;
    }
  }

  static ImmutableMap<String, Limits> typeLimitsMap = ImmutableMap.<String, Limits>builder()
      .put("N1", Limits.CPUSeries_N1)
      .put("N2", Limits.CPUSeries_N2)
      .put("N2D", Limits.CPUSeries_N2D)
      .put("E2", Limits.CPUSeries_E2)
      .put("E2_MICRO", Limits.CPUSeries_E2MICRO)
      .put("E2_SMALL", Limits.CPUSeries_E2SMALL)
      .put("E2_MEDIUM", Limits.CPUSeries_E2SMALL)
      .build();

  // Returns the array of integers within the given range, incremented by the specified step.
  // start (inclusive): starting number of the range
  // stop (inclusive): ending number of the range
  // step : increment value
  static int[] getNumsInRangeWithStep(int start, int stop, int step) {
    return IntStream.range(start, stop).filter(x -> (x - start) % step == 0).toArray();
  }

  static int gbToMb(int value) {
    return value << 10;
  }

  static int[] concat(int[] a, int[] b) {
    int[] result = new int[a.length + b.length];
    System.arraycopy(a, 0, result, 0, a.length);
    System.arraycopy(b, 0, result, a.length, b.length);
    return result;
  }

  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-google-cloud-project-id";
    // Name of the zone to create the instance in. For example: "us-west3-b".
    String zone = "google-cloud-zone";
    // Name of the new virtual machine (VM) instance.
    String instanceName = "instance-name";
    String cpuSeries = "N1";
    // Number of CPU cores you want to use.
    int coreCount = 2;
    // The amount of memory for the VM instance, in megabytes.
    int memory = 256;

    createInstanceWithCustomMachineTypeWithHelper(
        projectId, zone, instanceName, cpuSeries, coreCount, memory);
  }

  // Create a VM instance with a custom machine type.
  public static void createInstanceWithCustomMachineTypeWithHelper(
      String project, String zone, String instanceName, String cpuSeries, int coreCount, int memory)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Construct the URI string identifying the machine type.
    String machineTypeUri = customMachineTypeUri(zone, cpuSeries, coreCount, memory);

    // 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()) {

      AttachedDisk attachedDisk = AttachedDisk.newBuilder()
          .setInitializeParams(
              // Describe the size and source image of the boot disk to attach to the instance.
              // The list of public images available in Compute Engine can be found here:
              // https://cloud.google.com/compute/docs/images#list_of_public_images_available_on
              AttachedDiskInitializeParams.newBuilder()
                  .setSourceImage(
                      String.format("projects/%s/global/images/family/%s", "debian-cloud",
                          "debian-13"))
                  .setDiskSizeGb(10)
                  .build()
          )
          // 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();

      // Create the Instance object with the relevant information.
      Instance instance = Instance.newBuilder()
          .setName(instanceName)
          .addDisks(attachedDisk)
          .setMachineType(machineTypeUri)
          .addNetworkInterfaces(
              NetworkInterface.newBuilder().setName("global/networks/default").build())
          .build();

      // Create the insert instance request object.
      InsertInstanceRequest insertInstanceRequest = InsertInstanceRequest.newBuilder()
          .setProject(project)
          .setZone(zone)
          .setInstanceResource(instance)
          .build();

      // Invoke the API with the request object and wait for the operation to complete.
      Operation response = instancesClient.insertAsync(insertInstanceRequest)
          .get(3, TimeUnit.MINUTES);

      // Check for errors.
      if (response.hasError()) {
        throw new Error("Instance creation failed!!" + response);
      }
      System.out.printf("Instance created : %s", instanceName);
      System.out.println("Operation Status: " + response.getStatus());
    }
  }

  public static String customMachineTypeUri(String zone, String cpuSeries, int coreCount,
      int memory) {

    if (!Arrays.asList(CpuSeries.E2.cpuSeries, CpuSeries.N1.cpuSeries, CpuSeries.N2.cpuSeries,
        CpuSeries.N2D.cpuSeries).contains(cpuSeries)) {
      throw new Error(String.format("Incorrect cpu type: %s", cpuSeries));
    }

    TypeLimits typeLimit = Objects.requireNonNull(
        typeLimitsMap.get(CpuSeries.get(cpuSeries).name())).typeLimits;

    // Perform the following checks to verify if the requested parameters are allowed.
    // Find more information about limitations of custom machine types at:
    // https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types

    // 1. Check the number of cores and if the coreCount is present in allowedCores.
    if (typeLimit.allowedCores.length > 0 && Arrays.stream(typeLimit.allowedCores)
        .noneMatch(x -> x == coreCount)) {
      throw new Error(String.format(
          "Invalid number of cores requested. "
              + "Number of cores requested for CPU %s should be one of: %s",
          cpuSeries,
          Arrays.toString(typeLimit.allowedCores)));
    }

    // 2. Memory must be a multiple of 256 MB
    if (memory % 256 != 0) {
      throw new Error("Requested memory must be a multiple of 256 MB");
    }

    // 3. Check if the requested memory isn't too little
    if (memory < coreCount * typeLimit.minMemPerCore) {
      throw new Error(
          String.format("Requested memory is too low. Minimum memory for %s is %s MB per core",
              cpuSeries, typeLimit.minMemPerCore));
    }

    // 4. Check if the requested memory isn't too much
    if (memory > coreCount * typeLimit.maxMemPerCore && !typeLimit.allowExtraMemory) {
      throw new Error(String.format(
          "Requested memory is too large.. Maximum memory allowed for %s is %s MB per core",
          cpuSeries, typeLimit.extraMemoryLimit));
    }

    // 5. Check if the requested memory isn't too large
    if (memory > typeLimit.extraMemoryLimit && typeLimit.allowExtraMemory) {
      throw new Error(
          String.format("Requested memory is too large.. Maximum memory allowed for %s is %s MB",
              cpuSeries, typeLimit.extraMemoryLimit));
    }

    // Check if the CPU Series is E2 and return the custom machine type in the form of a string
    // acceptable by Compute Engine API.
    if (Arrays.asList(CpuSeries.E2_SMALL.cpuSeries, CpuSeries.E2_MICRO.cpuSeries,
        CpuSeries.E2_MEDIUM.cpuSeries).contains(cpuSeries)) {
      return String.format("zones/%s/machineTypes/%s-%s", zone, cpuSeries, memory);
    }

    // Check if extended memory was requested and return the extended custom machine type
    // in the form of a string acceptable by Compute Engine API.
    if (memory > coreCount * typeLimit.maxMemPerCore) {
      return String.format("zones/%s/machineTypes/%s-%s-%s-ext", zone, cpuSeries, coreCount,
          memory);
    }

    // Return the custom machine type in the form of a standard string
    // acceptable by Compute Engine API.
    return String.format("zones/%s/machineTypes/%s-%s-%s", zone, cpuSeries, coreCount, memory);
  }
}

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 cpuSeries = 'N1';
// const coreCount = 2
// const memory = 256

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

function range(from, to, step) {
  return [...Array(Math.floor((to - from) / step) + 1)].map(
    (_, i) => from + i * step
  );
}

class CustomMachineType {
  constructor(zone, cpuSeries, coreCount, memory) {
    this.zone = zone;
    this.cpuSeries = cpuSeries;
    this.coreCount = coreCount;
    this.memory = memory;

    this.N1 = 'custom';
    this.N2 = 'n2-custom';
    this.N2D = 'n2d-custom';
    this.E2 = 'e2-custom';
    this.E2Micro = 'e2-custom-micro';
    this.E2Small = 'e2-custom-small';
    this.E2Medium = 'e2-custom-medium';

    this.CpuSeriesE2Limit = {
      allowedCores: range(2, 33, 2),
      minMemPerCore: 512,
      maxMemPerCore: 8192,
      allowExtraMemory: false,
      extraMemoryLimit: 0,
    };

    this.CpuSeriesE2MicroLimit = {
      allowedCores: [],
      minMemPerCore: 1024,
      maxMemPerCore: 2048,
      allowExtraMemory: false,
      extraMemoryLimit: 0,
    };

    this.CpuSeriesE2SmallLimit = {
      allowedCores: [],
      minMemPerCore: 2048,
      maxMemPerCore: 4096,
      allowExtraMemory: false,
      extraMemoryLimit: 0,
    };

    this.CpuSeriesE2MediumLimit = {
      allowedCores: [],
      minMemPerCore: 4096,
      maxMemPerCore: 8192,
      allowExtraMemory: false,
      extraMemoryLimit: 0,
    };

    this.CpuSeriesN2Limit = {
      allowedCores: [...range(2, 33, 2), ...range(36, 129, 4)],
      minMemPerCore: 512,
      maxMemPerCore: 8192,
      allowExtraMemory: true,
      extraMemoryLimit: 624 << 10,
    };

    this.CpuSeriesN2DLimit = {
      allowedCores: [2, 4, 8, 16, 32, 48, 64, 80, 96],
      minMemPerCore: 512,
      maxMemPerCore: 8192,
      allowExtraMemory: true,
      extraMemoryLimit: 768 << 10,
    };

    this.CpuSeriesN1Limit = {
      allowedCores: [1, range(2, 97, 2)],
      minMemPerCore: 922,
      maxMemPerCore: 6656,
      allowExtraMemory: true,
      extraMemoryLimit: 624 << 10,
    };

    this.TYPE_LIMITS = {
      [this.N1]: this.CpuSeriesN1Limit,
      [this.N2]: this.CpuSeriesN2Limit,
      [this.N2D]: this.CpuSeriesN2DLimit,
      [this.E2]: this.CpuSeriesE2Limit,
      [this.E2Micro]: this.CpuSeriesE2MicroLimit,
      [this.E2Small]: this.CpuSeriesE2SmallLimit,
      [this.E2Medium]: this.CpuSeriesE2MediumLimit,
    };

    if (![this.E2, this.N1, this.N2, this.N2D].includes(cpuSeries)) {
      throw new Error(`Incorrect CPU type: ${this.cpuSeries}`);
    }

    this.typeLimit = this.TYPE_LIMITS[this.cpuSeries];

    // Check whether the requested parameters are allowed.
    // Find more information about limitations of custom machine types at:
    // https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types

    // Check the number of cores
    if (
      this.typeLimit.allowedCores.length > 0 &&
      !this.typeLimit.allowedCores.includes(coreCount)
    ) {
      throw new Error(
        `Invalid number of cores requested. Allowed number of cores for ${this.cpuSeries} is: ${this.typeLimit.allowedCores}`
      );
    }

    // Memory must be a multiple of 256 MB
    if (this.memory % 256 !== 0) {
      throw new Error('Requested memory must be a multiple of 256 MB');
    }

    // Check if the requested memory isn't too little
    if (this.memory < this.coreCount * this.typeLimit.minMemPerCore) {
      throw new Error(
        `Requested memory is too low. Minimal memory for ${this.cpuSeries} is ${this.typeLimit.minMemPerCore} MB per core`
      );
    }

    // Check if the requested memory isn't too much
    if (
      this.memory > this.coreCount * this.typeLimit.maxMemPerCore &&
      !this.typeLimit.allowExtraMemory
    ) {
      throw new Error(
        `Requested memory is too large.. Maximum memory allowed for ${this.cpuSeries} is ${this.typeLimit.maxMemPerCore} MB per core`
      );
    }

    if (
      this.memory > this.typeLimit.extraMemoryLimit &&
      this.typeLimit.allowExtraMemory
    ) {
      throw new Error(
        `Requested memory is too large.. Maximum memory allowed for ${this.cpuSeries} is ${this.typeLimit.extraMemoryLimit} MB`
      );
    }
  }

  // Returns the custom machine type in form of a string acceptable by Compute Engine API.
  getMachineTypeURI() {
    if (
      [this.E2Small, this.E2Micro, this.E2Medium].includes(this.cpuSeries)
    ) {
      return `zones/${this.zone}/machineTypes/${this.cpuSeries}-${this.memory}`;
    }

    if (this.memory > this.coreCount * this.typeLimit.maxMemPerCore) {
      return `zones/${this.zone}/machineTypes/${this.cpuSeries}-${this.coreCount}-${this.memory}-ext`;
    }

    return `zones/${zone}/machineTypes/${this.cpuSeries}-${this.coreCount}-${this.memory}`;
  }
}

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

  const machineType = new CustomMachineType(
    zone,
    cpuSeries,
    coreCount,
    memory
  ).getMachineTypeURI();

  const [response] = await instancesClient.insert({
    instanceResource: {
      name: instanceName,
      disks: [
        {
          initializeParams: {
            diskSizeGb: '64',
            sourceImage:
              'projects/debian-cloud/global/images/family/debian-11/',
          },
          autoDelete: true,
          boot: true,
        },
      ],
      machineType,
      networkInterfaces: [
        {
          name: 'global/networks/default',
        },
      ],
    },
    project: projectId,
    zone,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

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

createInstanceWithCustomMachineTypeWithHelper();

Python

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Python 設定操作說明進行操作。詳情請參閱 Compute Engine Python API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。

from __future__ import annotations

from collections import namedtuple
from enum import Enum
from enum import unique
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 gb_to_mb(value: int) -> int:
    return value << 10


class CustomMachineType:
    """
    Allows to create custom machine types to be used with the VM instances.
    """

    @unique
    class CPUSeries(Enum):
        N1 = "custom"
        N2 = "n2-custom"
        N2D = "n2d-custom"
        E2 = "e2-custom"
        E2_MICRO = "e2-custom-micro"
        E2_SMALL = "e2-custom-small"
        E2_MEDIUM = "e2-custom-medium"

    TypeLimits = namedtuple(
        "TypeLimits",
        [
            "allowed_cores",
            "min_mem_per_core",
            "max_mem_per_core",
            "allow_extra_memory",
            "extra_memory_limit",
        ],
    )

    # The limits for various CPU types are described on:
    # https://cloud.google.com/compute/docs/general-purpose-machines
    LIMITS = {
        CPUSeries.E2: TypeLimits(frozenset(range(2, 33, 2)), 512, 8192, False, 0),
        CPUSeries.E2_MICRO: TypeLimits(frozenset(), 1024, 2048, False, 0),
        CPUSeries.E2_SMALL: TypeLimits(frozenset(), 2048, 4096, False, 0),
        CPUSeries.E2_MEDIUM: TypeLimits(frozenset(), 4096, 8192, False, 0),
        CPUSeries.N2: TypeLimits(
            frozenset(range(2, 33, 2)).union(set(range(36, 129, 4))),
            512,
            8192,
            True,
            gb_to_mb(624),
        ),
        CPUSeries.N2D: TypeLimits(
            frozenset({2, 4, 8, 16, 32, 48, 64, 80, 96}), 512, 8192, True, gb_to_mb(768)
        ),
        CPUSeries.N1: TypeLimits(
            frozenset({1}.union(range(2, 97, 2))), 922, 6656, True, gb_to_mb(624)
        ),
    }

    def __init__(
        self, zone: str, cpu_series: CPUSeries, memory_mb: int, core_count: int = 0
    ):
        self.zone = zone
        self.cpu_series = cpu_series
        self.limits = self.LIMITS[self.cpu_series]
        # Shared machine types (e2-small, e2-medium and e2-micro) always have
        # 2 vCPUs: https://cloud.google.com/compute/docs/general-purpose-machines#e2_limitations
        self.core_count = 2 if self.is_shared() else core_count
        self.memory_mb = memory_mb
        self._checked = False
        self._check_parameters()
        self.extra_memory_used = self._check_extra_memory()

    def is_shared(self):
        return self.cpu_series in (
            CustomMachineType.CPUSeries.E2_SMALL,
            CustomMachineType.CPUSeries.E2_MICRO,
            CustomMachineType.CPUSeries.E2_MEDIUM,
        )

    def _check_extra_memory(self) -> bool:
        if self._checked:
            return self.memory_mb > self.core_count * self.limits.max_mem_per_core
        else:
            raise RuntimeError(
                "You need to call _check_parameters() before calling _check_extra_memory()"
            )

    def _check_parameters(self):
        """
        Check whether the requested parameters are allowed. Find more information about limitations of custom machine
        types at: https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types
        """
        # Check the number of cores
        if (
            self.limits.allowed_cores
            and self.core_count not in self.limits.allowed_cores
        ):
            raise RuntimeError(
                f"Invalid number of cores requested. Allowed number of cores for {self.cpu_series.name} is: {sorted(self.limits.allowed_cores)}"
            )

        # Memory must be a multiple of 256 MB
        if self.memory_mb % 256 != 0:
            raise RuntimeError("Requested memory must be a multiple of 256 MB.")

        # Check if the requested memory isn't too little
        if self.memory_mb < self.core_count * self.limits.min_mem_per_core:
            raise RuntimeError(
                f"Requested memory is too low. Minimal memory for {self.cpu_series.name} is {self.limits.min_mem_per_core} MB per core."
            )

        # Check if the requested memory isn't too much
        if self.memory_mb > self.core_count * self.limits.max_mem_per_core:
            if self.limits.allow_extra_memory:
                if self.memory_mb > self.limits.extra_memory_limit:
                    raise RuntimeError(
                        f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.extra_memory_limit} MB."
                    )
            else:
                raise RuntimeError(
                    f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.max_mem_per_core} MB per core."
                )

        self._checked = True

    def __str__(self) -> str:
        """
        Return the custom machine type in form of a string acceptable by Compute Engine API.
        """
        if self.cpu_series in {
            self.CPUSeries.E2_SMALL,
            self.CPUSeries.E2_MICRO,
            self.CPUSeries.E2_MEDIUM,
        }:
            return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.memory_mb}"

        if self.extra_memory_used:
            return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}-ext"

        return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}"

    def short_type_str(self) -> str:
        """
        Return machine type in a format without the zone. For example, n2-custom-0-10240.
        This format is used to create instance templates.
        """
        return str(self).rsplit("/", maxsplit=1)[1]

    @classmethod
    def from_str(cls, machine_type: str):
        """
        Construct a new object from a string. The string needs to be a valid custom machine type like:
         - https://www.googleapis.com/compute/v1/projects/diregapic-mestiv/zones/us-central1-b/machineTypes/e2-custom-4-8192
         - zones/us-central1-b/machineTypes/e2-custom-4-8192
         - e2-custom-4-8192 (in this case, the zone parameter will not be set)
        """
        zone = None
        if machine_type.startswith("http"):
            machine_type = machine_type[machine_type.find("zones/") :]

        if machine_type.startswith("zones/"):
            _, zone, _, machine_type = machine_type.split("/")

        extra_mem = machine_type.endswith("-ext")

        if machine_type.startswith("custom"):
            cpu = cls.CPUSeries.N1
            _, cores, memory = machine_type.rsplit("-", maxsplit=2)
        else:
            if extra_mem:
                cpu_series, _, cores, memory, _ = machine_type.split("-")
            else:
                cpu_series, _, cores, memory = machine_type.split("-")
            if cpu_series == "n2":
                cpu = cls.CPUSeries.N2
            elif cpu_series == "n2d":
                cpu = cls.CPUSeries.N2D
            elif cpu_series == "e2":
                cpu = cls.CPUSeries.E2
                if cores == "micro":
                    cpu = cls.CPUSeries.E2_MICRO
                    cores = 2
                elif cores == "small":
                    cpu = cls.CPUSeries.E2_SMALL
                    cores = 2
                elif cores == "medium":
                    cpu = cls.CPUSeries.E2_MEDIUM
                    cores = 2
            else:
                raise RuntimeError("Unknown CPU series.")

        cores = int(cores)
        memory = int(memory)

        return cls(zone, cpu, memory, cores)


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

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

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


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

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

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


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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result


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

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

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

    if internal_ip:
        network_interface.network_i_p = internal_ip

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

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

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

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

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

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

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

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

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

    operation = instance_client.insert(request=request)

    wait_for_extended_operation(operation, "instance creation")

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


def create_custom_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    cpu_series: CustomMachineType.CPUSeries,
    core_count: int,
    memory: int,
) -> compute_v1.Instance:
    """
    Create a new VM instance with a custom machine type.

    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.
        cpu_series: the type of CPU you want to use. Select one value from the CustomMachineType.CPUSeries enum.
            For example: CustomMachineType.CPUSeries.N2
        core_count: number of CPU cores you want to use.
        memory: the amount of memory for the VM instance, in megabytes.

    Return:
        Instance object.
    """
    assert cpu_series in (
        CustomMachineType.CPUSeries.E2,
        CustomMachineType.CPUSeries.N1,
        CustomMachineType.CPUSeries.N2,
        CustomMachineType.CPUSeries.N2D,
    )
    custom_type = CustomMachineType(zone, cpu_series, memory, core_count)

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

    return create_instance(project_id, zone, instance_name, disks, str(custom_type))

REST

如要使用自訂機型建立執行個體,請呼叫 instances.insert 方法,並指定自訂 machineType 值,記憶體單位為 MB:

  • 如果是 N1 機器系列,請省略系列前置字串,並以 custom- 開頭。
  • 如果是 E2 共用核心機型,請將 vCPU 數量替換為 micro、small 或 medium。
  • 如要啟用擴充記憶體,請在機型字串後方附加 -ext。

下列範例會建立 N2 自訂機型,配備 16 個 vCPU 和 105 GB (107,520 MB) 記憶體:

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

{
  "name": "example-instance",
  "machineType": "zones/ZONE/machineTypes/n2-custom-16-107520",
  "disks": [
    {
      "boot": true,
      "initializeParams": {
        "diskSizeGb": "10",
        "sourceImage": "projects/debian-cloud/global/images/family/debian-13"
      }
    }
  ],
  "networkInterfaces": [
    {
      "network": "global/networks/default"
    }
  ]
}

更改下列內容:

  • PROJECT_ID:要建立執行個體的專案 ID。
  • ZONE:要建立執行個體的可用區。

您也可以使用自訂機型建立 Spot VM 和代管執行個體群組 (MIG)。

在建立執行個體時新增擴充記憶體

如要建立具有擴充記憶體的 VM 執行個體,請按照下列步驟操作:

控制台

  1. 前往 Google Cloud 控制台的「Create an instance」(建立執行個體) 頁面。

    前往「Create an instance」(建立執行個體)

  2. 在「機器設定」窗格中,執行下列操作:

    1. 選取要託管 VM 的「區域」和「可用區」。
    2. 選取執行個體的機器設定:
      • 如要建立一般用途自訂 VM,請選取「General purpose」(一般用途),然後在「Series」(系列) 區段中選取「N4」、「N4D」、「N4A」、「N2」、「N2D」或「N1」。
      • 如要建立附加 GPU 的 N1 自訂 VM,請選取「GPUs」(GPU),然後執行下列操作:
        1. 在「GPU type」(GPU 類型) 清單中,選取「NVIDIA T4」、「NVIDIA V100」或「NVIDIA Tesla P4」。
        2. 在「Number of GPUs」(GPU 數量) 清單中,選取 GPU 數量。
    3. 在「Machine type」(機器類型) 區段中,選取「Custom」(自訂)。
    4. 如要指定 vCPU 數量,請拖曳「Cores」(核心) 滑桿,或在欄位中輸入值。
    5. 如要新增擴充記憶體,請選取「擴充記憶體」。如要指定機型的記憶體容量,請拖曳「Memory」(記憶體) 滑桿,或在欄位中輸入值。編輯 vCPU 數量和記憶體容量時,控制台會顯示 VM 的預估費用。
  3. 選用:指定其他設定選項。詳情請參閱「建立執行個體時的設定選項」。

  4. 如要建立並啟動 VM,請按一下 [Create] (建立)。

gcloud

使用 gcloud compute instances create 指令搭配 --machine-type 旗標和 -ext 後置字元,建立具有擴充記憶體的自訂機型:

gcloud compute instances create INSTANCE_NAME \
    --zone=ZONE \
    --machine-type=MACHINE_SERIES-custom-NUMBER_OF_VCPUS-AMOUNT_OF_MEMORY_MB-ext

更改下列內容:

  • INSTANCE_NAME:執行個體的名稱。
  • ZONE:要建立執行個體的可用區。
  • MACHINE_SERIES:支援擴充記憶體的小寫機器系列,例如 n4、n4d、n4a、n2 或 n2d。如果是 N1,請省略 MACHINE_SERIES-,並從 custom- 開始。
  • NUMBER_OF_VCPUS:vCPU 數量。
  • AMOUNT_OF_MEMORY_MB:記憶體總量,以 MB 為單位。這個值必須是 256 MB 的整數倍。

下列範例會在可用區 us-central1-a 建立 N2 自訂機型,配備 2 個 vCPU 和 20 GB (20,480 MB) 的擴充記憶體:

gcloud compute instances create example-instance \
    --zone=us-central1-a \
    --machine-type=n2-custom-2-20480-ext

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"
	"google.golang.org/protobuf/proto"
)

// createInstanceWithExtraMemWithoutHelper сreates new VM instances with extra memory
// without using a CustomMachineType struct.
func createInstanceWithExtraMemWithoutHelper(
	w io.Writer,
	projectID, zone, instanceName, cpuSeries string,
	coreCount, memory int,
) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// cpuSeries := "N1"
	// coreCount := 2 // number of CPU cores you want to use.
	// memory := 256 // the amount of memory for the VM instance, in megabytes.

	// The coreCount and memory values are not validated anywhere and can be rejected by the API.

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

	mt := fmt.Sprintf("zones/%s/machineTypes/%v-%v-%v-ext", zone, cpuSeries, coreCount, memory)
	inst := &computepb.Instance{
		Name: proto.String(instanceName),
		Disks: []*computepb.AttachedDisk{
			{
				InitializeParams: &computepb.AttachedDiskInitializeParams{
					DiskSizeGb: proto.Int64(10),
					SourceImage: proto.String(
						"projects/debian-cloud/global/images/family/debian-12",
					),
				},
				AutoDelete: proto.Bool(true),
				Boot:       proto.Bool(true),
			},
		},
		MachineType: proto.String(mt),
		NetworkInterfaces: []*computepb.NetworkInterface{
			{
				Name: proto.String("global/networks/default"),
			},
		},
	}

	req := &computepb.InsertInstanceRequest{
		Project:          projectID,
		Zone:             zone,
		InstanceResource: inst,
	}

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

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

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

	return nil
}

Java

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Java 設定操作說明進行操作。詳情請參閱 Compute Engine Java API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。


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

public class ExtraMemoryWithoutHelper {

  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-google-cloud-project-id";
    // Name of the zone to create the instance in. For example: "us-west3-b".
    String zone = "google-cloud-zone";
    // Name of the new virtual machine (VM) instance.
    String instanceName = "instance-name";
    String cpuSeries = "N1";
    // Number of CPU cores you want to use.
    int coreCount = 2;
    // The amount of memory for the VM instance, in megabytes.
    int memory = 256;

    createInstanceWithExtraMemoryWithoutHelper(projectId, zone, instanceName, cpuSeries, coreCount,
        memory);
  }

  // Create VM instances with extra memory without using a CustomMachineType class and
  // return the created Instance.
  public static void createInstanceWithExtraMemoryWithoutHelper(
      String project, String zone, String instanceName, String cpuSeries, int coreCount, int memory)
      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()) {

      // The coreCount and memory values are not validated anywhere and can be rejected by the API.
      String machineType = String.format("zones/%s/machineTypes/%s-%s-%s-ext", zone, cpuSeries,
          coreCount, memory);

      AttachedDisk attachedDisk = AttachedDisk.newBuilder()
          .setInitializeParams(
              // Describe the size and source image of the boot disk to attach to the instance.
              // The list of public images available in Compute Engine can be found here:
              // https://cloud.google.com/compute/docs/images#list_of_public_images_available_on
              AttachedDiskInitializeParams.newBuilder()
                  .setSourceImage(
                      String.format("projects/%s/global/images/family/%s", "debian-cloud",
                          "debian-13"))
                  .setDiskSizeGb(10)
                  .build()
          )
          // 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();

      // Create the Instance object with the relevant information.
      Instance instance = Instance.newBuilder()
          .setName(instanceName)
          .addDisks(attachedDisk)
          .setMachineType(machineType)
          .addNetworkInterfaces(
              NetworkInterface.newBuilder().setName("global/networks/default").build())
          .build();

      // Create the insert instance request object.
      InsertInstanceRequest insertInstanceRequest = InsertInstanceRequest.newBuilder()
          .setProject(project)
          .setZone(zone)
          .setInstanceResource(instance)
          .build();

      // Invoke the API with the request object and wait for the operation to complete.
      Operation response = instancesClient.insertAsync(insertInstanceRequest)
          .get(3, TimeUnit.MINUTES);

      // Check for errors.
      if (response.hasError()) {
        System.out.println("Instance creation failed!!" + response);
        return;
      }
      System.out.printf("Instance created : %s", instanceName);
      System.out.println("Operation Status: " + response.getStatus());
    }
  }
}

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 cpuSeries = 'N1';
// const coreCount = 2
// const memory = 256

// The coreCount and memory values are not validated anywhere and can be rejected by the API.

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

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

  const machineType = `zones/${zone}/machineTypes/${cpuSeries}-${coreCount}-${memory}-ext`;

  const [response] = await instancesClient.insert({
    instanceResource: {
      name: instanceName,
      disks: [
        {
          initializeParams: {
            diskSizeGb: '64',
            sourceImage:
              'projects/debian-cloud/global/images/family/debian-11/',
          },
          autoDelete: true,
          boot: true,
        },
      ],
      machineType,
      networkInterfaces: [
        {
          name: 'global/networks/default',
        },
      ],
    },
    project: projectId,
    zone,
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

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

createInstanceWithExtraMemWithoutHelper();

Python

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Python 設定操作說明進行操作。詳情請參閱 Compute Engine Python API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。

from __future__ import annotations

import re
import sys
from typing import Any
import warnings

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


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

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

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


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

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

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


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

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

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

    Returns:
        Whatever the operation.result() returns.

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

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

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

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

    return result


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

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

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

    if internal_ip:
        network_interface.network_i_p = internal_ip

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

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

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

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

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

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

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

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

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

    operation = instance_client.insert(request=request)

    wait_for_extended_operation(operation, "instance creation")

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


def create_custom_instances_extra_mem(
    project_id: str, zone: str, instance_name: str, core_count: int, memory: int
) -> list[compute_v1.Instance]:
    """
    Create 3 new VM instances with extra memory without using a CustomMachineType helper class.

    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.
        core_count: number of CPU cores you want to use.
        memory: the amount of memory for the VM instance, in megabytes.

    Returns:
        List of Instance objects.
    """
    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)]
    # The core_count and memory values are not validated anywhere and can be rejected by the API.
    instances = [
        create_instance(
            project_id,
            zone,
            f"{instance_name}_n1_extra_mem",
            disks,
            f"zones/{zone}/machineTypes/custom-{core_count}-{memory}-ext",
        ),
        create_instance(
            project_id,
            zone,
            f"{instance_name}_n2_extra_mem",
            disks,
            f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}-ext",
        ),
        create_instance(
            project_id,
            zone,
            f"{instance_name}_n2d_extra_mem",
            disks,
            f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}-ext",
        ),
    ]
    return instances

REST

如要建立具有擴充記憶體的執行個體,請呼叫 instances.insert 方法,並將 -ext 附加至 machineType 欄位,將記憶體擴充至該機器系列的上限:

zones/ZONE/machineTypes/MACHINE_SERIES-custom-NUMBER_OF_VCPUS-AMOUNT_OF_MEMORY_MB-ext

更改下列內容:

  • ZONE:要建立執行個體的可用區。
  • MACHINE_SERIES:小寫機器系列,例如 n4、n4d、n4a、n2 或 n2d。如果是 N1,請省略 MACHINE_SERIES-,並從 custom- 開始。
  • NUMBER_OF_VCPUS:vCPU 數量。
  • AMOUNT_OF_MEMORY_MB:記憶體總量,以 MB 為單位。這個值必須是 256 MB 的整數倍。

舉例來說,下列指令會指定 N2 機型,並配備 2 個 vCPU 和 20 GB (20,480 MB) 的擴充記憶體:

zones/ZONE/machineTypes/n2-custom-2-20480-ext

為現有 VM 執行個體新增擴充記憶體

如要為使用自訂機型的現有執行個體新增記憶體,請先停止執行個體。執行個體停止運作後,請完成下列步驟,為 VM 增加記憶體:

控制台

  1. 前往 Google Cloud 控制台的「VM instances」(VM 執行個體) 頁面。

    前往 VM 執行個體

  2. 按一下要修改的已停止 VM 名稱。

  3. 按一下頁面頂端的 [Edit] (編輯)。

  4. 在「Machine configuration」(機器設定) 部分,確認「Machine type」(機器類型) 下方已選取「Custom」(自訂)。

  5. 如要新增擴充記憶體,請選取「Extend Memory」(擴充記憶體),然後指定所需的「Memory」(記憶體) 數量。

  6. 按一下 [儲存]。

  7. 如要重新啟動 VM,請按一下頁面頂端的「Start / Resume」(啟動/繼續)。

gcloud

  1. 執行 gcloud compute instances stop 指令來停止 VM:

    gcloud compute instances stop INSTANCE_NAME \
        --zone=ZONE
    
  2. 執行 gcloud compute instances set-machine-type 指令,並搭配 --custom-cpu、--custom-memory、--custom-vm-type 和 --custom-extensions 旗標,更新具有擴充記憶體的自訂機型:

    gcloud compute instances set-machine-type INSTANCE_NAME \
        --zone=ZONE \
        --custom-cpu=NUMBER_OF_VCPUS \
        --custom-memory=AMOUNT_OF_MEMORY \
        --custom-vm-type=MACHINE_SERIES \
        --custom-extensions
    

    或者,您也可以將完整的自訂機型字串和 -ext 後置字串傳遞至 --machine-type 旗標:

    gcloud compute instances set-machine-type INSTANCE_NAME \
        --zone=ZONE \
        --machine-type=MACHINE_SERIES-custom-NUMBER_OF_VCPUS-AMOUNT_OF_MEMORY_MB-ext
    

    更改下列內容:

    • INSTANCE_NAME:VM 的名稱。
    • ZONE:VM 所在的可用區。
    • NUMBER_OF_VCPUS:vCPU 數量。
    • AMOUNT_OF_MEMORY:記憶體總量,後置字串為單位 (MB 或 GB),如省略單位,則以 GB 為單位。
    • AMOUNT_OF_MEMORY_MB:記憶體總量,以 MB 為單位。這個值必須是 256 MB 的整數倍。
    • MACHINE_SERIES:支援擴充記憶體的小寫機器系列,例如 n4、n4d、n4a、n2、n2d 或 n1。如果是使用 --machine-type 旗標的 N1,請省略 MACHINE_SERIES-,並以 custom- 開頭。
  3. 執行 gcloud compute instances start 指令,重新啟動 VM:

    gcloud compute instances start INSTANCE_NAME \
        --zone=ZONE
    

Go

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Go 設定操作說明進行操作。詳情請參閱 Compute Engine Go API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。

import (
	"context"
	"fmt"
	"io"
	"strings"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "cloud.google.com/go/compute/apiv1/computepb"
	"google.golang.org/protobuf/proto"
)

// modifyInstanceWithExtendedMemory sends an instance creation request
// to the Compute Engine API and waits for it to complete.
func modifyInstanceWithExtendedMemory(
	w io.Writer,
	projectID, zone, instanceName string,
	newMemory int,
) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// newMemory := 256 // the amount of memory for the VM instance, in megabytes.

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

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

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

	containsString := func(s []string, str string) bool {
		for _, v := range s {
			if v == str {
				return true
			}
		}

		return false
	}

	if !(strings.Contains(instance.GetMachineType(), "machineTypes/n1-") ||
		strings.Contains(instance.GetMachineType(), "machineTypes/n2-") ||
		strings.Contains(instance.GetMachineType(), "machineTypes/n2d-")) {
		return fmt.Errorf("extra memory is available only for N1, N2 and N2D CPUs")
	}

	// Make sure that the machine is turned off
	if !containsString([]string{"TERMINATED", "STOPPED"}, instance.GetStatus()) {
		reqStop := &computepb.StopInstanceRequest{
			Project:  projectID,
			Zone:     zone,
			Instance: instanceName,
		}

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

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

	// Modify the machine definition, remember that extended memory
	// is available only for N1, N2 and N2D CPUs
	machineType := instance.GetMachineType()
	start := machineType[:strings.LastIndex(machineType, "-")]

	updateReq := &computepb.SetMachineTypeInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
		InstancesSetMachineTypeRequestResource: &computepb.InstancesSetMachineTypeRequest{
			MachineType: proto.String(fmt.Sprintf("%s-%v-ext", start, newMemory)),
		},
	}
	op, err := instancesClient.SetMachineType(ctx, updateReq)
	if err != nil {
		return fmt.Errorf("unable to update instance: %w", err)
	}

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

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

	return nil

}

Java

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Java 設定操作說明進行操作。詳情請參閱 Compute Engine Java API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。


import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.compute.v1.GetInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.Instance.Status;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.InstancesSetMachineTypeRequest;
import com.google.cloud.compute.v1.Operation;
import com.google.cloud.compute.v1.SetMachineTypeInstanceRequest;
import com.google.cloud.compute.v1.StopInstanceRequest;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class UpdateMemory {

  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-google-cloud-project-id";
    // Name of the zone to create the instance in. For example: "us-west3-b".
    String zone = "google-cloud-zone";
    // Name of the new virtual machine (VM) instance.
    String instanceName = "instance-name";
    // The amount of memory for the VM instance, in megabytes.
    int newMemory = 256;

    modifyInstanceWithExtendedMemory(projectId, zone, instanceName, newMemory);
  }

  // Modify an existing VM to use extended memory and return the modified Instance.
  public static void modifyInstanceWithExtendedMemory(
      String project, String zone, String instanceName, int newMemory)
      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()) {

      // Create the get instance request object.
      GetInstanceRequest getInstanceRequest = GetInstanceRequest.newBuilder()
          .setProject(project)
          .setZone(zone)
          .setInstance(instanceName)
          .build();

      Instance instance = instancesClient.get(getInstanceRequest);

      // Check the machine type.
      if (!(instance.getMachineType().contains("machineTypes/n1-")
          || instance.getMachineType().contains("machineTypes/n2-")
          || instance.getMachineType().contains("machineTypes/n2d-"))) {
        System.out.println("extra memory is available only for N1, N2 and N2D CPUs");
        return;
      }

      // Make sure that the machine is turned off.
      if (!(instance.getStatus().equals(Status.TERMINATED.toString())
          || instance.getStatus().equals(Status.STOPPED.toString()))) {

        StopInstanceRequest stopInstanceRequest = StopInstanceRequest.newBuilder()
            .setProject(project)
            .setZone(zone)
            .setInstance(instanceName)
            .build();

        OperationFuture<Operation, Operation> operation = instancesClient.stopAsync(
            stopInstanceRequest);
        Operation response = operation.get(3, TimeUnit.MINUTES);
        if (response.hasError()) {
          System.out.printf("Unable to stop instance %s", response.getError());
          return;
        }
      }

      // Modify the machine definition. Note that extended memory
      // is available only for N1, N2 and N2D CPUs.
      String machineType = instance.getMachineType();
      String start = machineType.substring(0, machineType.lastIndexOf("-"));

      // Create the machine type instance request object.
      SetMachineTypeInstanceRequest setMachineTypeInstanceRequest =
          SetMachineTypeInstanceRequest.newBuilder()
              .setProject(project)
              .setZone(zone)
              .setInstance(instanceName)
              .setInstancesSetMachineTypeRequestResource(InstancesSetMachineTypeRequest.newBuilder()
                  .setMachineType(String.format("%s-%d-ext", start, newMemory))
                  .build())
              .build();

      // Invoke the API with the request object and wait for the operation to complete.
      Operation response = instancesClient.setMachineTypeAsync(setMachineTypeInstanceRequest)
          .get(3, TimeUnit.MINUTES);

      // Check for errors.
      if (response.hasError()) {
        System.out.printf("Unable to update instance %s", response.getError());
        return;
      }
      System.out.println("Instance updated!");
    }
  }
}

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 newMemory = 256;

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

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

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

  if (
    !['machineTypes/n1-', 'machineTypes/n2-', 'machineTypes/n2d-'].some(
      type => instance.machineType.includes(type)
    )
  ) {
    throw new Error('extra memory is available only for N1, N2 and N2D CPUs');
  }

  // Make sure that the machine is turned off
  if (!['TERMINATED', 'STOPPED'].some(status => instance.status === status)) {
    const [response] = await instancesClient.stop({
      project: projectId,
      zone,
      instance: instanceName,
    });

    let operation = response.latestResponse;
    const operationsClient = new compute.ZoneOperationsClient();

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

  // Modify the machine definition, remember that extended memory
  // is available only for N1, N2 and N2D CPUs

  const start = instance.machineType.substring(
    0,
    instance.machineType.lastIndexOf('-')
  );

  const [response] = await instancesClient.setMachineType({
    project: projectId,
    zone,
    instance: instanceName,
    instancesSetMachineTypeRequestResource: {
      machineType: `${start}-${newMemory}-ext`,
    },
  });
  let operation = response.latestResponse;
  const operationsClient = new compute.ZoneOperationsClient();

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

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

modifyInstanceWithExtendedMemory();

Python

在試用這個範例之前,請先按照「使用用戶端程式庫的 Compute Engine 快速入門導覽課程」中的 Python 設定操作說明進行操作。詳情請參閱 Compute Engine Python API 參考文件。

如要向 Compute Engine 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。

from __future__ import annotations

import sys
import time
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 add_extended_memory_to_instance(
    project_id: str, zone: str, instance_name: str, new_memory: int
):
    """
    Modify an existing VM to use extended memory.

    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.
        new_memory: the amount of memory for the VM instance, in megabytes.

    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()
    instance = instance_client.get(
        project=project_id, zone=zone, instance=instance_name
    )

    if not (
        "n1-" in instance.machine_type
        or "n2-" in instance.machine_type
        or "n2d-" in instance.machine_type
    ):
        raise RuntimeError("Extra memory is available only for N1, N2 and N2D CPUs.")

    # Make sure that the machine is turned off
    if instance.status not in (
        instance.Status.TERMINATED.name,
        instance.Status.STOPPED.name,
    ):
        operation = instance_client.stop(
            project=project_id, zone=zone, instance=instance_name
        )
        wait_for_extended_operation(operation, "instance stopping")
        start = time.time()
        while instance.status not in (
            instance.Status.TERMINATED.name,
            instance.Status.STOPPED.name,
        ):
            # Waiting for the instance to be turned off.
            instance = instance_client.get(
                project=project_id, zone=zone, instance=instance_name
            )
            time.sleep(2)
            if time.time() - start >= 300:  # 5 minutes
                raise TimeoutError()

    # Modify the machine definition, remember that extended memory is available only for N1, N2 and N2D CPUs
    start, end = instance.machine_type.rsplit("-", maxsplit=1)
    instance.machine_type = start + f"-{new_memory}-ext"
    # TODO: If you prefer to use the CustomMachineType helper class, uncomment this code and comment the 2 lines above
    # Using CustomMachineType helper
    # cmt = CustomMachineType.from_str(instance.machine_type)
    # cmt.memory_mb = new_memory
    # cmt.extra_memory_used = True
    # instance.machine_type = str(cmt)
    operation = instance_client.update(
        project=project_id,
        zone=zone,
        instance=instance_name,
        instance_resource=instance,
    )
    wait_for_extended_operation(operation, "instance update")

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

REST

  1. 呼叫 instances.stop 方法停止 VM。
  2. 呼叫 instances.setMachineType 方法,並在 machineType 欄位中指定 -ext 後置字串,即可更新機器類型資源:

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME/setMachineType
    
    {
      "machineType": "zones/ZONE/machineTypes/MACHINE_SERIES-custom-NUMBER_OF_VCPUS-AMOUNT_OF_MEMORY_MB-ext"
    }
    

    更改下列內容:

    • PROJECT_ID:包含 VM 的專案 ID。
    • ZONE:VM 所在的可用區。
    • INSTANCE_NAME:VM 的名稱。
    • MACHINE_SERIES:小寫機器系列,例如 n4、n4d、n4a、n2 或 n2d。如果是 N1,請省略 MACHINE_SERIES-,並從 custom- 開始。
    • NUMBER_OF_VCPUS:vCPU 數量。
    • AMOUNT_OF_MEMORY_MB:記憶體總量,以 MB 為單位。這個值必須是 256 MB 的整數倍。
  3. 呼叫 instances.start 方法,重新啟動 VM。

後續步驟