1. 概览
Confidential Space (CS) 提供了一个安全、经过证明且加密的环境来处理敏感数据。依赖于独立虚拟机实例会产生运维开销,因为手动编排缺乏任务关键型服务所需的可伸缩性。如果没有自动编排,在整个舰队中执行同步滚动更新或部署新的操作系统映像在技术上会变得非常困难,并且容易发生停机。
在此 Codelab 中,您将学习如何在托管式实例组 (MIG) 上部署 Confidential Space 工作负载。您还将学习如何使用健康检查启用自动修复功能、如何根据 CPU 利用率启用自动扩缩功能,以及如何针对操作系统映像和工作负载启用滚动更新。
本 Codelab 中展示的流程应有助于您为任务关键型长期运行的部署设置自己的可用于生产用途的安全 Confidential Space。
学习内容
- 如何为 Confidential Space 创建专用实例模板。
- 如何使用 Google Compute Engine 以及如何配置 MIG 和实例组
- 如何创建防火墙规则和健康检查以实现自动修复。
- 如何使用模板和健康检查配置可用区级 MIG。
- 如何为 MIG 设置自动扩缩。
- 如何使用脚本在 MIG 上为工作负载映像以及 Confidential Space 的新操作系统映像版本设置一键式操作系统映像更新
所需条件
- 启用了结算功能的 Google Cloud 项目。
- 熟悉文本编辑器、Docker 部署和 Bash 脚本
- 已安装 gcloud 命令行工具并已通过身份验证。
- 对 Compute Engine、Confidential Space、IAM、机密虚拟机、容器技术、远程代码库、服务账号、Cloud Run 和 Cloud Scheduler 有基本的了解
- 已构建并推送到 Artifact Registry 的 Confidential Space 工作负载容器映像。
2. Confidential Space 与 MIG 的搭配使用方式
使用托管式实例组 (MIG) 部署 Confidential Space 工作负载可让安全应用更强大、更具可伸缩性且更易于运行。
生产服务的安全性和运营需求在逻辑上分为两个组件。Confidential Space 通过在高度隔离、加密且经过证明的环境(称为可信执行环境 [TEE])中运行工作负载来提供必要的安全性。相比之下,MIG 提供大规模运行安全应用所需的基本运维功能,与 Kubernetes 类似。MIG 可消除在单个虚拟机上运行任务关键型工作负载时固有的风险,因为单个虚拟机可能会运行缓慢或容易发生故障。这种组合可确保数据保护和系统可靠性。此解决方案可确保高可用性和自动修复,因为工作负载在池中的多个虚拟机上运行。如果一个虚拟机崩溃,由于负载均衡和剩余实例的存在,服务仍可正常运行。
此外,MIG 还利用可配置的健康检查来持续监控虚拟机的运行状态。如果发现某个实例的健康状况不佳,MIG 会自动将其替换为新的健康虚拟机,从而保证持续运行。
MIG 还通过自动扩缩功能为用户提供有效的可伸缩性。此功能提供了一种自动管理容量的方法,无需人工干预,可根据利用率灵活地添加或移除容量。
最后,MIG 可通过滚动更新实现零停机时间更新。一个主要优势是能够“一键升级”底层 Confidential Space 操作系统映像或应用的容器映像(或两者),而不会导致任何服务中断。MIG 会通过逐步将旧实例替换为运行更新后映像的新实例来管理此更改,从而确保在整个部署过程中始终保持可用性。请注意,您的应用可能需要向后兼容,才能支持这种类型的逐步升级。
3. 设置云资源
准备工作
- 设置 Google Cloud 项目。如需详细了解如何创建 Google Cloud 项目,请参阅 “设置并浏览您的第一个 Google 项目”Codelab。您可以参阅创建和管理项目,详细了解如何检索项目 ID,以及项目 ID 与项目名称和项目编号有何不同。
- 为您的项目启用结算功能。
- 在您的某个 Google 项目的 Cloud Shell 中,设置所需的项目环境变量,如下所示。
export CURRENT_PROJECT_ID=<Google Cloud project id of current project>
- 为您的项目启用机密计算 API 和以下 API。
gcloud config set project $CURRENT_PROJECT_ID
gcloud services enable \
cloudapis.googleapis.com \
container.googleapis.com \
artifactregistry.googleapis.com \
confidentialcomputing.googleapis.com \
compute.googleapis.com \
logging.googleapis.com \
run.googleapis.com \
cloudscheduler.googleapis.com
- 在 Google Cloud 项目 Cloud Shell 中,克隆 Confidential Space Codelab Github 代码库,然后使用以下命令获取完成此 Codelab 所需的相应脚本。
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
- 将目录更改为实例组 Codelab 的脚本目录
cd confidential-space/codelabs/mig_cs_codelab/scripts
- 更新 config_env.sh 中的项目 ID 行,以反映所选项目的 ID。
- 设置任何预先存在的变量。使用这些变量替换资源名称
- 您可以使用现有的云资源名称设置以下变量。如果设置了该变量,则会使用项目中的相应现有云资源。如果未设置,则云资源名称将来自 config_env.sh 脚本
- 运行 config_env.sh 脚本,将此项目的其余变量名称设置为基于资源名称的项目 ID 的值
source config_env.sh
- 为项目添加权限。如需添加权限,请按照授予 IAM 角色网页上的详细说明操作。
您需要拥有此项目的以下权限
- Artifact Registry Writer
- Cloud Scheduler Admin
- Compute 服务代理
- 机密计算工作负载用户
- 日志写入者
- Cloud Run Developer
- Cloud Run Invoker
gcloud config set project $CURRENT_PROJECT_ID
# Add Artifact Registry Writer role
gcloud projects add-iam-policy-binding $CURRENT_PROJECT_ID --member="serviceAccount:${CURRENT_WORKLOAD_SERVICE_ACCOUNT}" --role='roles/artifactregistry.writer'
# Add Confidential Space Workload Userd
gcloud projects add-iam-policy-binding $CURRENT_PROJECT_ID --member="serviceAccount:${CURRENT_WORKLOAD_SERVICE_ACCOUNT}" --role='roles/confidentialcomputing.workloadUser'
# Add Logging Log Writer
gcloud projects add-iam-policy-binding $CURRENT_PROJECT_ID --member="serviceAccount:${CURRENT_WORKLOAD_SERVICE_ACCOUNT}" --role='roles/logging.logWriter'
# Add Cloud Run Developer
gcloud projects add-iam-policy-binding $CURRENT_PROJECT_ID --member="serviceAccount:${CURRENT_WORKLOAD_SERVICE_ACCOUNT}" --role='roles/run.developer'
# Add Cloud Run Invoker
gcloud projects add-iam-policy-binding $CURRENT_PROJECT_ID --member="serviceAccount:${CURRENT_WORKLOAD_SERVICE_ACCOUNT}" --role='roles/run.invoker'
# Add Cloud Scheduler Admin
gcloud projects add-iam-policy-binding $CURRENT_PROJECT_ID --member="serviceAccount:${CURRENT_WORKLOAD_SERVICE_ACCOUNT}" --role='roles/cloudscheduler.admin'
- 查看 test_workload.py
- 通过查看源代码来验证工作负载的输出,它应该只是输出工作负载的当前版本
- 当我们首次将工作负载推送到 CS 并检查输出时,应该会看到“版本 A”打印出来
4. 设置工作负载
您首先需要为本 Codelab 中使用的工作负载创建 Docker 映像。该工作负载是一个简单的脚本,用于输出您当前运行的工作负载的版本。它会打印出工作负载正在启动,然后打印出工作负载的版本,休眠 5 秒,然后打印出工作负载已完成。
创建工作负载的步骤
- 运行 create_workload.sh 以创建工作负载。此脚本:
- 创建由工作负载将发布到的项目所拥有的 Artifact Registry
- 构建代码并将其打包到 Docker 映像中。如需了解详情,请参阅相关的 Dockerfile 配置信息。
- 将 Docker 映像发布到项目拥有的 Artifact Registry
- 向服务账号 <您的服务账号名称> 授予对制品注册表 <制品注册表代码库名称> 的读取权限
5. 设置实例模板和 MIG
创建实例模板的步骤
您必须先创建实例模板。此模板是必需的蓝图,托管式实例组 (MIG) 将使用它在 Confidential Space 中预配和运行工作负载。
实例模板至关重要,因为它定义了所有专用参数:
- 机器类型:在此示例中,我们使用支持 AMD SEV 机密计算技术 (
--confidential-compute-type=SEV) 的机密虚拟机机器类型(例如n2d-standard-2)。 - 虚拟机操作系统映像:我们使用
confidential-space-images项目和confidential-space-debug映像系列来拉取最新的 Confidential Space 操作系统映像。 - 注意:我们在本指南中使用 debug 映像,以便更轻松地进行问题排查。与生产映像不同,调试版本在工作负载完成后仍会让虚拟机保持运行,并允许 SSH 访问以进行测试。对于使用真实敏感数据的生产部署,您必须切换到生产映像系列。
- 工作负载参考:元数据中的必需
tee-image-reference行包含 Confidential Space 虚拟机将启动的特定容器映像(您的应用工作负载)。
此设置可确保 MIG 创建的每个虚拟机都是配置正确的 Confidential Space,可随时执行您的工作负载。
创建托管式实例组的步骤
下一步是使用您刚刚定义的模板创建托管式实例组 (MIG)。MIG 至关重要,因为它可以自动部署、管理和扩缩多个相同的虚拟机。
脚本 create_launch_mig.sh 可实现以下三个主要目标:
1. 创建 MIG
- 命令:
gcloud compute instance-groups managed create ${CURRENT_MIG_NAME} - 用途:此命令用于创建将管理虚拟机的群组。
--size 3:指定 MIG 应最初创建并维护 3 个实例的工作负载。--template ${TEMPLATE_NAME}:至关重要的是,它引用了之前创建的实例模板,确保所有 3 个实例都配置为运行特定tee-image-reference工作负载容器的 Confidential Space 虚拟机。--zone ${CURRENT_PROJECT_ZONE}:指定实例的部署位置。
2. 提取项目编号
- 命令:
PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") - 用途:此脚本用于获取项目的数字 ID。创建服务账号角色和权限时,通常需要此编号,尤其是对于 Google 管理的服务代理。
3. 授予 IAM 权限
- 命令:
gcloud projects add-iam-policy-binding --role="roles/compute.serviceAgent" - 用途:此步骤会向工作负载的服务账号 (
${SERVICE_ACCOUNT) 授予 Compute Engine Service Agent 角色。此权限非常重要,因为它允许服务账号代表项目的 Compute Engine 服务执行操作,这对于 MIG 的自动化功能(例如管理实例、设置网络和与其他 Google Cloud 服务互动)通常是必需的。
运行 create_launch_mig.sh 以创建托管式实例组。
6. 启用自动修复和自动扩缩的步骤
设置自动修复
为确保高可用性,我们会验证工作负载是否响应。如果应用冻结,MIG 应替换该虚拟机。有关来源 IP 范围的防火墙规则在本文档中进行了定义。
# 1. Create Health Check (TCP Port 22)
gcloud compute health-checks create tcp ${HEALTH_CHECK_NAME} \
--port 22 \
--check-interval 30s \
--healthy-threshold 1 \
--timeout 10s \
--unhealthy-threshold 3 \
--global
# 2. Allow Health Check Traffic (Firewall)
gcloud compute firewall-rules create allow-health-check \
--allow tcp:22 \
--source-ranges 130.211.0.0/22,35.191.0.0/16 \
--network default \
--project="${CURRENT_PROJECT_ID}" \
# 3. Apply to MIG
gcloud compute instance-groups managed update ${CURRENT_MIG_NAME} \
--health-check ${HEALTH_CHECK_NAME} \
--initial-delay 60 \
--zone ${CURRENT_PROJECT_ZONE}
设置自动扩缩
我们将配置该组,使其在 1 到 5 个实例之间自动扩缩,以应对流量高峰。
gcloud compute instance-groups managed set-autoscaling ${CURRENT_MIG_NAME} \
--max-num-replicas 5 \
--target-cpu-utilization 0.80 \
--cool-down-period 90 \
--zone ${CURRENT_PROJECT_ZONE}
7. 验证工作负载并设置映像更新
验证工作负载
在托管式实例组 (MIG) 启动虚拟机后,我们需要验证您的 Confidential Space 工作负载是否正常运行。
您可以通过 Google Cloud 控制台或命令行执行此操作。
gcloud compute instance-groups managed list-instances ${CURRENT_MIG_NAME} \
--zone ${CURRENT_PROJECT_ZONE}
您还可以检查相应特定实例的串行端口输出,以查看工作负载的日志
# Replace <INSTANCE_NAME> with one of the names from the previous command
gcloud compute instances get-serial-port-output <INSTANCE_NAME> \
--zone ${CURRENT_PROJECT_ZONE} \
--port 1
设置图片更新
在生产环境中,您必须定期更新托管式实例组 (MIG),以应对以下两种不同的情况:
- 工作负载更新:发布应用代码的新版本(例如,将 test_workload.py 从 v1 更新到 v2)。
- 基础设施更新:Google 针对底层 Confidential Space 操作系统发布安全补丁或更新。请注意,最佳实践是至少每月获取一次最新的 CS 映像。
由于我们使用动态映像链接 (.../images/family/...) 和动态容器标记 (:latest) 配置了实例模板,因此可以通过一次“滚动替换”操作来处理这两种情况。这样可确保您的虚拟机群组始终运行最新的堆栈,而不会出现任何停机情况,并且您无需为每个细微更改创建新的实例模板。
滚动替换脚本
在目录 update_images 下,前往 update_images_script.sh。此脚本会触发滚动替换,该操作会逐步销毁并重新创建组中的每个虚拟机
#!/bin/bash
# Initialize the template
gcloud compute instance-groups managed set-instance-template "${CURRENT_MIG_NAME}" \
--template=projects/"${PROJECT_ID}"/global/instanceTemplates/"${TEMPLATE_NAME}" \
--zone="${CURRENT_PROJECT_ZONE}" \
--project="${PROJECT_ID}"
# Trigger the rolling replace
gcloud compute instance-groups managed rolling-action replace "${CURRENT_MIG_NAME}" \
--version=template="${TEMPLATE_NAME}" \
--project="${PROJECT_ID}" \
--zone="${CURRENT_PROJECT_ZONE}" \
--max-surge=1 \
--max-unavailable=0
# Wait for the update to complete
gcloud compute instance-groups managed wait-until --version-target-reached "${CURRENT_MIG_NAME}" \
--zone="${CURRENT_PROJECT_ZONE}" \
--project="${PROJECT_ID}"
对于此脚本,我们可以使用替换而不是重新启动。
- 重新启动只是重新启动机器。它会保留现有的操作系统磁盘,这意味着它不会提取新的操作系统补丁。
- 替换会删除虚拟机,并根据模板重新创建一个虚拟机。这会强制系统从映像系列中查找最新的 Confidential Space 操作系统映像,并从注册表中拉取“最新”容器映像。
--max-surge=1:此设置允许 MIG 临时创建比目标大小多 1 个的虚拟机。它会启动新的(已更新的)虚拟机,并等待该虚拟机运行正常之后再删除旧的(过时的)虚拟机。
–max-unavailable=0:这可确保零停机时间。它会告知 MIG,除非已成功将替换机器纳入到集群中,否则不允许将任何机器离线。
滚动重启脚本
在目录 update_images 下,还有一个脚本 update_workload_image_script.sh。此脚本会触发滚动重启,这是一种仅用于刷新工作负载的更快方法。由于 Confidential Space 会在每次启动时从注册表中拉取容器映像,因此只需重启即可将应用更新到 :latest 版本,而无需更改底层主机。
#!/bin/bash
# Reboots the existing VMs to refresh the container
gcloud compute instance-groups managed rolling-action restart "${CURRENT_MIG_NAME}" \
--project="${PROJECT_ID}" \
--zone="${CURRENT_PROJECT_ZONE}" \
--max-surge=1 \
--max-unavailable=0
# Wait for the update to complete
gcloud compute instance-groups managed wait-until --stable "${CURRENT_MIG_NAME}" \
--zone="${CURRENT_PROJECT_ZONE}" \
--project="${CURRENT_PROJECT_ID}"
验证更新后的工作负载
我们可以通过模拟实际应用发布来测试“一键升级”。我们将修改工作负载代码,将其推送到 Artifact Registry,更新 MIG,并验证新版本是否在零停机时间内运行。
第 1 步:部署新的工作负载版本
首先,我们需要创建应用的“新”版本。
- 打开本地 test_workload.py 文件。
- 将版本输出语句从 print("Workload Version A") 更改为 print("Workload Version B")
- 运行 create_workload.sh,重新构建容器映像并将其推送到 Artifact Registry。请注意,我们正在推送到同一标记 (:latest)。
第 2 步:执行滚动更新
运行我们在上一部分中创建的更新脚本。这样会强制 MIG 替换每个虚拟机,并拉取与 :latest 关联的新容器哈希。
# Run your update script
./update_images/update_images_script.sh
等待脚本完成
第 3 步:验证通过串行端口进行的更新
更新完成后,我们会验证新虚拟机是否正在运行更新后的代码。
# Replace <INSTANCE_NAME> with one of the names from the previous command
gcloud compute instances get-serial-port-output <INSTANCE_NAME> \
--zone ${CURRENT_PROJECT_ZONE} \
--port 1
获取新实例的名称:
gcloud compute instance-groups managed list-instances ${CURRENT_MIG_NAME} --zone ${CURRENT_PROJECT_ZONE}
查看日志:
# Replace <NEW_INSTANCE_NAME> with one of the names of the running VMs
gcloud compute instances get-serial-port-output <NEW_INSTANCE_NAME> \
--zone ${CURRENT_PROJECT_ZONE} \
--port 1
实例运行后,从上一个 gcloud 命令中选择任意实例名称,即可查看其串行端口
预期输出:您应该会看到更新后的日志消息,确认部署成功:
... 工作负载版本 B ...
第 4 步:验证基础架构配置(可选)
您还可以通过检查实例模板的元数据,验证该模板是否已正确配置为可提取操作系统和工作负载的动态更新。
运行以下命令以查看动态容器引用:
gcloud compute instance-templates describe ${TEMPLATE_NAME} \
| grep -A 1 tee-image-reference
结果:您应该会看到容器映像以 :latest 结尾。
- 含义:由于模板指向的是 tag 而不是特定的哈希,因此每次滚动替换操作都会成功拉取您在第 1 步中推送的最新代码。
(可选)自动更新
虽然手动更新对于主要版本发布很有用,但您通常希望您的设备群在无人干预的情况下自动获取最新的安全补丁或常规部署 build。
我们可以将更新脚本打包到 Cloud Run 作业中,从而自动执行“滚动替换”流程。在此 Codelab 中,我们将每 15 分钟触发一次。在生产环境中,应以低得多的频率运行。用户可以根据自己的需求按周或按月配置。
第 1 步:将更新程序脚本容器化
首先,我们需要将 update_images_script.sh(其中包含 gcloud ... rolling-action replace 逻辑)打包到 Docker 容器中,以便它可以在云端运行。
我们准备了一个辅助脚本,用于构建此容器并将其推送到您的 Artifact Registry。
运行以下命令:
# Build and Push the "Updater" Container
# This packages your update logic into a docker image
./update_images/deploy_docker_script_image.sh
此操作的作用:
- 它会从 update_images/ 目录中获取 update_images_script.sh。
- 它会创建一个包含 Google Cloud SDK 和您的脚本的 Docker 映像。
- 它会将映像推送到 ${CURRENT_PROJECT_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/update-script:latest。
第 2 步:部署和安排作业
现在,我们需要告知 Google Cloud 定期运行此容器。我们使用 Cloud Run 作业来执行容器,并使用 Cloud Scheduler 来触发容器。
运行调度配置脚本:
# Create the Cloud Run Job and the Scheduler Trigger
./create_configs/create_schedule_job.sh
脚本内部:此脚本会执行两项关键操作:
- 创建 Cloud Run 作业:它定义了一个名为 mig-updater-job 的作业,该作业会执行我们刚刚推送的容器。
- 创建调度器触发器:它会设置一个 Cloud Scheduler 作业,以每 15 分钟调用一次 Cloud Run 作业 API。
# (Snippet from create_schedule_job.sh for reference)
# The schedule is set to run every 15 minutes for testing purposes
gcloud scheduler jobs create http ${SCHEDULER_NAME} \
--schedule "*/15 * * * *" \
--uri "https://${CURRENT_PROJECT_REGION}-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/${PROJECT_ID}/jobs/${JOB_NAME}:run" \
--http-method POST \
--oauth-service-account-email ${SERVICE_ACCOUNT}
第 3 步:验证自动化
您无需等待 15 分钟即可进行测试。您可以强制调度程序立即运行,以验证流水线。
- 强制运行作业:
gcloud scheduler jobs run ${SCHEDULER_NAME} --location ${CURRENT_PROJECT_REGION}
- 检查执行情况:前往 Cloud Run 控制台 > 作业。您应该会看到新的执行开始。
- 检查 MIG:运行 gcloud compute instance-groups managed list-instances ${CURRENT_MIG_NAME}。当作业触发滚动更新时,您会看到实例进入“RECREATING”状态。
为什么是 15 分钟?在此 Codelab 中,我们将时间表设置为 */15 * * * *,以便您快速查看结果。在实际的生产环境中,您可能会将此设置更改为每天运行一次(例如,0 3 * * * 表示凌晨 3 点)或每周运行一次。
8. 清理
清理脚本 cleanup.sh 可用于清理我们在此 Codelab 中创建的资源。在此清理过程中,系统将删除以下资源:
- 托管式实例组 (${CURRENT_MIG_NAME}) 及其底层虚拟机。
- 实例模板 (${TEMPLATE_NAME})。
- 健康检查和防火墙规则 (${HEALTH_CHECK_NAME})。
- Artifact Registry 代码库 (${REPOSITORY})。
- 服务账号(如果您为此实验创建了专用服务账号)。
如果您已完成探索,请考虑按照以下说明删除项目:关闭(删除)项目。
恭喜
恭喜,您已成功完成此 Codelab!
您已了解如何使用托管式实例组 (MIG) 安全地扩缩 Confidential Space 工作负载。您已成功配置自动修复以从故障中恢复、自动扩缩以应对流量高峰,并为 Confidential Space 操作系统映像和工作负载容器执行了零停机时间更新。
后续操作
查看其他 Confidential Space Codelab:
- 使用 Confidential Space 保护机器学习模型和知识产权
- 如何利用多方计算和 Confidential Space 交易数字资产
- 使用 Confidential Space 分析机密数据
- 搭配使用 Confidential Space 与未存储在云提供商处的受保护资源