Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Ах, это соблазнительное желание «запилить свое приложение». Все мы с ним знакомы. Как ему не поддаться? Но столкнувшись с вопросами «как» и «где» разместить свой код, многие бросают эту затею. А это еще не было вопроса «Зачем».
В этой статье я хочу поделиться опытом, рассказать, как развернуть свое первое SaaS-приложение. Также разберем, как его развить в будущем. Это материал для тех, кто давно собирался, но не знает, как.
Что важно понять и принять сразу: ваш проект будет эволюционировать. Сперва это будет минимально работающий продукт с совсем базовым функционалом. Затем проект начнет решать все новые и новые задачи, поэтому потребует дополнительных ресурсов. В итоге эволюция приведет к тому, что ваше приложение изменится до неузнаваемости.
К чему это я? К тому, что не нужно требовать от своего проекта всего и сразу. В него не придут в одночасье сотни пользователей, это значит, что нужно начать с чего-то простого и развивать. Со временем проект будет эволюционировать под ваши потребности.
Облака
Белогривые лошадки. Начнем с того, что не стоит самим покупать «железки» и делать свой центр обработки данных. Это сложно, долго и дорого. Лучше разместите свое приложение у облачных провайдеров, используя IaaS. Так вы сэкономите деньги, время и нервы. Свой ЦОД — это удел крупных компаний со специфическими требованиями.
В современных реалиях для российского проекта стоит выбрать отечественного облачного провайдера. Например:
Selectel,
Yandex.Cloud,
Mail.ru Cloud Solutions,
CloudMTS,
SberCloud.
Также для приценки приведу стоимость сервера:
Selectel (4 ядра, 8 ГБ ОЗУ и 30 ГБ на очень быстром NVMe диске):
Yandex.Cloud (4 ядра, 8 ГБ ОЗУ и 30 ГБ на быстром SSD диске):
Сколько серверов?
Для начала вам потребуется два сервера:
Сервер тестирования (dev). На нем вы проверяете все новые фичи и исправленные баги.
Сервер эксплуатации (prod). На нем и размещаете ваше приложение для пользователей.
Помните об эволюционном пути развития проекта. В самом начале все сервисы вашего приложения будут на одном сервере:
веб-сервер,
сервер системы управления базами данных,
почтовый сервер,
все остальное, что потребуется вашему приложению.
Со временем prod претерпит изменения. Какие? Чтобы узнать, придется читать дальше!
Требуемые ресурсы серверов для вашего приложения нужно считать самостоятельно. У всех разные задачи. Помните, что сервер использующий:
менее 50% своих ресурсов работает штатно.
50-70% заставляет задуматься о дополнительных ресурсах.
90% и более не дает вашему приложению работать от слова совсем. Это катастрофа и вы единолично вызываете глобальное потепление. Должно быть стыдно.
Под процентами понимайте загруженность CPU и RAM. Конечно, не все так просто, это лишь основные величины. Есть также пиковые нагрузки и множество факторов влияющих на штатную работу вашего приложения со стороны сервера:
скорость чтения записи на диск;
ОС и ее настройки;
используемая СУБД и ее настройки;
используемый веб-сервер и его настройки и т. д.
Что еще вам обязательно понадобиться
Выбор языка программирования, СУБД, веб-сервера и много чего еще я вынесу за скобки этой статьи. Это зависит от типа вашего приложения и множества других факторов. Но есть вещи, которые обязан использовать каждый.
Система контроля и управления версиями жизненно необходима! Используйте Git, достойных альтернатив попросту нет.
Обязательно используйте хранилище кода. Тут выбор за вами: GitHub, Bitbucket или GitLab (российских аналогов пока нет). Все они имеют приватные репозитории на бесплатных тарифах и поддерживают работу с Git.
Создайте репозиторий (или несколько) для проекта в одном из хранилищ. В нем должно быть как минимум две ветки. Названия могут быть любыми, но чаще их называют как-то так:
dev – ветка для dev-сервера (создается от ветки master).
master – ветка для prod-сервера.
Клонируйте репозиторий проекта на dev-сервер и переключитесь на ветку dev. Проделайте то же самое для prod-сервера, но используйте ветку master.
Принцип такой: начали делать новую «фичу» или исправлять «баг» — создаете новую ветку от ветки dev. Закончили работу в новой ветке — вливаете ее в ветку dev. Получаете и тестируете все на dev-сервере. Если все хорошо, то вливаете ветку dev в ветку master и выкатываете изменения на prod-сервер.
Разверните сервера на ОС Linux. Чаще всего используют Centos 7 или Ubuntu 20.04 LTS. Могут быть и другие Linux, выбор за вами. Важно использовать версии ОС с длительным сроком поддержки (Long-Term Support — LTS).
ОС от Microsoft (Windows Server) используется только для специфичных проектов, где без нее не обойтись. Не забывайте, что за лицензию регулярно придется доплачивать облачному провайдеру.
Я рекомендую «заскриптовать» развертывание сервера. Создайте репозиторий с bash-скриптами, которые устанавливают необходимые сервисы, «подсовывают» в них нужные конфиги и поднимают (запускают) их. Да, на это нужно потратить время, но вы получите ряд преимуществ:
dev и prod вы развернете с одних и тех же скриптов, причем, абсолютно одинаково, ничего не забудете. Поверьте, это сэкономит кучу нервных клеток.
сервера не должны «падать», но они так иногда делают. Скрипты помогут вам быстро «поднять» новый сервер, причем точно такой же, как старый.
Админы делятся на три типа: которые не делают бэкапы, которые уже делают бэкапы, которые проверяют созданные бэкапы. Давайте угадаем, кто поступает правильно.
Обязательно делайте бэкапы данных — дампы баз данных, файлов пользователей и т. д. Их можно хранить у тех же облачных провайдеров, это не очень дорого. Конечно, все зависит от объема, но хранение пары сотен ГБ обойдется дешевле стоимости сервера, приведенного выше. Если ваша система позволяет работать с файлами, хранящимися в удаленной корзине типа S3, то сразу храните файлы в таких хранилищах у облачных провайдеров.
Не забывайте про файрвол. Эта ваша первая линия защиты, ведь ваш сервер доступен из сети Интернет.
Если ваше приложение работает через браузер, а все остальное пока находится на том же сервере, то достаточно открыть SSH, HTTP и HTTPS и закрыть остальные порты. Современные IDE и клиенты СУБД прекрасно умеют работать «over SSH». Поищите, как это настроить и вы прикроете множество уязвимостей для вашего приложения.
Еще я бы порекомендовал поменять SSH порт с 22 на какой-нибудь другой, например, 2200 и использовать SSH-ключи вместо логина и пароля.
Если облачные провайдеры предоставляют файрвол, который стоит на границе облачной сети и Интернет — настраивайте его. Если нет, то разворачивайте свой сервер (на ОС Centos 7), устанавливайте iptables и заскриптуйте правила при помощи bash. В следующий раз, когда вам понадобиться что-то открыть или закрыть, то вы допишете правило в скрипт и выполните его. Это лучше, чем вычитывать, что же у вас открыто и закрыто действующими правилами. Принцип написания скрипта прост:
Сбрасываете все действующие правила.
Объявляете политику по умолчанию (я предпочитаю «Все запрещено»).
Разрешаете то, что необходимо. Например, SSH, HTTP и HTTPS.
Я всегда делаю три скрипта. Вкусовщина, конечно, но мне так удобнее. И да, скрипты я обязательно храню в репозитории.
Скрипт, который сбрасывает все правила и ставит политикой по умолчанию «Все разрешено». Иногда надо быстро проверить, не в файрволе ли проблема.
Скрипт с постоянными правилами. Принцип его написания я описал выше.
Скрипт сохранения правил, использующий утилиту iptables-save. Нужен потому что iptables хранит изменения правил только до перезагрузки ОС. Чтобы сохранить нужные правки, используем этот скрипт.
Уследить за всем будет непросто, а стикеры на мониторе могут быстро заполонить все свободное место. И организовать собственное государство. Поэтому искренне надеюсь, что вы используете какой-нибудь таск-трекер. Опять-таки, в наших реалиях платформа нужна российская. Варианты:
Flowlu.
Аспро.Agile.
Kaiten.
Битрикс24.
YouGile.
Количество пользователей растет
Значит нагрузка на prod-сервер тоже увеличилась. Вы оптимизируете код и запросы в СУБД. Это временно помогает, но не решает проблему, так как пользователи все приходят. В этом же и была цель приложения?
Пришло время изменить архитектуру prod-сервера. Дело это не быстрое, поэтому нужно выиграть время. В этом поможет вертикальное масштабирование. Пока просто добавьте ресурсы на prod-сервер: CPU, RAM, увеличьте объем диска.
Вам придется разделить сервисы. Возможно, реализовать микросервисную архитектуру. В любом случае prod-сервер будет уже не один.
Архитектура с «Бастионным узлом»
Смысл этой архитектуры очень прост: абсолютно все запросы из интернета проходят через единый файрвол. Реализован он может быть по-разному. Некоторые облачные провайдеры уже предоставляют такой файрвол, и вам потребуется лишь настроить на нем правила с проброской портов.
Есть другой вариант: развернуть свой сервер с минимальными характеристиками. 1 ядро, 1 ГБ ОЗУ и минимальный, пусть даже медленный, диск. Ставите на него Centos 7 и iptables. Создаете репозиторий и скриптуете правила iptables с проброской по порту на нужный сервер.
В первую очередь с единого prod-сервера выносят СУБД. Возможно, что вам потребуется вынести что-то еще. Смотрите, что создает нагрузку и выносите этот сервис на отдельный сервер.
Если вы ранее скриптовали установку prod-сервера, то теперь вы создаете два репозитория. В один выносите скрипты по развертыванию СУБД, а в другой все остальное. Разворачиваете два сервера: СУБД и приложения. На файрволе делаете проброску портов HTTP и HTTPS на сервер приложений.
Так, стоп. Мы же не пробросили SSH? Конечно, это можно было сделать. Но я предлагаю подумать о будущем и сделать лучше.
Нужно развернуть еще один сервер, который называется терминальным. Пока хватит 2 ядра, 4 ГБ ОЗУ и быстрого диска на 20 ГБ. Терминальный сервер будет работать под управлением ОС Ubuntu 20.04 LTS с графическим интерфейсом, службой VNC и/или RDP. Также на него следует поставить IDE и клиент СУБД. Позже на нем можно развернуть средства мониторинга всех серверов. Например, grafana+prometheus или zabbix. Осталось пробросить SSH-порт на файрволе к терминальному серверу.
На терминальном сервере у нас развернут VNC и/или RDP, а проброшен только доступ по SSH. Так зачем тогда вообще нужен графический интерфейс?
Ответ прост: нужно подключаться VNC over SSH и/или RDP over SSH. До файрвола у нас будет шифрованный канал (SSH), а на терминальный сервер мы подключимся уже по графическому интерфейсу. В итоге терминальный сервер будет вашим рабочим местом в приватной облачной сети. На него можно установить любое нужное ПО и безопасно подключаться к облачным серверам.
Какие преимущества мы получим от этих действий:
Сервисы на разных серверах, а значит можно более тонко настраивать потребляемые ресурсы, оптимизировать производительность и стоимость.
Единая точка входа «Бастионный узел»:
Очень легко контролировать доступ.
Скрытая архитектура вашего приложения.
Легко масштабироваться в дальнейшем.
Работа на серверах только с доверенного устройства — терминального сервера.
Шифрованный канал связи, но в отличие от VPN дополнительные настройки не требуются.
Используйте Docker, а лучше docker-compose
Пользователей все больше, а значит для поддержки и разработки приложения требуется больше разработчиков.
И тут мы сталкиваемся с еще двумя проблемами:
Каждому программисту нужно обеспечить рабочее место с локальной версией системы. До этого разработчик разворачивал и настраивал самостоятельно все компоненты системы руками.
У разработчика на ПК новая «фича» работала нормально, залили на dev-сервер — ничего не работает. Чудеса, да и только. У этой проблемы даже есть имя: различные среды для разработки, тестирования и эксплуатации.
Обе проблемы можно решить при помощи docker-compose. Также нам опять пригодятся скрипты, которые делали для развертывания серверов. Теперь в них можно заменить установку, настройку и запуск сервисов yml-файлом docker-compose.
Да, конечно, скрипты развертывания локальной, dev и prod версии системы будут отличаться, но в них много общего. Главное: мы получим единую среду разработки, тестирования и эксплуатации. Поверьте, это очень важно.
Если вы подготовите развертывание приложения через докер к моменту перехода на архитектуру с «Бастионным узлом», то убьете двух зайцев:
Заяц 1: Вам не потребуется еще раз развертывать сервера и переносить данные.
Заяц 2: В вашем приложении еще нет тысяч пользователей и процесс миграции на современные технологии будет менее болезненным. Чем дольше вы будете оттягивать переезд на Docker, тем будет сложнее миграция.
А что дальше?
После всего вышеописанного можно посоветовать:
Автоматизировать развертывание кода через pipeline, используя концепцию CI/CD.
Мониторить нагрузку и переходить на горизонтальное масштабирование ресурсов с использованием балансировщиков нагрузки при необходимости. Я бы посоветовал посмотреть в сторону Kubernetes. Тем более некоторые облачные провайдеры предлагают его в качестве PaaS. Но не забывайте, что ваше приложение должно уметь работать с балансировщиком нагрузки.
В заключение повторюсь: приложение должно эволюционировать, постепенно адаптироваться под реалии.
Мир ИТ очень динамичен. То что актуально и в тренде сейчас, через некоторое время может быть заменено, изменено или просто устареть.
Не отставайте от актуальных трендов, но и не пытайтесь прикрутить все фичи сразу. Сперва подумайте, есть ли в них смысл для вашего проекта и стоят ли они ресурсозатрат.