This document describes how to create a custom image for use with Google Distributed Cloud (GDC) air-gapped virtual machine (VM) instances.
You can create custom images from existing source disks and use them to create and start virtual machines (VMs). Custom images are ideal for when you create and modify a persistent boot disk to a certain state and need to save that state for creating VMs. Creating and saving a custom image to use as a new VM image in future VM creation prevents duplicating your setup steps later.
This document is for developers in platform administrator or application operator groups that create VMs and manage VM images in a Google Distributed Cloud (GDC) air-gapped environment. For more information, see Audiences for GDC air-gapped documentation.
Before you begin
To use gdcloud command-line interface (CLI) commands, ensure that you have downloaded, installed,
and configured the gdcloud CLI.
All commands for Distributed Cloud use the gdcloud or
kubectl CLI, and require an operating system (OS) environment.
Get the kubeconfig file path
To run commands against the Management API server, ensure you have the following resources:
Sign in and generate the kubeconfig file for the Management API server if you don't have one.
Use the path to the kubeconfig file of the Management API server to replace
MANAGEMENT_API_SERVERin these instructions.
Request IAM roles
Contact your Project IAM Admin to request the following roles on your project:
Virtual Machine Project Admin (
project-vm-admin): create, modify, list, and delete VMs in the project namespace.Project Viewer(
project-viewer): view all resources within the project namespaces.Virtual Machine Image Project Admin (
project-vm-image-admin): create, list, and delete custom VM images in the project namespace.
All VM roles must bind to the namespace of the project where the VM resides. Follow the steps to verify your access.
Create a custom image
This section describes how to create a custom image on a VM.
Prepare your VM for an image
You can create an image from a disk while it is attached to a running VM. However, your image is more reliable if you put the VM into a state for the image to capture.
Stop writing data to the persistent disk
Stop the VM so that it can shut down and stop writing any data to the persistent disk.
Create the image
Follow these steps to create disk images from a persistent disk, even while that disk is attached to a VM:
Console
Select a project.
In the navigation menu, click Virtual Machines > Images.
Click Create Image.
Enter a unique name for the image. The name must be no longer than 35 characters.
Enter a version to add to the image name.
In the Source Disk field, select a disk.
In the Minimum Disk Size field, enter a disk size.
Enter a description of the image.
Click Create.
The image appears in the list of images.
API
List all
VirtualMachineDiskobjects:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachinedisks.virtualmachine.gdc.googSelect a
VirtualMachineDiskobject to use as source disk for the new image.Check whether the VM disk is attached to a VM:
kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachinedisks.virtualmachine.gdc.goog DISK_NAME \ -o jsonpath='{.status.virtualMachineAttachments}'The following example output shows a disk attached to a VM:
[{"autoDelete":true,"nameRef":{"name":"vm1"},"uid":"...."}]- If the output returns a value for
"name", the disk is attached to a VM signified by thenamefield. In this example, thenamevalue isvm1. Proceed to check the VM's running status. - If the output is empty, proceed to get the
sizeof theVirtualMachineDisk.
- If the output returns a value for
Check the VM's running status. If the status is not
Stopped, Stop the VM and proceed with creating theVirtualMachineImage.Get the
sizeofVirtualMachineDiskto create the image:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachinedisks.virtualmachine.gdc.goog DISK_NAME \ -o jsonpath='{.spec.size}'Create a
VirtualMachineImageImportobject and deploy it to the Management API server:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ apply -f - <<EOF apiVersion: virtualmachine.gdc.goog/v1 kind: VirtualMachineImageImport metadata: name: VM_IMAGE_IMPORT_NAME spec: source: diskRef: name: DISK_NAME imageMetadata: name: IMAGE_NAME operatingSystem: OS_NAME minimumDiskSize: MINIMUM_DISK_SIZE EOFVerify that the image import has finished and the status is
Ready:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachineimageimports.virtualmachine.gdc.goog VM_IMAGE_IMPORT_NAME \ -o jsonpath='{.status}'When the import is complete, the status output looks similar to the following:
{ "conditions": [ { "lastTransitionTime": "", "message": "", "observedGeneration": 1, "reason": "ImportJobComplete", "status": "True", "type": "Ready" } ], "imageName": IMAGE_NAME }Verify the image has been created:
kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachineimages.virtualmachine.gdc.goog \ CREATED_IMAGE_NAMEReplace the variables using the following definitions.
Variable Definition MANAGEMENT_API_SERVERThe Management API server kubeconfig file. PROJECTThe GDC project in which to create the image. DISK_NAMEThe name of the source disk, such as vm1-boot-disk.VM_IMAGE_IMPORT_NAMEThe name of the VM image import. The name must be no longer than 35 characters. IMAGE_NAMEThe name of the created image, such as custom-image.OS_NAMEThe name of the image OS, must be one of these four: ubuntu-2004,windows-2019,windows-2022, orrhel-8.MINIMUM_DISK_SIZEThe minimum disk size in the VM image import, such as 20G:
minimumDiskSizemust always be greater than or equal to the source boot disk size.CREATED_IMAGE_NAMEThe name of the created image. The created image name must be unique; you cannot use an image name that already exists in the project.
Terraform
List all
VirtualMachineDiskobjects:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachinedisks.virtualmachine.gdc.googSelect a
VirtualMachineDiskobject to use as source disk for the new image.Check whether the VM disk is attached to a VM:
kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachinedisks.virtualmachine.gdc.goog DISK_NAME \ -o jsonpath='{.status.virtualMachineAttachments}'Example output showing a disk is attached to a VM:
[{"autoDelete":true,"nameRef":{"name":"vm1"},"uid":"...."}]- If the output returns a value for
"name", the disk is attached to a VM signified by thenamefield. In this example output, thenamevalue isvm1. Proceed to check the VM's running status. - If the output is empty, proceed to get the
sizeof theVirtualMachineDisk.
- If the output returns a value for
Check the VM's running status. If the status is not
Stopped, Stop the VM and proceed with creating theVirtualMachineImage.Get the
sizeofVirtualMachineDiskto create the image:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachinedisks.virtualmachine.gdc.goog DISK_NAME \ -o jsonpath='{.spec.size}'Create a file named
main.tfwith the following content:provider "kubernetes" { config_path = "MANAGEMENT_API_SERVER" } resource "kubernetes_manifest" "image_import" { manifest = { "apiVersion" = "virtualmachine.gdc.goog/v1" "kind" = "VirtualMachineImageImport" "metadata" = { "name" = "VM_IMAGE_IMPORT_NAME" "namespace" = "PROJECT" } "spec" = { "source" = { "diskRef" = { "name" = "DISK_NAME" } } "imageMetadata" = { "name" = "IMAGE_NAME" "operatingSystem" = "OS_NAME" "minimumDiskSize" = "MINIMUM_DISK_SIZE" } } } }Apply the
VirtualMachineImageImportobject using Terraform:terraform applyVerify that the image import has finished and the status is
Ready:kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachineimageimports.virtualmachine.gdc.goog VM_IMAGE_IMPORT_NAME \ -o jsonpath='{.status}'The status should look like this when the import is complete:
{ "conditions": [ { "lastTransitionTime": "", "message": "", "observedGeneration": 1, "reason": "ImportJobComplete", "status": "True", "type": "Ready" } ], "imageName": IMAGE_NAME }Verify the image has been created:
kubectl --kubeconfig MANAGEMENT_API_SERVER \ -n PROJECT \ get virtualmachineimages.virtualmachine.gdc.goog \ CREATED_IMAGE_NAMEReplace the variables, using the following definitions.
Variable Definition MANAGEMENT_API_SERVERThe Management API server kubeconfig file. PROJECTThe GDC project in which to create the image. DISK_NAMEThe name of the source disk, such as vm1-boot-disk.VM_IMAGE_IMPORT_NAMEThe name of the VM image import. The name must be no longer than 35 characters. IMAGE_NAMEThe name of the created image, such as custom-image.OS_NAMEThe name of the image OS, must be one of these four: ubuntu-2004,windows-2019,windows-2022, orrhel-8.MINIMUM_DISK_SIZEThe minimum disk size in the VM image import, such as 20G:
minimumDiskSizemust always be greater than or equal to the source boot disk size.CREATED_IMAGE_NAMEThe name of the created image. The created image name must be unique; you cannot use an image name that already exists in the project.