修复 EFS 挂载连接

AWSBeginner
立即练习

介绍

应用 A 可以读取共享上传内容,但应用 B 无法连接同一 EFS 存储。诊断连接失败,恢复 B 的挂载,并将访问保持在预期应用服务器范围内。

请先完成前两个 EFS 引导实验。本新环境提供故障所需的已有文件系统、访问点、原始上传和应用主机。使用配置好的 AWS CLI、SSH 连接和 AWS View,无需之前 VM 的资源或个人 AWS 账号。

认证关联

认证 考纲任务 实践
Cloud Practitioner (CLF-C02) Task 3.5;Task 3.6 将文件服务连接与 VPC 安全组访问关联,区分网络可达性和存储资源可用状态。

课程概览

概念示意图;实际标识符以你的新环境为准。

诊断并修复 NFS 网络规则

本步骤定位连接失败的层次,修复存储安全组。

在 /home/labex/project 中操作。resources.json 记录本实验的存储和应用标识符:

cd /home/labex/project
aws sts \
  get-caller-identity
FS_ID=$(jq -r .fault.filesystem_id resources.json)
MOUNT_TARGET_ID=$(jq -r .fault.mount_target_id resources.json)
AP_ID=$(jq -r .fault.access_point_id resources.json)
EFS_GROUP_ID=$(jq -r .fault.storage_group_id resources.json)
APP_GROUP_ID=$(jq -r .application_group_id resources.json)
APP_A_IP=$(jq -r '.clients["application-a"].ip' resources.json)
echo "$FS_ID"
echo "$MOUNT_TARGET_ID"
echo "$AP_ID"
echo "$EFS_GROUP_ID"
echo "$APP_GROUP_ID"
echo "$APP_A_IP"

通过两个应用读取已有上传:

curl -i http://127.0.0.1:8081/uploads/original-upload.txt
curl -i http://127.0.0.1:8082/uploads/original-upload.txt

A 返回 200 OK 和 Original upload from application A,B 返回 404 Not Found。查看挂载:

ssh -F ssh_config application-a 'findmnt -t nfs4 /srv/shared'
ssh -F ssh_config application-b 'findmnt -t nfs4 /srv/shared'

A 有 NFS 挂载,B 没有,B 的 findmnt 返回状态 1。更改路径或权限前,先确认 B 能否连接网络端点:

MOUNT_IP=$(aws efs \
  describe-mount-targets \
  --mount-target-id "$MOUNT_TARGET_ID" \
  --query 'MountTargets[0].IpAddress' --output text)
echo "$MOUNT_IP"
ssh -F ssh_config application-b "nc -zvw2 $MOUNT_IP 2049"

连接失败。nc 在不创建挂载的情况下测试 TCP 可达性。错误的访问点路径或 POSIX 身份可能阻止已建立连接后的文件访问,但不能解释这次 TCP 测试失败。

确认挂载目标可用,并查看绑定的安全组:

aws efs \
  describe-mount-targets \
  --mount-target-id "$MOUNT_TARGET_ID" \
  --query 'MountTargets[].{ID:MountTargetId,State:LifeCycleState,Subnet:SubnetId}'
aws efs \
  describe-mount-target-security-groups \
  --mount-target-id "$MOUNT_TARGET_ID"
aws ec2 \
  describe-security-groups \
  --group-ids "$EFS_GROUP_ID" \
  --query 'SecurityGroups[].IpPermissions'

NFS 入站规则用 /32 CIDR,仅允许 A 的私有地址访问 TCP 2049,排除了 B。用提供的应用安全组规则替换该地址规则:

aws ec2 \
  revoke-security-group-ingress \
  --group-id "$EFS_GROUP_ID" \
  --protocol tcp \
  --port 2049 \
  --cidr "$APP_A_IP/32"

允许应用组的两个成员:

aws ec2 \
  authorize-security-group-ingress \
  --group-id "$EFS_GROUP_ID" \
  --ip-permissions "IpProtocol=tcp,FromPort=2049,ToPort=2049,UserIdGroupPairs=[{GroupId=$APP_GROUP_ID}]"
ssh -F ssh_config application-b "nc -zvw2 $MOUNT_IP 2049"

新连接成功。你修复了网络层,没有向 0.0.0.0/0 开放 NFS,也没有替换文件系统。

恢复 B 的访问点挂载

本步骤将应用 B 连接到已有共享上传目录,不替换 A 的数据。

挂载前查看提供的访问点:

aws efs \
  describe-access-points \
  --access-point-id "$AP_ID" \
  --query 'AccessPoints[].{ID:AccessPointId,Root:RootDirectory.Path,User:PosixUser}'

根目录是 /uploads,数字身份对应准备好的应用用户。两个应用需要相同上传内容,因此应选择同一访问点。不要创建新文件系统,也不要将 A 的文件复制到 B 的本地磁盘。

使用官方 EFS 助手和 TLS 在 B 上挂载:

ssh -F ssh_config application-b \
  "sudo mkdir -p /srv/shared && sudo mount -t efs -o tls,stunnel,lookupcache=positive,accesspoint=${AP_ID} ${FS_ID}:/ /srv/shared"
ssh -F ssh_config application-b 'findmnt -t nfs4 /srv/shared'

挂载使用 lookupcache=positive:当另一台应用创建之前不存在的文件时,再次向服务器查询该文件名,让短时间内的上传结果可见。生产工作负载的缓存调整还需要单独评估性能。参见 Linux NFS 目录缓存选项。

B 现在在 /srv/shared 显示 NFS 4 挂载。应用已配置为使用该目录,因此下一次请求直接读取 EFS:

curl -i http://127.0.0.1:8082/uploads/original-upload.txt
ssh -F ssh_config application-a 'stat -c "%i %u:%g" /srv/shared/original-upload.txt'
ssh -F ssh_config application-b 'stat -c "%i %u:%g" /srv/shared/original-upload.txt'

B 返回原始内容,两个主机报告相同 inode 和所有者。修复恢复了对已有文件的访问,而不是另建副本。

验证新上传和访问边界

本步骤证明 B 可写入共享文件,无关客户端仍被排除。

通过 B 上传新文件,再通过 A 读取:

curl -i -X PUT --data-binary 'Shared upload after connection repair' \
  http://127.0.0.1:8082/uploads/shared.txt
curl -i http://127.0.0.1:8081/uploads/shared.txt

B 返回 201 Created,A 返回 200 OK 和相同内容。在 AWS View 使用文件名 shared.txt,从两个应用卡片读取。

参考服务器属于不同安全组。确认它无法建立新的 NFS 连接:

ssh -F ssh_config reference-c "nc -zvw2 $MOUNT_IP 2049"

连接应失败并返回非零状态。这是预期的访问边界,不是另一个应用故障。确认参考服务器的无关上传仍然可用:

curl -i http://127.0.0.1:8083/uploads/reference.txt

响应是 200 OK 和 Unrelated reference upload remains unchanged。修复后的应用与参考服务仍有不同的网络访问范围。

AWS View application uploads

连接修复后,两台应用读取同一份新上传内容。标识符以每次新环境为准。

释放实验存储

本步骤在测试修复后删除临时存储,保留准备好的应用和网络资源。

将两个上传应用恢复为本地目录,并卸载共享存储:

ssh -F ssh_config application-a \
  'printf "{\"upload_directory\":\"/srv/uploads\"}\n" | sudo tee /etc/uploads-app/config.json'
ssh -F ssh_config application-b \
  'printf "{\"upload_directory\":\"/srv/uploads\"}\n" | sudo tee /etc/uploads-app/config.json'
ssh -F ssh_config application-a 'sudo umount /srv/shared'
ssh -F ssh_config application-b 'sudo umount /srv/shared'

存储标识符来自 resources.json,只删除这些确切资源。先删除访问点和挂载目标:

aws efs \
  delete-access-point \
  --access-point-id "$AP_ID"
aws efs \
  delete-mount-target \
  --mount-target-id "$MOUNT_TARGET_ID"
aws efs \
  describe-mount-targets \
  --file-system-id "$FS_ID"

等待 MountTargets 为空,再删除文件系统和存储安全组:

aws efs \
  delete-file-system \
  --file-system-id "$FS_ID"
aws ec2 \
  delete-security-group \
  --group-id "$EFS_GROUP_ID"

通过成功的响应确认列表为空:

aws efs \
  describe-file-systems \
  --query 'FileSystems[?Name==`fs03-shared-uploads`].FileSystemId'
aws ec2 \
  describe-security-groups \
  --filters Name=group-name,Values=fs03-efs-access \
  --query 'SecurityGroups[].GroupId'

存储列表应为空。保留应用服务器、原有安全组、子网和参考上传内容。在环境仍可进行授权读取时运行清理检查。

总结

你在诊断 EFS 连接时区分了资源可用性、TCP 可达性、挂载选择和文件权限。使用应用安全组修复受限规则,恢复 B 对原始文件的访问,测试跨服务器的新上传,并继续排除参考客户端。最后按依赖顺序删除实验存储。

进一步阅读 AWS 官方资料:客户端与挂载目标网络规则; 诊断挂载超时与访问失败。