- PVSM.RU - https://www.pvsm.ru -
Добрый день, уважаемые читатели.
Снова хочу поделиться с вами приобретенным опытом.На одном из проектов была поставлена цель организовать FTP-сервер повышенной надёжности. Под повышенной надёжностью подразумевалось следующее:
Шаг первый: Установка s3fs и монтирование S3 bucket в качестве дискового раздела.
Тут вариантов не много, вернее один (если ошибаюсь — поправьте) — s3fs [1]. Разработчики s3fs на своей странице утверждают, что «s3fs is stable and is being used in number of production environment». Процесс установки s3fs расписывать нет смысла, он есть тут [2].Остановлюсь только на действительно важных моментах.Во-первых, у последней версии s3fs проблемы с синхронизацией данных. Когда вы заливаете новый файл на S3, он тут же появляется у вас на сервере, но если потом вы вносите изменения в этот файл на S3, то на сервере по-прежнему остается старая версия. Налицо проблема с кешированием. Попытки монтировать S3 bucket с различными опциями включения и выключения кеширования ничего не дали. После тестирования различных релизов s3fs была найдена версия [3], где данный баг себя не проявил. Скачиваем пакет, распаковываем и устанавливаем как написано в Makefile. Чтобы s3fs заработал корректно, убедитесь что в системе уже установлены следующие пакеты:
Для проверки можно попробовать примонтировать бакет командой:
#/usr/bin/s3fs mybucket /mnt/mybucket/ -o accessKeyId=XXXXXXXXXXXXX -o secretAccessKey=YYYYYYYYYYYYYYYYY -o allow_other,rw -o readwrite_timeout=120;
Шаг второй: Установка pure-ftpd.
Тут казалось бы ничего интересного. Достаточно просто установить при помощи любого пакетного менеджера. Однако pure-ftpd отличается своей параноидальностью, и перед тем, как удалить файл он сперва копирует его в новый временный файл. А когда размер файла составляет несколько гигабайт, то эта процедура занимает дополнительное время. А в нашем случае, когда данные хранятся не локально, а на S3, то и совсем не малое время.
Чтобы отключить создание временных файлов перед удалением, я пересобрал pure-ftpd с опцией --without-sendfile. Конечно было бы правильнее собрать свой пакет и установить его в систему, но я делал на быструю руку и на это отвлекаться не стал.
Шаг третий: Настройка прав пользователей.
Один из самых интересных нюансов. По требованиям заказчика в каждой домашней папке пользователя должны находиться каталоги, которые пользователь удалить не может или не может в них писать. Если бы мы имели дело с обычными дисковыми разделами, то мы могли просто сменить владельца папки. Но в нашем случае это не сработает так как права будут наследоваться от опции, с которой примонтирован раздел (ro ил rw). То есть пользователь или может всё, или только читать. Но у pure-ftpd есть одно полезное свойство, он умеет «ходить» по ссылкам. Для этого во время сборки добавляем ещё одну опцию --with-virtualchroot. Таким образом, мы можем примонтировать бакет дважды, в read-only и read-write режимах и сделать ссылки на них в домашних директориях пользователей.
#/usr/bin/s3fs mybucket /mnt/mybucketrw/ -o accessKeyId=XXXXXXXXXXXXX -o secretAccessKey=YYYYYYYYYYYYYYYYY -o allow_other,rw -o readwrite_timeout=120;
#/usr/bin/s3fs mybucket /mnt/mybucketro/ -o accessKeyId=XXXXXXXXXXXXX -o secretAccessKey=YYYYYYYYYYYYYYYYY -o allow_other,ro -o readwrite_timeout=120;
#mount | grep s3fs
s3fs on /mnt/mybucketro type fuse.s3fs (ro,nosuid,nodev,allow_other)
s3fs on /mnt/mybucketrw type fuse.s3fs (rw,nosuid,nodev,allow_other)
Директория пользователя будет выглядеть так:
ls -la /mnt/Users/User1/
.
lrwxrwxrwx 1 root root 15 Mar 25 09:10 mybucketro/folder1 -> /mnt/mybucketro/folder1
lrwxrwxrwx 1 root root 15 Mar 25 09:10 mybucketrw/folder2 -> /mnt/mybucketrw/folder2
Теперь мы дали пользователю доступ на чтение в папку /mnt/mybucketro/folder1 и доступ на запись в папку /mnt/mybucketrw/folder2.На этом этапе можем считать, что пункт первый ТЗ (Данные хранятся в AWS S3) выполнен.
Шаг четвертый: Настройка высокой доступности.
Тут решено было задействовать старый добрый AWS LoadBalancer и его чудесный HealthCheck.
Открываем AWS Console и создаём новый балансер (Уверен, что повторять процесс создания балансера необходимости нет. Если что, вот напоминалочка [4]).
В Ping Protocol выбираем TCP, Ping Port — 21.
Всё, теперь жизнеспособность сервера будет проверяться по доступности 21 порта, то есть нашего FTP-сервера.
Создаем AMI с нашего сервера (на котором уже настроен FTP и примонтированы разделы). Далее всё как всегда, делаем launch-config с созданной AMI и создаём auto-scaling-group.
При создании auto-scaling-group указываем наш новый Load Balancer и опцию --health-check-type ELB.В такой конфигурации, если наш FTP-сервер «упадёт», то Load Balancer удалит его и «поднимет» новый рабочий сервер.Учитывая, что все данные мы храним на S3, то нам такая процедура не навредит.
Шаг пятый(опциональный) Всячески приветствуются ваши наработки: Настройка балансировки нагрузки и автомасштабирования.
Вопрос по балансировке нагрузки на фтп далеко не так просто решается, как, допустим, нагрузка на веб. Я с таким столкнулся впервые и, не найдя, готового бесплатного решения, предложил заказчику балансировать нагрузку с помощью ДНС.
В AWS Route53 есть опция для записей A-типа — weight. Чем выше это значение у записи, тем выше её приоритет в момент ответа клиенту.
То есть, теоретически, мы можем завести 5 записей с одинаковым weight и таким образом равномерно распределять запросы клиентов по 5-ти серверам.Для автоматизации добавления записей в AWS Route53 я сделал два скрипта. Один для добавления записи:
#!/bin/bash
zone_id="Z3KU6XBKO52XV4"
dns_record="example.com."
instance_dns=$(/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-hostname)
instance_ip=$(/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4)
let number_nodes=$(route53 get $zone_id | grep $dns_record | wc -l)+1
weight="50"
id=$(date "+%Y_%m_%d_%H:%M")
route53 get $zone_id | grep $instance_ip > /dev/null
if [ $? -ne 0 ]; then
route53 get $zone_id | grep $dns_record | awk '{print $4" "$3" "$6" "$7}' | sed 's/id=//' | sed 's/,//' | sed 's/w=//' | sed 's/)//' | while read i; do
route53 del_record $zone_id $dns_record A $i
route53 add_record $zone_id $dns_record A $(echo $i | awk '{print $1" "$2" "$3}') $weight
done
route53 add_record $zone_id $dns_record A $instance_ip 60 $id $weight
fi
Другой для удаления:
#!/bin/bash
zone_id="Z3KU6XBKO52XV4"
dns_record="example.com."
instance_dns=$(/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-hostname)
instance_ip=$(/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4)
let number_nodes=$(route53 get $zone_id | grep $dns_record | wc -l)+1
weight="50"
id=$(date "+%Y_%m_%d_%H:%M")
route53 get $zone_id | grep $instance_ip > /dev/null
if [ $? -eq 0 ]; then
route53 del_record $zone_id $(route53 get $zone_id | grep $instance_ip | awk '{print $1" "$2" "$4" "$3" "$6" "$7}' | sed 's/id=//' | sed 's/,//' | sed 's/w=//' | sed 's/)//')
fi
Скрипты использует утилиту route53, которая идёт с пакетом python-boto.
Оба скрипта помещаем на сервер, с которого делаем AMI и добавляем их вызов в стартовый скрипт Pure-Ftpd
Теперь при запуске Pure-Ftpd сам добавит в AWS Route53 новую «A» запись со своим IP-адресом, а при выключении удалит её.
Остается только добавить политики для ScaleUP и ScaleDown для нашей auto-scaling-group.
Вот и вся настройка. Такая конфигурация успешно работает на проекте уже полгода.
Если остались вопросы — пишите комментарии, по возможности отвечу. Также буду рад, если кто-то поделится своим опытом в организации подобных систем.
Автор: camec
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/30346
Ссылки в тексте:
[1] s3fs: https://code.google.com/p/s3fs/wiki/FuseOverAmazon
[2] тут: https://code.google.com/p/s3fs/wiki/InstallationNotes
[3] версия: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-r177-source.tar.gz&can=2&q=
[4] напоминалочка: http://habrahabr.ru/company/epam_systems/blog/138732/
[5] Источник: http://habrahabr.ru/post/173699/
Нажмите здесь для печати.