复用并变更应用部署

AWSBeginner
立即练习

介绍

应用部署可以发生变更,但并非每项变更都要替换实例。你将使用提供的本地模块,审查一次保留工作负载的标签更新,然后发布会替换实例的新启动配置。应用从提供的外部存储读取报告。

本实验要求你具备 Terraform 模块调用、计划和状态的基础知识,并已完成前面的 EC2 和工作负载角色实验。全新环境提供初始部署、网络、AMI、角色和实例配置文件、私有报告及参考应用。你将修改模块调用,并在每个阶段观察资源标识、本地文件和外部数据。

与认证考试的关联

认证 考试任务 实践内容
Cloud Practitioner (CLF-C02) 任务 3.1 基础设施即代码的资源配置方法。
CloudOps Engineer – Associate (SOA-C03) 任务 3.1 基础 Terraform 部署更新和替换。

实验概览

概念总览:更改模块标签输入会更新同一实例,而更改启动消息会替换实例;S3 报告保留。

阅读模块接口并应用更新

在这一步中,你将阅读提供的模块输入和输出,修改发布标签输入,并验证现有实例和本地文件保持完整不变。

上方的 AWS View 与 Terminal 观察相同资源,并发送实际工作负载请求。模块部署已经运行。提供的角色和实例配置文件仅授予所需报告的读取权限;网络、角色和报告存储桶仍在此根目录的管理归属之外。

检查根模块调用和小型模块接口:

cd /home/labex/project/application-releases
cat application.tf
cat modules/application/variables.tf
cat modules/application/outputs.tf
cat modules/application/main.tf
terraform state list
ORIGINAL_ID=$(terraform output -raw instance_id)
echo "$ORIGINAL_ID"
REPORT_BUCKET=$(terraform output -raw report_bucket)
echo "$REPORT_BUCKET"

source = "./modules/application" 选择本地模块目录。调用传入已准备好的基础设施输入,以及 message 和 release_label。子模块创建 EC2 资源,其输出通过根模块输出提供实际实例 ID。因此,状态地址以 module.application 开头。

模块将 release_label 映射为 ReleaseNote 标签,将 message 写入 User Data,并启用 user_data_replace_on_change。你将更改调用方输入,同时保留提供的实现。保持 modules/application/ 下的三个文件全部不变,并使用该预先提供的本地模块。在根模块调用中进行更改。

在 AWS View 中,选择 application-server、User · 198.51.100.10、Application · 8081 和 Health,然后点击 Send request。预期看到 Connected · 200 和 Application release one。选择 Local report file 再次发送:预先准备的实例包含 local,existing-record。选择 Private report 读取独立的 S3 报告,内容为 period,total / Q1,320。

仅将标签输入从 initial 改为 reviewed。这会重写小型根模块调用,但保留全部基础设施引用和启动消息:

cat > application.tf <<'HCL'
module "application" {
  source = "./modules/application"
  ami_id = var.ami_id
  subnet_id = var.subnet_id
  security_group_id = var.security_group_id
  profile_name = var.profile_name
  report_bucket = var.report_bucket
  message = "Application release one"
  release_label = "reviewed"
}
output "instance_id" { value = module.application.instance_id }
output "image_id" { value = module.application.image_id }
output "report_bucket" { value = var.report_bucket }
HCL
terraform fmt
terraform validate
terraform plan

审查模块实例标签的就地更新,确认没有实例创建或销毁。应用配置并输入 yes:

terraform apply

比较实际 ID 和原生标签:

echo "$ORIGINAL_ID"
terraform output -raw instance_id
aws ec2 \
  describe-instances \
  --instance-ids "$ORIGINAL_ID" \
  --query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name,Tags:Tags}'

ID 不变,ReleaseNote 为 reviewed。在 AWS View 中,向同一实例发送 Health 和 Local report file 请求。消息仍为 Application release one,现有本地记录也仍保留。标签更新不会重新运行启动初始化。

terraform plan

预期看到 No changes.。

审查并应用启动配置替换

在这一步中,你将更改启动消息,检查已保存的替换计划,并在保留外部报告的同时验证新工作负载。

消息是 User Data 的一部分。此模块的 user_data_replace_on_change 设置使启动配置变更明确触发实例替换。现有本地记录属于旧实例的文件系统;S3 报告属于单独提供的存储。

更改调用中的消息并保存计划:

sed -i 's/Application release one/Application release two/' application.tf
terraform fmt
terraform validate
terraform plan -out=release.tfplan
terraform show release.tfplan

审查实例的 -/+ 替换和变更后的 User Data。计划不得销毁提供的网络、角色、实例配置文件、镜像、存储桶或参考应用。release.tfplan 为下一条命令保存已审查的计划。

应用该已保存计划:

terraform apply release.tfplan

应用已保存计划不会再次要求输入 yes;命令执行的是已保存操作。等待完成,然后比较两个实际实例标识:

NEW_ID=$(terraform output -raw instance_id)
echo "$ORIGINAL_ID"
echo "$NEW_ID"
aws ec2 \
  describe-instances \
  --instance-ids "$ORIGINAL_ID" "$NEW_ID" \
  --query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name,Image:ImageId}'

ID 不同:原实例为 terminated,新实例使用相同预先准备的 AMI,状态为 running。根据 ID 匹配结果,不要依赖行顺序。

在 AWS View 中,选择正在运行的 application-server 条目并发送 Health。预期看到 Connected · 200 和 Application release two。已终止的旧实例不再是可选择的运行目标。

发送 Local report file 请求。其内容现在是 local,initialized,由新实例中的 User Data 创建。替换没有保留旧实例的本地记录。然后发送 Private report:外部 S3 报告仍返回 Connected · 200,内容为 period,total / Q1,320。发送 Unrelated private object,预期看到 Connected · 403 和 Access denied。

最后选择 reference-server、User、端口 8081 和 Health,然后发送请求。它必须仍返回 Connected · 200 和 Reference application。

terraform plan

预期看到 No changes.。新实例由模块管理,外部数据和参考环境则保持完整不变。 示例结果:旧实例已终止,替换实例提供第二版应用。各环境中的实例 ID 会有所不同。

销毁模块工作负载并保留其依赖

在这一步中,你将移除受管理的替换实例,同时保留提供的基础设施、工作负载角色和外部报告数据。

销毁根目录中的受管理资源前,先记录镜像 ID:

IMAGE_ID=$(terraform output -raw image_id)
echo "$IMAGE_ID"
terraform plan -destroy

预期销毁一个受管理实例。AMI 数据源读取现有镜像;网络、实例配置文件、角色和存储桶作为预先提供的输入传入模块。执行删除并输入 yes:

terraform destroy

查询替换实例的原生终止状态,并检查剩余状态:

aws ec2 \
  describe-instances \
  --instance-ids "$NEW_ID" \
  --query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name}'
terraform state list

预期看到 terminated,且状态中不再有受管理实例。提供的镜像和实例配置文件必须仍然存在:

aws ec2 describe-images --image-ids "$IMAGE_ID" --query 'Images[].{ID:ImageId,Name:Name}'
aws iam \
  get-instance-profile \
  --instance-profile-name supplied-application-reader \
  --query 'InstanceProfile.{Name:InstanceProfileName,Roles:Roles[].RoleName}'

使用 Terminal 操作者读取保留的 S3 报告。这检查外部数据保留;工作负载自身的限定范围访问已在销毁前验证。

aws s3api get-object --bucket "$REPORT_BUCKET" --key report.csv /tmp/g5-retained-report.csv
cat /tmp/g5-retained-report.csv

字节仍为 period,total / Q1,320。在 AWS View 中,选择 reference-server、User、端口 8081 和 Health,然后发送请求。预期看到 Connected · 200 和 Reference application。

保留根模块和子模块文件以供审阅。保留的 HCL 会在之后的普通计划中提出创建新实例;清理要求的是在原生资源层删除受管理工作负载,而不是让后续计划为空。

总结

你使用提供的模块输入和输出更新了现有工作负载,并发布了替换实例。你审查了对资源和数据的影响,应用了已保存计划,区分了实例本地文件与保留的外部报告,并且仅清理了模块拥有的工作负载。