使用 User Data 初始化实例

AWSBeginner
立即练习

介绍

团队希望每台新报表服务器启动后都显示正确的应用问候语。你将编写 Bash User Data 脚本,在启动 EC2 实例时传入该脚本,并检查应用响应和启动日志。

你应已了解如何启动 EC2 实例并通过 SSH 连接。这个全新环境提供自己的镜像、网络和密钥对;服务器及其启动配置由你创建。

认证备考关联

本实验练习通过程序配置资源和自动化启动,对应 AWS Certified Cloud Practitioner CLF-C02 考试领域 3 的任务 3.1。

在启动时配置应用

在本步骤中,你将编写启动脚本,使用它启动实例,并验证应用响应。

User Data(用户数据)是在启动时传给实例的信息。Linux 启动脚本可以利用它自动配置软件。默认情况下,这些脚本在首次启动时以 root 身份执行,因此脚本内部的命令不需要 sudo。EC2 User Data 官方指南 介绍了这一启动行为及日志位置。

首先进入工作目录:

cd /home/labex/project

预置镜像包含报表应用。将镜像和网络 ID 加载到当前 shell:

source launch.env

使用 here-document 创建 user-data.sh。外层 SCRIPT 标记界定完整脚本;内层 JSON 标记界定应用配置。带引号的标记会保留原样文本。第一行 #!/bin/bash 选择 Bash;set -euo pipefail 使脚本在命令失败或使用未设置变量时停止。最后的 echo 会写入一条便于检查的启动日志。

cat > user-data.sh <<'SCRIPT'
#!/bin/bash
set -euo pipefail
cat > /etc/report-app/config.json <<'JSON'
{
  "message": "Started with User Data"
}
JSON
echo 'Report application configuration applied.'
SCRIPT

这会创建本地文件,尚未修改任何实例。使用 --user-data file://user-data.sh 将文件传给 run-instances。AWS CLI 会读取文件并为 API 编码,无需自行编码。将服务器命名为 bootstrap-server:

aws ec2 \
  run-instances \
  --image-id "$AMI_ID" \
  --instance-type t3.micro \
  --subnet-id "$SUBNET_ID" \
  --security-group-ids "$SECURITY_GROUP_ID" \
  --key-name report-key \
  --count 1 \
  --user-data file://user-data.sh \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=bootstrap-server}]'

保存新实例的 ID。过滤器选择它的名称标签;$(...) 捕获纯文本结果:

INSTANCE_ID=$(aws ec2 \
  describe-instances \
  --filters Name=tag:Name,Values=bootstrap-server \
  --query 'Reservations[0].Instances[0].InstanceId' \
  --output text)

检查状态和公网地址:

aws ec2 \
  describe-instances \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name,PublicIPv4:PublicIpAddress}'

确认状态为 running。如果仍为 pending,稍等片刻后重复查询。运行状态本身不能证明启动配置成功;接下来检查应用。

打开 AWS View,点击 Refresh resources,在 Application requests 下选择 bootstrap-server。点击 Check application,确认 HTTP 200 和消息 Started with User Data。你通过启动脚本完成了服务器配置,无需在启动后再编辑配置。

AWS View 显示启动脚本配置的应用返回 HTTP 200

示例展示预期响应。你的实例和网络 ID 会不同。

获取公网地址,以便通过 SSH 连接:

PUBLIC_IP=$(aws ec2 \
  describe-instances \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[0].Instances[0].PublicIpAddress' \
  --output text)

提供的 SSH 配置会选择私钥和实验访问路径:

ssh -F ssh_config ubuntu@"$PUBLIC_IP"

现在你已进入应用实例。使用管理员权限读取启动输出日志:

sudo cat /var/log/cloud-init-output.log

找到 Report application configuration applied.,这是你提供的脚本输出。诊断启动故障时,先检查日志中的命令错误,再测试应用本身,而不是仅凭实例状态判断。

返回 LabEx 终端:

exit

你也可以取回实例上保存的 User Data。查询选择它的 Base64 值,管道将该值传给 base64 --decode,显示原始脚本:

aws ec2 \
  describe-instance-attribute \
  --instance-id "$INSTANCE_ID" \
  --attribute userData \
  --query 'UserData.Value' \
  --output text | base64 --decode

确认 Bash 脚本和问候语与你的文件一致。User Data 通常只在首次启动时执行;停止后再启动实例,不会自动重复这些配置。使用启动自动化获得一致的初始配置,并避免在脚本中写入凭证。

终止初始化服务器

在本步骤中,你将移除自己创建的实例,并验证最终状态。

仅终止保存在变量中的这个实例:

aws ec2 \
  terminate-instances \
  --instance-ids "$INSTANCE_ID"

等待实例达到 terminated。等待器会轮询状态,成功时不输出内容:

aws ec2 \
  wait instance-terminated \
  --instance-ids "$INSTANCE_ID"

确认最终状态:

aws ec2 \
  describe-instances \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}'

结果应显示 terminated。刷新 AWS View,确认 bootstrap-server 已不再是运行中的应用目标。保留预置网络和密钥对。

总结

你编写了 Bash User Data 脚本,并在启动 EC2 时传入它。你通过 AWS View 验证了应用自动配置,检查了启动输出日志,并取回了保存的脚本。最后,你终止服务器并确认了最终状态。