[Из песочницы] Архитектура и стоимость простого бессерверного веб-приложения Amazon Web Services

Введение

Весной этого года я сидел в локдауне на Багамах, без права сходить на берег и, борясь со скукой, решил посмотреть, что это за зверь такой Amazon Web Services, и да, я пропал. Случилось, что называется, любовь с первого взгляда. Одной из технологий, что пьянила меня не хуже багамского рома, были бессерверные вычисления.

zqrtip-dcv8j8qhjyd_xuccs4ng.jpeg

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

Я их понимаю. Толстые железные сервера обеспечат их подразделения ИТ-инфраструктуры хлебом с маслом на долгие годы. Так что, эта история не для них, а для тех, кто еще не потратил на инфраструктуру ЦОДа несколько десятков чемоданов денег и хочет при этом пользоваться всеми благами цивилизации.

Удивительно, но термин «бессерверные» придумали не маркетологи, а деятель по имени Остин Коллин в 2015 году. Идея была проста — зачем каждой организации содержать штат админов? Лучше согнать всех админов в одно место, запастись для них Budweiser и пусть они админят свои сервера где-то далеко под землей. Бизнес должен быть сосредоточен на бизнесе и в плане инфраструктуры ему достаточно ответить на один простой вопрос — как много бабла я готов платить в месяц за используемые мощности. Ведь вся прелесть бессерверных технологий, что горизонтальное масштабирование ограничено только размером кошелька. Причем масштабирование может быть осуществелно в автоматическом режиме. На днях я забыл остановить стресс тест для одного проекта и был неприятно удивлен размером выставленного счета. Это обратная сторона медали, которая, к слову, легко решается сервисом AWS Billing Alert.

Итак, мы решили создать наше первое бессерверное приложение, но не по какому то туториалу, где множество ограничений, а почти по-настоящему. Почти, потому что, кроме «Hello World» это приложение ничего не делает, но зато сколько всего в этом задействовано!


Архитектура приложения

thcuqkcnqduo9lj2pwtsbxa_4ii.png

Приложение состоит из четырех основных частей:


  • Хранилище статического контента на базе AWS S3;
  • Авторизация через AWS Cognito User Pool;
  • Обработка динамического вызова API с помощью API Gateway и Lambda Function;
  • Хранилище данных в NoSQL БД DynamoDB.


Статический контент в AWS S3 корзине

AWS S3 — это объектное хранилище данных, ставшее, можно сказать, стандартом в индустрии. Mail.ru, Яндекс, Мегафон — используют устоявшийся термин Simple Object Storage и совместимое с AWS S3 API.

Одна из фишек S3 — это возможность использования корзины в качестве веб-сервера статического контента. То есть мы просто загружаем все наши CSS, JavaScript и HTML в корзину и ставим галку «Static Web Hosting». Но есть одно «Но». Доступ к корзине по HTTP возможен только без шифрования. То есть включил галку хостинг, открыл доступ для всех анонимусов и вот тебе такой открытый всем ветрам веб-сайт. Нам это не подходит. Ничего не могу сказать плохого про анонимусов, но наш «Hello World» должен быть доступен только для авторизированных пользователей и только с использованием SSL, да еще желательно, чтобы прямого доступа к корзине никто, кроме владельца аккаунта, не имел.

И тут нам на помощь приходит сервис дистрибьюции CloudFront, что доставляет контент близко к пользователям по всему миру, за исключением 1/6 части суши. То есть даже в Африке есть edge location, а в России нет. И появится ли не известно. В России, кстати, есть свои сети доставки контента, и я подумываю провести эксперимент по интеграции двух сервисов.

Для возможности использования SSL мы в сервисе Certificate Manager выпускаем бесплатный сертификат по имени нашего домена и привязываем его к нашей CloudFront дистрибьюции, после чего наш контент становится доступен по HTTPS, который терминируется на CloudFront edge location и дальше идет по сети AWS в незашифрованном виде. Но наша корзина S3 надежно защищена политиками и доступ к ней имеет только владелец аккаунта и созданная нами дистрибьюция. Конечно, для параноиков есть возможность зашифровать саму корзину при помощи SSE-KMS и перешифровывать его SSL при помощи Lambda@Edge на edge location. Но сегодня мы не такие параноики и не будем так делать.

Перед CloudFront сидит DNS сервис Route 53, и мудро перенаправляет трафик, направленный в сторону нашего домена к дистрибьюции CloudFront.


Cognito User Pool

Задача этого сервиса — выполнять функции подписки, верификации по е-мейлу или телефону и авторизации для веб пользователей и пользователей мобильных приложений. Amazon Cognito умеет работать с внешними поставщиками удостоверений, которые поддерживают стандарты SAML или OpenID Connect, с социальными платформами (Facebook, Twitter, Amazon) и позволяет использовать собственный поставщик удостоверений.

bwu-f2ih71ufyf8ym0gcmh7qvfu.png


  1. Клиент запрашивает токен;
  2. Cognito User Pool верифицирует пользователя у поставщика удостоверений либо делает это самостоятельно;
  3. Cognito User Pool возвращает клиенту токен;
  4. Клиент использует токен для доступа к приложению.

Чтобы все это работало с нашим приложением мы используем Cognito SDK для JavaScript. Теперь у нас неавторизованный пользователь переадресуется на созданную нами страницу регистрации и входа в систему. Мы, конечно, можем использовать функцию предоставления пользовательского интерфейса авторизации Cognito Hosted UI, где уже преднастрены страницы входа в систему, восстановления забытого пароля, MFA и интеграции по SAML. Но, на сегодняшний день эта функция доступна только на английском языке, что, честно говоря, меня удивляет и расстраивает. Казалось бы, глобальный сервис…

Список атрибутов пользователя по — умолчанию соответствует спецификации OpenID Connect, но никто нам не запрещает использовать наши собственные кастомные атрибуты. К сожалению, после того как в пуле появились пользователи атрибуты изменить не удастся и надо создавать новый пул и мигрировать в него пользователей, но может это и к лучшему.


API Gateway и Lambda Function

API Gateway — это высокопроизводительный шлюз для HTTP, Rest API и Web Socket. Мы создаем на шлюзе ресурс и его метод GET перенаправляет запрос к нашей Lambda функции. А чтобы враг не прошел, мы настраиваем на шлюзе Authorizer и без токена в зубах никого к нашей функции не подпускаем. При этом мы наступаем со всей дури на грабли CORS, о которых молчит большинство туториалов, грабли, связанные с интеграцией Lambda proxy и необходимости явно прописывать в API заголовки для каждого HTTP статуса. В свою очередь наша функция при помощи библиотеки boto3 может общаться с любым ресурсом AWS, но только при наличие правильно настроенных разрешений.

Страшилка на ночь
В самом начале я писал, как можно попасть на бабки просто забыв погасить инстанс EC2. Без правильно настроенных разрешений можно попасть по самые помидоры и мир полон страшных историй, как за одну чорную-чорную ночь списалось 10к денег из-за ошибок в настройке разрешений.


Хранилище данных в NoSQL БД DynamoDB

В нашем приложении для полноты картины не хватало внешнего источника данных, и мы создаем таблицу DynamoDB из одного элемента: id = UUID identifier; Text = «Hello World».


И что в итоге:


  • Пользователь отправляет запрос к нашему веб-приложению;
    Route 53 переадресует запрос от нашего домена к сети дистрибьюции CloudFront и находит ближайший к пользователю edge location;
  • CloudFront решает выдавать ли статический контент из кэша или переадресовать запрос в корзину;
  • JavaScript на странице понимает, что пользователь не авторизован и переадресует его на страницу входа в систему;
  • Cogito User Pool верифицирует пользователя и возвращает токен;
  • Этот токен вместе с запросом отправляется в сторону API Gateway, который проверяет наличие токена;
  • Если токен валидный шлюз передает запрос Lambda функции;
  • Та запрашивает БД и возвращает приветствие миру, которое вернувшись в код JavaScript появляется на экране счастливого пользователя.


А теперь о бабках

Джеф Безос все-таки акула бизнеса. И он уже придумал как сортировщикам товаров подавать сигналы прямо в голову, чтобы они сортировали более сортировочно. Так что халявы, казалось бы, не будет. И вообще, сколько может стоить вся эта бессерверная история для стартапа на коворкинге в Бургер Кинг?

К нашему счастью в AWS существует такая фича как «уровень бесплатного пользования». Это как первые 3 дозы хмурого за счет дилера, но рано или поздно придется платить по счетам самому. Но в отличие от диллера, если вы знаете параметры вашего сервиса, то можно оценить его стоимость при помощи инструмента AWS Pricing Calculator.

Базовая тарификация у используемых нами сервисов, следующая:


S 3


  • Уровень бесплатного пользования — 5 Gb.
  • Превышение — $0,02 за Gb в месяц.
  • Исходящий трафик тоже не бесплатен — $0,09 за Gb
  • И запросы PUT, GET и прочие тоже — $0,005 за 1000 запросов


CloudFront


  • Уровень бесплатного пользования — 50 Gb исходящего трафика, трафик внутри сети AWS не оплачивается;
  • Превышение — $0,08 за Gb, то есть распространять трафик через CloudFront немного дешевле, чем напрямую к S3;
  • Дополнительные фичи, типа шифрования полей или выделенного IP адреса, стоят отдельных денег.


Cognito User Pool


  • Уровень бесплатного пользования — 50к MAU (активных пользователей в месяц) для пользователей Cognito User Pool и всего 50 MAU для пользователей, авторизирующихся через SAML;
  • Превышение — $0,005 за MAU;
  • За SMS верификацию платить нужно отдельно.


API Gateway


  • Уровень бесплатного пользования — 1кк запросов в месяц;
  • Превышение — $3,5 за 1кк запросов.


Lambda


  • Уровень бесплатного пользования — 1кк запросов в месяц, 400к Гб-секунд (Без паники. Всего лишь время выполнения умноженное на объем используемой памяти)
  • Превышение — $0,0000166667 за Гб-секунду.

Секрет мастерства:
Тарифицируемый минимум — это 100 миллисекунд. Наша функция выполняется за 2. То есть можно 50 раз запросить «Hello World» за эти же деньги или нагрузить ее другим, не менее полезным функционалом. Так что обязательно смотрим в CloudWatch Logs Insights и оцениваем, что почем.


DynamoDB

В DynamoDB с расчетами все не совсем просто и стоимость зависит от выбора модели согласованности данных. Условно — чем ниже согласованность, тем больше данных в одном юните 1–4–8 Кб.


  • Уровень бесплатного пользования — нет;
  • RCU (чтение) — $0,25 за 1кк юнитов;
  • WCU (запись) — $1,25 за 1кк юнитов;
  • За хранение данных и непрерывное резервное копирование (да-да, есть и такая фича), глобальные таблицы и прочие плюшки придется платить отдельно;
  • И за трафик тоже.


Вместо заключения

В нашем тестовом приложении мы уместились в уровень бесплатного пользования за исключением таблицы DynamoDB. Ее существование встало нам в круглую сумму $0,59 в месяц, что при нынешнем курсе доллара вполне приемлемо.

Так что у нас в распоряжении есть отличный инструмент, позволяющий реализовывать практически любые фантазии практически бесплатно.

Зима будет длинной и холодной — самое время начать творить в облаке.

© Habrahabr.ru