Общие файлы между серверами приложений с EFS

AWSBeginner
Практиковаться сейчас

Введение

Приложение загрузки работает на двух серверах. Каждый сохраняет файлы на своём локальном диске: файл может успешно загрузиться через один сервер, но не найтись на другом. Предоставьте обоим общий файловый интерфейс с помощью Amazon Elastic File System (EFS).

Сначала завершите AWS VPC for Beginners и AWS EC2 and EBS for Beginners. Независимая среда содержит приложение, три узла и их сеть. Используйте Terminal для AWS CLI и SSH и AWS View для сравнения реальных ответов. CLI настроен; личная учётная запись AWS и ресурсы предыдущих упражнений не нужны. Здесь изучаются общие файлы и подключения без оценки производительности или доступности в рабочей среде.

Связь с сертификацией

Сертификация Задача экзамена Практика
Cloud Practitioner (CLF-C02) Task 3.6 Распознать общий файловый сервис EFS и отличить смонтированный интерфейс от отдельных локальных каталогов.

Обзор

Схема концептуальная; реальные идентификаторы указаны в новой среде.

Создать хранилище приложения загрузки

На этом шаге наблюдайте проблему локальных загрузок и создайте общую файловую систему.

Работайте в /home/labex/project. Проверьте настроенную идентичность без вывода учётных данных:

cd /home/labex/project
aws sts \
  get-caller-identity

ARN пользователя заканчивается на labex-fs01-operator. resources.json содержит подготовленные подсеть и группу безопасности приложений. Считайте идентификаторы для последующих команд с реальными ресурсами среды:

SUBNET_ID=$(jq -r .subnet_id resources.json)
APP_GROUP_ID=$(jq -r .application_group_id resources.json)
VPC_ID=$(jq -r .vpc_id resources.json)
echo "$SUBNET_ID"
echo "$APP_GROUP_ID"
echo "$VPC_ID"
aws ec2 \
  describe-instances \
  --filters Name=tag:Name,Values=application-a,application-b \
  --query 'Reservations[].Instances[].{Name:Tags[?Key==`Name`].Value|[0],IP:PrivateIpAddress,State:State.Name}'

Сначала наблюдайте локальную проблему. HTTP PUT сохраняет загрузку, GET читает файл. Эти адреса ведут к подготовленным серверам:

curl -i -X PUT --data-binary 'A local upload' \
  http://127.0.0.1:8081/uploads/local-example.txt
curl -i http://127.0.0.1:8082/uploads/local-example.txt

A возвращает 201 Created, B — 404 Not Found: его локальный каталог содержит другие файлы. Можно также записать и прочитать одинаковое имя через две карточки AWS View.

EFS предоставляет общую файловую систему. Оба приложения обращаются к одним каталогам и файлам через протокол Network File System (NFS). Сначала создайте систему. Токен обозначает запрос создания, тег Name помогает при проверке и очистке. --encrypted включает настройку шифрования хранимых данных сервиса. Шифрование передачи настраивается отдельно при монтировании.

FS_ID=$(aws efs \
  create-file-system \
  --creation-token fs01-shared-uploads \
  --encrypted \
  --tags Key=Name,Value=fs01-shared-uploads \
  --query FileSystemId --output text)
echo "$FS_ID"
aws efs \
  describe-file-systems \
  --file-system-id "$FS_ID" \
  --query 'FileSystems[].{ID:FileSystemId,State:LifeCycleState,Encrypted:Encrypted}'

Дождитесь состояния available. Ресурс существует, но приложениям ещё нужны доступная цель монтирования и настоящий mount.

Подключить систему к подсети приложений

На этом шаге создайте доступную точку NFS и ограничьте её серверами приложений.

Цель монтирования предоставляет сетевую точку подключения в подсети. NFS использует TCP 2049. Создайте отдельную группу хранилища и разрешите этот порт из подготовленной группы приложений. Правило источника включает оба сервера, не открывая NFS всем адресам. Независимый контрольный сервер относится к другой группе и должен оставаться исключённым.

EFS_GROUP_ID=$(aws ec2 \
  create-security-group \
  --group-name fs01-efs-access \
  --description 'NFS from the upload application servers' \
  --vpc-id "$VPC_ID" \
  --query GroupId --output text)
echo "$EFS_GROUP_ID"
aws ec2 \
  authorize-security-group-ingress \
  --group-id "$EFS_GROUP_ID" \
  --ip-permissions "IpProtocol=tcp,FromPort=2049,ToPort=2049,UserIdGroupPairs=[{GroupId=$APP_GROUP_ID}]"

Создайте цель в подготовленной подсети и назначьте новую группу:

MOUNT_TARGET_ID=$(aws efs \
  create-mount-target \
  --file-system-id "$FS_ID" \
  --subnet-id "$SUBNET_ID" \
  --security-groups "$EFS_GROUP_ID" \
  --query MountTargetId --output text)
echo "$MOUNT_TARGET_ID"
aws efs \
  describe-mount-targets \
  --file-system-id "$FS_ID" \
  --query 'MountTargets[].{ID:MountTargetId,IP:IpAddress,State:LifeCycleState,AZ:AvailabilityZoneName}'
aws efs \
  describe-mount-target-security-groups \
  --mount-target-id "$MOUNT_TARGET_ID"

Дождитесь available. Оба приложения находятся в одной зоне доступности, поэтому здесь нужна одна цель. Для рабочего регионального развёртывания планируйте цели в зонах размещения клиентов.

Смонтировать приложения и проверить общие файлы

На этом шаге подключите оба приложения к EFS и проверьте загрузки в обе стороны.

ssh_config подключает к каждому узлу. Точка монтирования — локальный каталог для доступа к удалённой файловой системе. Создайте /srv/shared на обоих узлах и смонтируйте корень EFS:

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

lookupcache=positive повторно запрашивает ранее отсутствовавшие имена у сервера, когда другое приложение создаёт файл. Это делает новые загрузки видимыми в коротком упражнении. Настройку кеша для рабочих нагрузок оценивайте отдельно по производительности. См. параметры кеша каталогов Linux NFS.

-t efs выбирает официальный помощник монтирования, tls шифрует соединение, stunnel выбирает поддерживаемый TLS-транспорт. ${FS_ID}:/ обозначает корень. Необходимые клиентские инструменты уже установлены.

Новый каталог изначально принадлежит root. Подготовьте подкаталог загрузок для пользователя приложения labex и настройте оба приложения:

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

Приложение читает конфигурацию при каждом запросе, перезапуск не нужен. Проверьте реальные монтирования:

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

Оба узла показывают NFS 4 в /srv/shared. При TLS ядро может показывать источник 127.0.0.1:/, поскольку помощник передаёт NFS через локальный зашифрованный туннель.

Загрузите через A и прочитайте через B:

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

B возвращает 200 OK и Shared upload version 1. Обновите через B и прочитайте через A, чтобы проверить обратное направление:

curl -i -X PUT --data-binary 'Shared upload version 2' \
  http://127.0.0.1:8082/uploads/shared.txt
curl -i http://127.0.0.1:8081/uploads/shared.txt
ssh -F ssh_config application-a 'stat -c "%i %u:%g" /srv/shared/uploads/shared.txt'
ssh -F ssh_config application-b 'stat -c "%i %u:%g" /srv/shared/uploads/shared.txt'

Оба приложения читают версию 2, а stat показывает одинаковый inode. Независимые монтирования обращаются к одному файлу EFS; локальные каталоги не копируются и не синхронизируются. Сравните файл и в AWS View.

Общие загрузки в AWS View

Оба приложения читают один обновлённый файл. Идентификаторы различаются в новых средах.

Размонтировать и удалить своё хранилище

На этом шаге прекратите использовать общий каталог и удалите только созданное вами хранилище.

Перед удалением сетевой точки верните каждому приложению подготовленный локальный каталог и размонтируйте EFS:

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'

Если umount сообщает о занятом каталоге, выйдите из оболочек, использующих /srv/shared, и повторите. Проверьте отсутствие монтирований:

ssh -F ssh_config application-a 'findmnt -t nfs4'
ssh -F ssh_config application-b 'findmnt -t nfs4'

Монтирований NFS быть не должно. Без совпадений findmnt возвращает статус 1; здесь это ожидаемый результат.

Удалите сначала цель монтирования, затем файловую систему и наконец только вашу отдельную группу хранилища:

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==`fs01-shared-uploads`].FileSystemId'
aws ec2 \
  describe-security-groups \
  --filters Name=group-name,Values=fs01-efs-access \
  --query 'SecurityGroups[].GroupId'

Оба запроса возвращают пустые списки. Удаление подтверждает успешный авторизованный запрос; ошибка сети или разрешений этого не доказывает. Сохраните подготовленные серверы, их группы и подсеть.

Запустите проверку удаления и сохранности подготовленных ресурсов. Каждое последующее упражнение начинается в собственной независимой среде.

Резюме

Вы подключили два приложения к одному EFS через цель монтирования, ограниченный NFS-доступ и TLS. Взаимные загрузки и одинаковая идентичность файла доказали реальный общий доступ. Затем вы вернули локальное хранилище, размонтировали клиенты и удалили свои ресурсы в порядке зависимостей.

Общая файловая система не разделяет каталоги приложений и POSIX-идентичности автоматически. Следующее упражнение устанавливает эти границы с помощью точек доступа EFS.

Подробнее см. в документации AWS: Помощник монтирования EFS и транспорт TLS; Сетевые правила клиентов и целей монтирования.