将自定义映像导出到 Cloud Storage


如需将 Compute Engine 启动磁盘数据移出 Compute Engine 项目,您可以将启动磁盘映像以 tar.gz 文件导出到 Cloud Storage。如需在 Compute Engine 上创建新的永久性磁盘时创建要使用的永久性磁盘映像,请参阅创建自定义映像

您可以通过将自定义映像导出到 Cloud Storage 来备份或共享该映像。如果您需要与无法访问您的映像的项目共享个别映像,此方法非常适合。您也可以选择通过在映像上或其所属的项目上授予 Compute Engine 映像用户角色来共享映像。

下图显示了创建和重用自定义映像的一些典型工作流。

创建和重用自定义映像。
图 1:自定义映像的创建和重用示例

准备工作

局限和限制

对于使用 VPC Service Controls 保护的项目,请使用以下方法之一:

  • 从映像所在的项目导出
  • 手动导出映像

使用单个命令导出映像

将映像导出到 Cloud Storage

您可以使用 Google Cloud ConsoleGoogle Cloud CLICloud Build API 导出映像。

控制台

  1. 在 Google Cloud Console 中,转到映像页面。

    转到“映像”

  2. 点击要导出的映像的名称,以转到映像详情页面。您无法导出 Google 提供的公共映像。您只能导出之前创建或导入的映像。

  3. 在映像详情页面中,点击导出以打开导出映像页面。

  4. 导出映像页面上,选择映像的导出格式

  5. 点击浏览以选择导出映像的目标 Cloud Storage 位置。

  6. 选择现有 Cloud Storage 位置以导出映像。或者,按照说明创建新的 Cloud Storage 存储分区,然后输入新 Cloud Storage 存储分区的名称。

  7. 选择 Cloud Storage 后,请为导出的映像选择一个文件名。您可以使用默认文件名,也可以选择自己的文件名。

  8. 选择 Cloud Storage 并为映像输入文件名后,点击选择

  9. 导出映像页面中,点击导出。选择导出后,Google Cloud 控制台将显示映像导出历史记录,您可以在其中查看映像导出过程。如需详细了解映像导出过程,请点击 Cloud Build ID 以转到映像导出详情页面,您可以在其中查看和下载映像导出日志。

  10. 转到 Storage 以访问导出的映像。

    转到 Storage

gcloud

如需将映像导出到 Cloud Storage,首选方法是使用 gcloud compute images export 命令。此命令使用 Daisy 将导出映像所需的多个步骤串联起来。此命令假定您已经创建了一个映像(例如,使用 gcloud compute images create 命令创建了映像)。

使用 Google Cloud CLI 运行以下命令:

gcloud compute images export \
    --destination-uri DESTINATION_URI \
    --image IMAGE_NAME

替换以下内容:

  • DESTINATION_URI:导出的映像文件的目标 Cloud Storage URI。
  • IMAGE_NAME:要导出的磁盘映像的名称。

默认情况下,映像以 Compute Engine 格式导出,即经过 tar 和 gzip 压缩的 disk.raw 文件。如需将映像导出为 QEMU 磁盘映像实用程序支持的其他格式,您可以使用 --export-format 标志。有效格式包括 vmdkvhdxvpcvdiqcow2

示例

例如,以下命令会将名为 my-image 的映像从 my-project 导出到名为 my-bucket 的 Cloud Storage 存储分区。默认情况下,映像会以 disk.raw file 的形式导出,并压缩为 tar.gz 文件格式。

gcloud compute images export \
    --destination-uri gs://my-bucket/my-image.tar.gz \
    --image my-image \
    --project my-project

如需了解标志,请参阅 gcloud compute images export 参考文档。

API

在 API 中,创建一个指向 Cloud Build API 的 POST 请求。

POST https://cloudbuild.googleapis.com/v1/projects/PROJECT_ID/builds
{
  "timeout": "7200s",
  "steps":[
    {
      "args":[
        "-timeout=7000s",
        "-source_image=SOURCE_IMAGE",
        "-client_id=api",
        "-format=IMAGE_FORMAT",
        "-destination_uri=DESTINATION_URI"
      ],
      "name":"gcr.io/compute-image-tools/gce_vm_image_export:release",
      "env":[
        "BUILD_ID=$BUILD_ID"
      ]
    }
  ],
  "tags":[
    "gce-daisy",
    "gce-daisy-image-export"
  ]
}

请替换以下内容:

  • PROJECT_ID:要导出的映像所属项目的 ID。
  • SOURCE_IMAGE:要导出的映像的名称。
  • IMAGE_FORMAT:已导出映像的格式。有效格式包括 vmdkvhdxvpcvdiqcow2
  • DESTINATION_URI:要将映像文件导出到的 Cloud Storage URI 位置。例如 gs://my-bucket/my-exported-image.vmdk

如需查看可提供的其他 args 值,请参阅虚拟机映像导出 GitHub 页面的“可选标志”部分。

示例响应

以下示例响应类似于返回的输出:

{
"name": "operations/build/myproject-12345/operation-1578608233418",
"metadata": {
 "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.BuildOperationMetadata",
 "build": {
  "id": "3a2055bc-ccbd-4101-9434-d376b88b8940",
  "status": "QUEUED",
  "createTime": "2019-10-02T18:59:13.393492020Z",
  "steps": [
   {
    "name": "gcr.io/compute-image-tools/gce_vm_image_export:release",
    "env": [
     "BUILD_ID=3a2055bc-ccbd-4101-9434-d376b88b8940"
    ],
    "args": [
     "-timeout=7056s",
     "-source_image=my-image",
     "-client_id=api",
     "-format=vmdk",
     "-destination_uri=gs://my-bucket/my-exported-image.vmdk"
    ]
   }
  ],
  "timeout": "7200s",
  "projectId": "myproject-12345",
  "logsBucket": "gs://123456.cloudbuild-logs.googleusercontent.com",
  "options": {
   "logging": "LEGACY"
  },
  "logUrl": "https://console.cloud.google.com/cloud-build/builds/3a2055bc-ccbd-4101-9434-d376b88b8940?project=123456"
 }
 }

您可以通过以下几种方式监控您的版本:

  • 使用返回的 build-id 运行 projects.builds.get 请求。
  • 查看在提供的 logUrl 下托管的日志。

使用自定义 Compute Engine 服务帐号从项目导出映像

在映像导出期间,系统会在您的项目中创建临时虚拟机 (VM)。此临时虚拟机上的映像导出工具必须经过身份验证。

服务帐号是关联到虚拟机的身份。服务帐号访问令牌可通过实例元数据服务器访问,用于对虚拟机上的映像导出工具进行身份验证。

默认情况下,导出过程使用项目的默认 Compute Engine 服务代理。但是,如果您在项目中停用了默认 Compute Engine 服务帐号,或者如果要使用自定义 Compute Engine 服务帐号,则需要创建服务帐号并针对导出过程指定该帐号。

您可以使用 Google Cloud CLICloud Build API 导出映像。

gcloud

  1. 创建服务帐号并分配最小角色。如需详细了解如何创建服务帐号,请参阅创建和管理服务帐号

    指定的 Compute Engine 服务帐号必须至少具有以下角色:

    • roles/compute.storageAdmin
    • roles/storage.objectAdmin

    如需了解详情,请参阅为 Compute Engine 服务帐号授予所需的角色

  2. 使用 gcloud compute images export 命令导出映像。

    gcloud compute images export \
        --destination-uri DESTINATION_URI \
        --image IMAGE_NAME \
        --compute-service-account SERVICE_ACCOUNT_EMAIL

    请替换以下内容:

    • DESTINATION_URI:导出的映像文件的目标 Cloud Storage URI。
    • IMAGE_NAME:要导出的磁盘映像的名称。
    • SERVICE_ACCOUNT_EMAIL:与上一步中创建的 Compute Engine 服务帐号关联的电子邮件地址。

示例

例如,以下命令使用具有电子邮件地址 image-export-service-account@proj-12345.iam.gserviceaccount.com 的服务帐号,将名为 my-image 的映像从 my-project 导出到名为 my-bucket 的 Cloud Storage 存储分区。默认情况下,映像会以 disk.raw 文件的形式导出,并压缩为 tar.gz 文件格式。

gcloud compute images export \
    --destination-uri gs://my-bucket/my-image.tar.gz \
    --image my-image \
    --project my-project \
    --compute-service-account image-export-service-account@proj-12345.iam.gserviceaccount.com
    

如需了解标志,请参阅 gcloud compute images export 参考文档。

API

  1. 创建服务帐号并分配最小角色。如需详细了解如何创建服务帐号,请参阅创建和管理服务帐号

    指定的 Compute Engine 服务帐号必须至少具有以下角色:

    • roles/compute.storageAdmin
    • roles/storage.objectAdmin

    如需了解详情,请参阅为 Compute Engine 服务帐号授予所需的角色

  2. 在 API 中,创建一个指向 Cloud Build API 的 POST 请求。

    POST https://cloudbuild.googleapis.com/v1/projects/PROJECT_ID/builds
    {
      "timeout": "7200s",
      "steps":[
        {
          "args":[
            "-timeout=7000s",
            "-source_image=SOURCE_IMAGE",
            "-client_id=api",
            "-format=IMAGE_FORMAT",
            "-destination_uri=DESTINATION_URI",
            "-compute_service_account=SERVICE_ACCOUNT_EMAIL"
          ],
          "name":"gcr.io/compute-image-tools/gce_vm_image_export:release",
          "env":[
            "BUILD_ID=$BUILD_ID"
          ]
        }
      ],
      "tags":[
        "gce-daisy",
        "gce-daisy-image-export"
      ]
    }
    

    请替换以下内容:

    • PROJECT_ID:要导出的映像所属项目的 ID。
    • SOURCE_IMAGE:要导出的映像的名称。
    • IMAGE_FORMAT:已导出映像的格式。有效格式包括 vmdkvhdxvpcvdiqcow2
    • DESTINATION_URI:要将映像文件导出到的 Cloud Storage URI 位置。例如 gs://my-bucket/my-exported-image.vmdk
    • SERVICE_ACCOUNT_EMAIL:与上一步中创建的 Compute Engine 服务帐号关联的电子邮件地址。

如需查看可提供的其他 args 值,请参阅虚拟机映像导出 GitHub 页面的“可选标志”部分。

使用共享 VPC 导出映像

在导出使用共享 VPC 的映像之前,您必须为 Cloud Build 服务帐号添加 compute.networkUser 角色。如需了解详情,请参阅为 Cloud Build 服务帐号授予所需的角色

您可以使用 Google Cloud CLICloud Build API 导出映像。

gcloud

使用 gcloud compute images export 命令导出映像。

gcloud compute images export \
    --image IMAGE_NAME \
    --destination-uri DESTINATION_URI \
    --project PROJECT_ID \
    --network NETWORK \
    [--subnet SUBNET \]
    [--zone ZONE]

请替换以下内容:

  • IMAGE_NAME:要导出的映像的名称。
  • DESTINATION_URI:要将映像文件导出到的 Cloud Storage URI 位置。
  • PROJECT_ID:映像所在项目的 ID。
  • NETWORK共享 VPC 网络的完整路径,例如 projects/HOST_PROJECT_ID/global/networks/VPC_NETWORK_NAME
  • SUBNET共享 VPC 子网的完整路径,例如 projects/HOST_PROJECT_ID/regions/REGION/subnetworks/SUBNET_NAME

    指定此模式取决于 VPC 网络模式。

    • 如果 VPC 网络使用旧版模式,请勿指定子网。
    • 如果 VPC 网络使用自动模式,则可以指定子网。
    • 如果 VPC 网络使用自定义模式,则必须指定此字段。
  • ZONE:要用于导出的可用区。此区域必须与子网的地区相匹配。例如,如果 SUBNET 位于 us-west1 区域,则导出可用区必须是以下各项之一:us-west1-aus-west1-bus-west1-c

    在大多数情况下,指定可用区是可选操作。如果指定了 SUBNET,则必须指定可用区。

例如,以下命令会将名为 example-image 的映像从 my-project 导出到名为 my-bucket 的 Cloud Storage 存储分区。在此示例中,Virtual Private Cloud 网络 (my-shared-vp) 使用自定义子网 (my-custom-subnet)。默认情况下,映像会以 disk.raw 文件形式导出,并压缩为 tar.gz 文件格式。

示例命令

gcloud compute images export \
    --image example-image \
    --destination-uri gs://my-bucket/my-image.tar.gz \
    --project my-project \
    --network projects/my-vpc-project/global/networks/my-shared-vpc \
    --subnet projects/my-vpc-project/regions/us-west1/subnetworks/my-custom-subnet \
    --zone us-west1-c
 

API

  1. 将映像添加到 Cloud Storage

  2. 在 API 中,创建一个指向 Cloud Build API 的 POST 请求。

    POST https://cloudbuild.googleapis.com/v1/projects/PROJECT_ID/builds
    {
      "timeout": "7200s",
      "steps":[
        {
          "args":[
            "-timeout=7000s",
            "-source_image=SOURCE_IMAGE",
            "-client_id=api",
            "-format=IMAGE_FORMAT",
            "-destination_uri=DESTINATION_URI",
            "-network=NETWORK",
            "-subnet=SUBNET",
            "-zone=ZONE"
          ],
          "name":"gcr.io/compute-image-tools/gce_vm_image_export:release",
          "env":[
            "BUILD_ID=$BUILD_ID"
          ]
        }
      ],
      "tags":[
        "gce-daisy",
        "gce-daisy-image-export"
      ]
    }
    

    请替换以下内容:

    • PROJECT_ID:要导出的映像所属项目的 ID。
    • SOURCE_IMAGE:要导出的映像的名称。
    • IMAGE_FORMAT:已导出映像的格式。 有效格式包括 vmdkvhdxvpcvdiqcow2
    • DESTINATION_URI:要将映像文件导出到的 Cloud Storage URI 位置。例如 gs://my-bucket/my-exported-image.vmdk
    • NETWORK共享 VPC 网络的完整路径,例如 projects/HOST_PROJECT_ID/global/networks/VPC_NETWORK_NAME
    • SUBNET共享 VPC 子网的完整路径,例如 projects/HOST_PROJECT_ID/regions/REGION/subnetworks/SUBNET_NAME

      指定此模式取决于 VPC 网络模式。

      • 如果 VPC 网络使用旧版模式,请勿指定子网。
      • 如果 VPC 网络使用自动模式,则可以指定子网。
      • 如果 VPC 网络使用自定义模式,则必须指定此字段。
    • ZONE:要用于导出的可用区。此区域必须与子网的地区相匹配。例如,如果 SUBNET 位于 us-west1 区域,则导出可用区必须是以下各项之一:us-west1-aus-west1-bus-west1-c

      在大多数情况下,指定可用区是可选操作。如果指定了 SUBNET,则必须指定可用区。

    如需查看可提供的其他 args 值,请参阅虚拟机映像导出 GitHub 页面的“可选标志”部分。

手动创建和导出映像

如果 gcloud compute images creategcloud compute images export 命令不符合您的要求,您可以在 Compute Engine 实例中手动创建和导出映像。此过程包含多个独立步骤,您可以先创建一个映像,然后导出一个映像。

在以下示例中,请注意创建的磁盘名为 image-disk

要创建和导出映像,请执行以下操作:

  1. 可选:在创建快照之前,先停止挂接了磁盘的实例。停止实例可确保快照中磁盘内容的完整性。 将 DISK_NAME 替换为要用于创建快照的磁盘的名称。

  2. 创建磁盘的快照,将该快照命名为 image-snapshot

    gcloud compute disks snapshot DISK_NAME \
        --snapshot-names image-snapshot
  3. 通过运行以下命令,使用 image-snapshot 快照创建一个名为 image-disk 的新磁盘:

    gcloud compute disks create image-disk \
        --source-snapshot image-snapshot
  4. 创建一个名为 temporary-disk 的临时磁盘来保存 tar 文件,并将该磁盘的 SIZE 指定为至少比映像磁盘大 50%。

    之后,您可以分离并删除磁盘。

    gcloud compute disks create temporary-disk \
        --size SIZE

    其中,SIZE 是临时磁盘的大小(以千兆字或太字节为单位)。例如,指定 100GB 可创建一个 100 千兆字节的磁盘。

  5. 创建实例并在实例上启用 storage-rw 范围。另外,将 image-disktemporary-disk 挂接到实例,以作为具有特定 device-name 属性的辅助磁盘。将 VM_NAME 替换为要创建的实例的名称。

    gcloud compute instances create VM_NAME \
        --scopes storage-rw \
        --disk name=image-disk,device-name=image-disk \
        --disk name=temporary-disk,device-name=temporary-disk

    请注意,您正在传入服务帐号范围,以便在后续步骤中将文件上传到 Cloud Storage。

    如有必要,请查看有关启动新实例的详情。

  6. 连接到您的实例。 将 VM_NAME 替换为要连接的实例的名称。

    gcloud compute ssh VM_NAME
  7. 格式化并装载临时磁盘。格式化磁盘将删除临时磁盘的内容。

    sudo mkdir /mnt/tmp
    sudo mkfs.ext4 -F /dev/disk/by-id/google-temporary-disk
    sudo mount -o discard,defaults /dev/disk/by-id/google-temporary-disk /mnt/tmp
  8. 可选:在创建 tar 文件之前,先装载映像磁盘并进行其他更改。例如,如果您不希望任何现有的文件包含在映像中,则建议您从 /home 目录中删除这些文件。装载需要修改的磁盘分区,修改磁盘上需要更改的文件,然后在完成这些操作后卸载磁盘。

    1. 创建一个可以装载磁盘或分区的目录。

      sudo mkdir /mnt/image-disk
    2. 使用 ls 命令确定您需要装载的具体磁盘或磁盘分区。

      ls /dev/disk/by-id/

      该命令会输出磁盘 ID 和分区的列表。例如,以下磁盘具有一个分区表,其中包含一个分区。google-image-disk ID 指向您要从中创建映像的完整磁盘,而 google-image-disk-part1 ID 指向该磁盘上的第一个分区。如果需要更改磁盘,请装载分区,然后从完整磁盘创建映像。

      google-image-disk
      google-image-disk-part1
      
    3. 装载磁盘或分区。如果您的磁盘具有分区表,请装载磁盘的各个分区。例如,装载 google-image-disk-part1

      sudo mount /dev/disk/by-id/google-image-disk-part1 /mnt/image-disk

      或者,如果您的磁盘采用了 raw 格式,并且没有分区表,请装载完整的 google-image-disk 磁盘。

      sudo mount /dev/disk/by-id/google-image-disk /mnt/image-disk
    4. 修改 /mnt/image-disk 目录中的文件以配置磁盘上的文件。例如,您可以移除 /mnt/image-disk/home/[USER]/.ssh/authorized_keys 文件以保护您的 SSH 密钥不被共享。

    5. 修改完文件之后,卸载磁盘。

      sudo umount /mnt/image-disk/
  9. 为您的映像创建一个 tar 文件。

    完成对映像磁盘上的文件的自定义操作后,请在临时磁盘上创建原始磁盘文件。请注意,该原始磁盘映像的名称必须为“disk.raw”,如下所示:

     sudo dd if=/dev/disk/by-id/google-image-disk of=/mnt/tmp/disk.raw bs=4096

    然后创建 tar.gz 文件:

    cd /mnt/tmp

    sudo tar czvf myimage.tar.gz disk.raw

    此命令会在以下位置创建实例的映像:

    /mnt/tmp/myimage.tar.gz

  10. 将映像上传到 Cloud Storage。

    如需将 tar 文件上传到 Cloud Storage,请使用预安装在您的实例上的 gsutil 命令行工具。

    1. 使用 gsutil 创建存储分区。

      在创建存储分区之前,请务必查看存储分区和对象命名准则。然后,使用以下命令创建您的存储分区:将 BUCKET_NAME 替换为要创建的存储分区的名称。

      me@example-instance:~$ 
      gsutil mb gs://BUCKET_NAME
    2. 将您的文件复制到新的存储分区中。将 BUCKET_NAME 替换为要将文件复制到其中的存储分区的名称。

      me@example-instance:~$ 
      gsutil cp /mnt/tmp/myimage.tar.gz gs://BUCKET_NAME

您的文件现已导出到 Cloud Storage。您现在可以与其他人共享映像,或使用 tar 文件将新映像添加到 Google Cloud 控制台项目中。

后续步骤