Хостинг майнкрафт серверов — и зачем такая сложная архитектура?

от автора

Привет! Это вторая часть статей про хостинг серверов Minecraft, который мы строим. В первой части я рассказывал про физическую часть инфраструктуры — от ноутбука до серверной стойки. В этой же мы погрузимся в её логическую часть без долгой исторической справки. Через тернии к k8s, приятного чтения.

В нашем историческом рассказе мы не будем соблюдать логические части, и просто построим примерно такую agend’у:

Интересно, зачем такая архитектура нужна обычному майнкрат-хостингу? (честно говоря, мне тоже интересно) Тогда пошли погружаться вместе!

Part 0: чуть-чуть истории и дисклеймер. 

Всё описанное ниже — это не больше чем наше любительское видение и попытки побыть архитекторами, тим-лидами, CEO компании и так далее. Напомню из первой части статей, фактически мы являемся командой из двух человек: я отвечаю за инфраструктуру, а второй «создатель» — за всё, что связано с разработкой. 

Всю нашу деятельность мы строили и продолжаем строить на одной важной особенности, которая, наверное, отличает нас от остальных: мы учимся чему-то новому или пытаемся разобраться в чем-то больше, чем просто на поверхности (рассмотрим простой пример с инфраструктурой: на работе «N» я узнал, что такое k8s. он уже был засетаплен и хорошо работал. вместе с этим я не понимал, как его варить, устанавливать и работать с ним чуть больше, чем писать манифесты. и на живом пет-проекте я могу это обкатать и протестировать, даже несмотря на то что это не такой большой хайлоад). 

В общем, не судите строго 🙂

Part 1: зоопарк серверов и облаков. 

Перед дальнейшим погружением в логическую часть сначала я остановлюсь на небольшой физической части рассказа — про географию инфраструктуры. 

Важным разделением должно быть следующее: инфраструктурные сервера и пользовательские. Те, на которых непосредственно размещаются Minecraft докер контейнеры мы называем «нодами» — просто для удобства. Основная  часть инфраструктурых серверов переехала с «балкона» (если вы не знаете это понятие, прочитайте первую часть статьи про физические сервера!) в collocation в один Московский ЦОД. Вторая часть — один физический сервак — у нас находится в Hetzner. 

С нодами ситуация интереснее: покупать сервера по всему миру и ставить их в collocation как минимум дорого, как максимум на данном этапе не имеет смысла, поэтому мы, как и большинство людей, арендуем их у других хостингов. Стараясь строить распределенную инфраструктуру, на данном этапе наше географическое присутствие находится в четырех странах:

  • Финляндия

  • Германия

  • Франция

  • Россия

Первые две страны — Германия и Финляндия, думаю вы уже догадались, выбраны абсолютно понятно почему: именно там Hetzner предоставляет dedicated-сервера для всех. Франция используется исключительно под часть antiddos-инфраструктуры и там нет как таковых пользовательских нод. 

С Российской частью всё намного интереснее. Наши точки присутствия находятся в Москве, Санкт-Петербурге и недавняя новая локация — Екатеринбург. 

Первые два города выбраны опять же логично — в Европейской части России больше всего игроков, и наименьший пинг от клиента будет либо до Москвы, либо до Питера. А вот Екатеринбург появился по многочисленным запросам от наших клиентов, которые находятся ближе к Азиатской части России или в странах СНГ (e.g. Казахстан). Звучит не так страшно, однако для одной Москвы мы пользуемся несколькими хостерами, и вот почему:

  • Selectel — довольно надежный партнер, который мы использовали с начала времен. Цены у него немного выше, чем у конкурентов, однако исторически сложилось что аптайм их серверов самый большой 

  • Cloud4box — после некоторых ситуаций, которые сложились в России, и увеличения курса Евро, нам пришлось искать альтернативы Hetzner с более дешевыми серверами, но процессорами, которые подходят под наши условия: нам нужно меньше ядер, но больше гигагерц на одно ядро — выбор пал на этих ребят по соотношению цена/качество

  • Smartape — бесплатный готовый antiddos от ddos-guard и сравнительно хорошие цены 

  • Ekacod — один из немногих постеров в центральной и азиатской части России, который нам подошел

Суммарно у нас около 30 физических серверов и примерно столько же виртуалок — они находятся на инфраструктурных гиперах. Мы используем стандартный подход для этого — Proxmox, а в Москве прикрутили к нему ceph для возможности live-миграции (и, конечно же, чтобы разобраться как он работает). 

В общем, с инфраструктурой разобрались, и теперь давайте погружаться дальше. 

наши точки присутствия

наши точки присутствия

Part 2: автоматизация.

С таким зоопарком нет никакого желания катить всё руками или даже баш-скриптами, а еще, конечно же, нужно улучшать свои знания в направлении ансибла — поэтому мы его и используем. Всего у нас два глобальных репозитория: под инфраструктуру и под ноды. Collocation так же разделяется на часть: фронты, мониторинг и всё остальное. Получается небольшая, но все же ветвистая структура. Давайте посмотрим детальнее как выглядит процесс разворачивания инфраструктуры на нодах. 

Итак, мы арендовали сервак, что дальше?

  • В репозиторий с terraform коммитим IP-адреса, которые потом раскатываются в Cloudflare DNS через простой gitlab-ci, таким образом нет необходимости самостоятельно идти в админку, что-то править, по пути перезатереть или сломать 

  • Записываем в hosts.yml в ансибле новый сервак, добавляем на него свой ssh-ключ и запускаем плейбук. Через полчаса мы раскатим всё и начнем принимать пользователей на новую ноду

roles:   - {role: 'base',  tags: ['base', 'base']}   - {role: 'docker',  tags: ['docker']}   - {role: 'node-exporter',  tags: ['node-exporter']}   - {role: 'promtail',  tags: ['promtail']}   - {role: 'letsencrypt',  tags: ['le']}   - {role: 'certbot', tags: ['le-ssl']}   - {role: 'wings', tags: ['wings']}   - {role: 'mysql-master-slave',     mysql_db: [       { name:  },     ],     mysql_users: [       { name: , pass: , priv: «» },     ], tags: [ 'mysql-master-slave' ]   }   - {role: 'cron-minecraft', tags: ['cron-minecraft']}   - {role: 'nginx-placeholder', tags: ['nginx-placeholder']}   - {role: 'superhub-node-monitoring', tags: ['superhub-node-monitoring']}   - {role: 'superhub-25565',  tags: ['25565']}   - {role: 'logrotate', tags: ['logrotate']}

Структура ролей так же выглядит довольно просто:

  • Base катит базовые настройки самой ноды: ssh-key авторизация, sysctl, пользователей и так далее

  • Docker, соответственно, ставит сам докер — он нужен для работы Minecraft-серверов, так как в архитектуре пользовательских под все сервера запускаются в отдельных контейнерах

  • Node-exporter катит базовый мониторинг (в отличии от инфры — в Московском ЦОДе мы так же используем consul для SD, потому что виртуалки появляются намного чаще, чем физические сервера)

  • Promtail нам нужен для сбора логов с демонов wings (об этом чуть позже) и логов бэкапов — мы хотим быть уверенными, что всё отработало корректно 

  • Certbot катит сертификаты, которые также нужны для корректной работы Wings 

  • Wings — это опенсурсный демон pterodactyl — панели, которую мы используем для управления пользовательскими серверами. Он ставится на каждую ноду и централизованно управляется из панели (про панель я расскажу в разделе про куб)

  • Cron-minecraft, nginx-placeholder, superhub-node-monitoring и остальные роли ниже — это всё наши кастомные роли, которые катят наши внутренние демоны и различные скрипты. Сюда мы включаем как кастомный мониторинг для нашего бекенда, автоматические бэкапы данных и баз данных 

После прокатки этого плейбука мы считаем ноду готовой к приему трафика и помечаем её в нашей базе данных как «открытую» — начиная с этого момента, пользователи могут арендовывать на ней ресурсы

Инфраструктурные плейбуки отличаются по своей роли, но имеют похожую структуру. Мы не используем никакой рокет-саенс, не делаем вложенные друг в друга роли и не пишем свои модули (а надо бы), поэтому копировать пример с инфрой нет смысла. Думаю, для всех очевидно, что как с нодами, так и с инфрой мы не катим руками пром / nginx и его различные конфигурации — за всё это отвечает ансибл, а в ряде случаев так же мы используем gitlab-ci — чтобы еще больше минимизировать ручные действия по запуску. 

Итого, что мы включаем в себя слово «автоматизация» на хостинге:

  • Terraform в минимальном виде для Cloudflare

  • Ansible для всего чего только можно

  • Kickstart+PXE, Cloudinit для разворачивания виртуалок в ЦОДе 

Part 3: любимое — мониторинг.

Вместо тысячи слов предлагаю взглянуть на картинку и вместе ее разобрать по кусочкам:

У нас есть 3 главных мониторинга:

  • Prometheus + Victoria Metrics

  • Elasticsearch 

  • Uptime Kuma

Давайте посмотрим на схему и разберемся, что зачем нужно. 

Elasticsearch

Сюда мы отправляем все netflow данные. Мы решили использовать готовое опенсурсное решение от elastiflow с базовой лицензией, которая позволяет получать до 4000 flow/sec, этого нам вполне достаточно. Необходимость данной системы в принципе обусловлена особенностью майнкрафт-сообщества (и, наверное, в целом игровых хостингов) — на них идут периодически малые или даже большие DDOS-атаки, которые вполне могут вывести гипер/ноду из строя на какое-то время. К сожалению, превентивно детектировать атаку мы не умеем, но вместе с этим ретроспективно и быстро реагируем на неё во время каких-либо проблем. Netflow собирает данные как с src/dst по IP-адресам, так и (что нам особенно важно) на какой порт заливается трафик. Этот детек позволяет нам связываться с клиентом напрямую и сообщать ему о случившемся и реагировать на инцидент ему — подключать внешнюю antiddos-защиту. 

На пользовательских нодах стоит softflowd демон, который по UDP отправляет весь netflow в flowcoll, который в свою очередь шлет данные в ELK. На уровне «балкона» отправкой таких данных занимается mikrotik — так как это входная точка всего трафика. Вот так это выглядит на уровне Кибаны:

Prometheus and so on

Исторически сложилось так, что мы хотели более отказоустойчивую инфраструктуру: на случай выпадения балкона всё равно иметь доступ к метрикам. Поэтому prometheus изначально сетапился на инфровой тачке в hetzner. Там же remote_write находится victoria metrics для long-term хранения метрик. Этот пром собирает данные со всех нод и других серверов не в периметре балкона. Мы мониторим как базовые метрики по типу node_exporter, так и часть других: cadvisor и blackbox (как альтернатива uptime-kuma для внутреннего мониторинга). Эта схема, я уверен, довольно базовая для большинства всех текущих компаний или любых других инсталляций (не забываем про alertmanager и вот-это-все). 

На другой стороне находится prometheus на балконе, который отправляет долгосрочные метрики так же в remote_write кластер. Единственным отличием внутреннего прома является consul SD — виртуалки на гиперах появляются и исчезают чаще, чем закупаются dedicated-серверы, и чтобы ничего нечаянно не забыть, мы постарались снизить ручной фактор в виде не пролитого конфига. Внутренний пром также собирает метрики по nginx vts для алертинга по 5хх ошибкам и далее.  Такая же схема у нас действует в k8s: prometheus в кубе шлет метрики в Victoria, и дальше мы их рисуем в графане на нужных дашбордах. 

Кстати, о графане. Тут у нас также нет никакого rocket sience и мы используем максимально стандартные дашборды для всего, чего только можно. Единственным отличием является классный дашборд, который нравится мне :). Я попытался сделать что-то наподобие «бизнес метрик» приложения, в котором мы строим данные по: 

  • Количестве платежей

  • Количестве пополнений баланса и суммы пополнения баланса 

  • Количестве зарегистрированных пользователей 

  • Метрики по активным запущенным серверам

  • Фейлы бэкапов, 504 панели (это важно для нас) и несколько других показателей.

Uptime kuma

Это такая альтернатива платным status page сервисам, которую мы хотели использовать для предоставления клиентам верхнеуровневой информации о «живости» той или иной системы. Если интересно, можете ознакомиться с ней по ссылке — status.superhub.host.

К сожалению, у kuma v1 есть несколько глобальных архитектурных проблем, которые разработчики обещают поправить в v2 версии. Самая главная проблема, с которой мы столкнулись — хранение всех данных в sqlite, что безумно медленно для нас (несмотря на небольшое количество проберов).

А как пофиксить?

Кстати, если вы используете kuma у себя на проекте и хотите убыстрить её работу — урежьте хранение данных до 1 дня и сделайте очистку базы sqlite — это значительно поможет и прирост в загрузке страницы будет значительным. 

Мы рассматриваем альтернативные варианты Kuma и, возможно, смотрим в сторону своего собственного статус-пейджа на базе Blackbox, однако сейчас у нас нет ресурсов на собственную разработку. 

Part 4: почти дочитали до конца — бекапы.

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

Почему забывают?

В течение 4 лет работы нашего хостинга мы столкнулись с несколькими прецедентами безопасности. Некоторых взламывали из-за уязвимости, кого-то — из-за того что у них не было 2FA. Однако с кем бы мы ни общались по итогам взломов — ни у кого не было даже малейших намеков на бекапы. (Правда стоит учитывать, что если вас взломают не просто в админке и удалят базу, а получат доступ к серваку или, что еще хуже, к серверу с бекапами — вам всё равно это не поможет, но давайте не будем говорить о грустном)

Посчитайте, сколько раз в этой статье упоминается разделение на пользовательские ноды и инфраструктурные сервера? И добавьте к этому +1. Сначала мы поговорим про инфровые бэкапы, а после упомянем о вторых. 

У нас есть 2 s3-провайдера, которые мы используем: minio на сервере в hezner, который имеет hot-storage с NVME дисками и cold-storage с HDD. Для ряда бакетов настроена ротация hot-бекапов на cold, так как cold storage Tb >> hot storage Tb

Бэкапы баз данных

В нашей архитектуре мы используем Xtradb Cluster с PMM на внешнем серваке для мониторинга. Бэкапы настроены через xtrabackup, которые создают их по крону раз в 3 часа. Таким образом мы всегда сможем откатиться на самую актуальную версию базы, потеряв всего 3 часа данных пользователей. Мы также используем Postgres для Jira и ряда других инфраструктурых сервисов, бэкапы которых улетают в s3. 

Бекапы на нодах

Одна часть бекапов улетает на minio s3 — это пользовательские бэкапы, а вторая — на внешний s3 у хостера. Давайте поймем, почему так. 

В панели управления сервером майнкрафт заложена возможность автоматического или ручного создания бекапа. За это отвечает тот же демон wings, который просто архивирует сервер и отправляет его в наше hot-s3 хранилище. При удалении сервера пользователем бекапы так же удаляются, и мы сокращаем используемое место. Самым важным пунктом в выборе своей системы против готовых и отказоустойчивых — это цена. Мы испытываем относительно немалые нагрузки по сети и количестве GET/POST/PUT запросов при загрузке пользовательских бэкапов. (К сожалению, некоторые клиенты не знают, что такое cron, и настраивают бэкапы * 0 * * * Да, бывает и такое). Если размещаться у s3-провайдеров, то по предварительной оценке мы будем платить за хранение пользовательских бэкапов примерно 1/3 стоимости всех инфраструктурых серверов в месяц. Кажется, это не целесообразно. 

С другой стороны мы все-таки используем внешнее s3-хранилище, но уже для наших личных автоматизированных бэкапов, а именно: при возможных проблемах на стороне хостинга — взлом сервера, удаление данных через панель или rm -rf, удаление данных самим пользователем (или взлом пользователя) мы добавляем небольшую прослойку в виде безопасности и бекапа всех данных раз в сутки в самое ненагруженное время — от 00:00 до 06:00 (время выбирается рандомно ансиблом в кроне). Эти бэкапы мы отправляем на внешнее хранилище по двум причинам: объем и количество данных. В этом случае нам дешевле и безопаснее хранить эти данные самостоятельно и платить за них и также контролировать возможный расход, который можно снизить, оптимизируя различные варианты бэкапов. 

Part 5: k8s.

Наверное, это будет самая большая часть повествования, однако я сразу отвечу на вопрос: да, мы захотели куб. Да, мы просто учимся чему-то новому. А теперь давайте погружаться в схему

Думаю, схема до k8s всем понятна, логична и не нуждается в обсуждении, поэтому мы сразу пойдем на уровень за ingress. Входной точкой любого пользователя может быть 2 домена: superhub.host и panel.superhub.host. Второй отвечает исключительно за управление своим сервером, в то время как вся магия покупки, оплаты, изменения характеристик сервера находится на нашем основном сайте

Вы попали на main front — это nextjs, который сварил вам нашу страничку. На ней вы так же увидели счетчик запущенных серверов — для этого вы обратились в /v2, а апишка в свою очередь получила эти метрики из мониторинга. Остальные данные о стоимости серверов, отзывах и так далее мы также забираем из /v2. Если клиент захочет зайти на /wiki, то эту страницу мы отрисуем с помощью прокси в GitHub — каждый пользователь может прислать нам PR на редактирование или создание новой статьи, а мы красиво оборачиваем это в текущий дизайн сайта. 

При авторизации мы используем свой auth-сервер и бекенд, которые хранят авторизационные данные в redis под каждого пользователя, а сверяют логины в отдельной базе. 

При покупке сервера клиентом мы записываем эти данные в отдельную «базу коллекторов» (нет, мы не передаем эти данные коллекторам(!), но звучит это довольно нео — там мы храним много информации: день и время списания, успешное оно или нет, сумма, как изменился баланс пользователя и многое другое. Коллектор-воркеры занимаются обработкой и списанием, а мастер дает воркерам задания на обработку платежей. 

Если говорить о панели, то мы используем опенсурсную панель pterodactyl с небольшими изменениями в безопасности — мы написали свою прослойку для бесшовной авторизации пользователя, поэтому все запросы сначала попадают на наш auth, а потом — в панель. Мы также убрали панельный 2FA и прикрутили свой (раньше клиент мог иметь 2FA в панели, а в личном кабинете авторизовывался только по паролю). У pterodactyl также существует scheduler, который отвечает за создание бекапов, отправку данных в wings и коммуникации с нодами. 

Одной особенностью нашей панели является распил монолита и заезд в куб. Если посмотреть на документацию pterodactyl, то панель ставится как обычный git clone; apt-get install php-fpm и всё. На наших мощностях мы приняли решение использовать куб и для неё — вместе с модным HPA, чтоб было красиво (Недавно у нас за’seal’лился vault, поэтому панель жила на одном поде. Мы это заметили не сразу, но было больно..)

Наверное, это всё. Мы не стали включать все микросервисы, которые написаны нами, потому что схема превратилась бы в большое месиво, однако мы стараемся заезжать под куб всем, чем возможно (включая все инфраструктурные сервисы — жира, графана и все-все-все). 

Part 6: и зачем это всё? 

Хороший вопрос, и ответа на него я не знаю. Мы строим космолет там, где в этом нет необходимости. Правда, с одной маленькой особенностью: нам это нравится. Мне нравится и хочется изучать что-то новое в администрировании; пробовать то, в чём я не разбираюсь, стараться сделать так, чтобы это было правильно и красиво. То, что я делаю на работе не всегда удается познать на 100% — за эту часть отвечает команда мониторинга, за эту — команда DBA, за десятую — команда bare-metal серверов. А тут мы отвечаем за всё и сразу. 

Наверное, я скажу иначе. Помогло ли мне это когда-либо в работе? Да, определенно. Получаю ли я от этого удовольствие? Конечно, иначе бы я этого не делал. Нравится ли мне заниматься этим после рабочего дня, на выходных и праздниках? Я отвечу этой картинкой:

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

Если захотите посмотреть на нашу верхнеуровневую архитектуру, то смело заходите к нам: superhub.host. До встречи!


ссылка на оригинал статьи https://habr.com/ru/articles/827002/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *