Найти в Дзене
Олег.Кряхтит.Онлайн

Как начать селфхостить: программная инфраструктура

В предыдущей статье мы поговорили об аппаратной инфраструктуре для селфхостинга. В этой поговорим о программной составляющей. Я помогу сделать выбор между виртуальными машинами, сортами контейнеров и отсутствием виртуальной инфраструктуры, сравню плюсы и минусы, опишу когда они уместны и на чём остановился сам. Мои фавориты - libvirt + qemu. Теперь вы сами стали хостером, которому нужно накормить толпу хлебами, но каждый просит забронировать за ним всю булку. Проверьте в BIOS опции аппаратного ускорения виртуализации, без которых производительность сильно хромает: Всё это не совсем про селфхостинг. Кажется, можно отмести практически сразу. В случае аренды VPS вы и так используете виртуальную машину, вложенные виртуальные машины обычно очень непроизводительны, а VPS и без того ограничены в ресурсах. Я отнёс оба варианта в один пункт. Перед началом использования советую почитать https://12factor.net/ru/, но не вдохновляться им слепо. В том или ином виде вам всё равно
понадобится: В ост
Оглавление

В предыдущей статье мы поговорили об аппаратной инфраструктуре для селфхостинга. В этой поговорим о программной составляющей. Я помогу сделать выбор между виртуальными машинами, сортами контейнеров и отсутствием виртуальной инфраструктуры, сравню плюсы и минусы, опишу когда они уместны и на чём остановился сам.

Виртуальные машины

Мои фавориты - libvirt + qemu.

Плюсы

  • Ограничить потребление ресурсов легко.

Минусы

  • Расходы на эмуляцию оборудования.
  • Расходы на запуск ядра ОС для каждой машины.
  • Потребление памяти. Убедитесь, что virtio-balloon настроен и работает. Ещё одна технология, которая может здорово выручить при использовании однотипных виртуальных машин - KSM (Kernel Same Page Merging): одинаковые фрагменты памяти объединятся, общее потребление сократится.

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

Проверьте в BIOS опции аппаратного ускорения виртуализации, без которых производительность сильно хромает:

  • Intel (Intel VT-x, EPT, VT-d);
  • AMD (AMD-V, RVI, AMD-Vi, SVM).

Когда выбирать виртуальные машины

  • Использование чрезмерно устаревшего ПО, зависящего от старой версии ядра ОС.
  • Использование системного ПО, которое сильно влияет на операционную систему. Здесь приведу пример: поговаривают, что LXD и ZFS сильно облегчают жизнь. Летом я буду собирать файловый сервер 2.0 для загородного дома, вот тогда и попробую. Пробовать буду в виртуальной машине, не боясь сломать личный ПК, файловый сервер 1.0 или изначально испортить свежеустановленную ОС нового сервера.
  • Эксперименты с дистрибутивами, установщиками и десктопными окружениями перед тем, как начать их использовать.

Всё это не совсем про селфхостинг. Кажется, можно отмести практически сразу. В случае аренды VPS вы и так используете виртуальную машину, вложенные виртуальные машины обычно очень непроизводительны, а VPS и без того ограничены в ресурсах.

Docker и Kubernetes (k8s)

Я отнёс оба варианта в один пункт. Перед началом использования советую почитать https://12factor.net/ru/, но не вдохновляться им слепо. В том или ином виде вам всё равно
понадобится:

  • Оркестратор - штука, которая запускает нужные сервисы и контролирует
    их состояние. Вторым можно пожертвовать.
  • Ингресс: обратный прокси, который будет отправлять трафик в один из
    нужных контейнеров.
  • Нужно будет собирать и где-то хранить образы. Можно на том же сервере,
    где они и запускаются, если он один. Главное не пихать в них секреты и не загружать их в публичные реестры.
  • Разобраться с хранением секретов.
  • Автоматическое создание и изменение DNS-записей, чтобы они вели куда
    надо. Может подойдёт Сonsul, может и один раз руками настроить сойдёт.
  • Разруливать порядок загрузки и зависимости между сервисами (веб-приложению нужна БД, поэтому она должна запуститься вперёд) всё
    равно придётся.
  • Куда-то собирать логи.

Плюсы

  • Воспроизводимость. Написав один раз Dockerfile, docker-compose.yml или values.yml и отладив резервное копирование данных сервиса, вы получите очень лёгкое восстановление.
  • Экономия места: Общие слои (например, базовый образ Ubuntu) не будут дублироваться между контейнерами. Но если вы используете чужие готовые образы - далеко не факт, что их базовые образы будут одинаковыми. Если упаковываете сами - лучше один раз выбрать предпочтительную основу.
  • Отказоустойчивость: в случае с k8s, при правильно организованных health-check оно само будет перезапускаться когда надо, а выход из строя одной железки не скажется на доступности ваших сервисов. При очень сильном желании k8s можно организовать между несколькими VPS у разных провайдеров.
  • Масштабируемость: если ваши сервисы доступны
    публично и вам нужно справляться с нагрузкой, вы можете настроить
    динамическое масштабирование. Но не забывайте, что бесконечного
    масштабирования не бывает, всё упрётся в бутылочное горлышко, а самое
    частое бутылочное горлышко в селфхостинге - деньги.
  • Много ПО имеет целевой формат распространения в виде docker-образов. Вы сэкономите кучу времени, вам не потребуется бодаться с конфликтами и подготовкой окружения.

Минусы

  • Ручные правки: Если вы привыкли лезть в /etc
    и править конфиги на лету — придётся переучиваться. Каждый такая правка
    теперь требует пересборки образа. Можно монтировать конфиг-файлы (см.
    volumes), но для применения всё равно придётся перезапускать контейнер.
  • Ресурсы: на правильно приготовленный k8s со
    всеми сортами отказоустойчивости и резервирования уйдёт много времени и
    денег. У некоторых хостеров есть услуга managed k8s, это может
    частично компенсировать время (ценой денег).
  • Если ПО не адаптировано к докеру, это придётся кому-то сделать. Вам. Вы потратите кучу времени, если у вас нет опыта в использовании docker.

Когда k8s дома нужен?

  • Для работы нужна практика и понимание устройства k8s.
  • Вы решили масштабироваться за пределы одного сервера, расположив их в
    разных местах. Один на даче, другой в квартире, третий у родителей.
  • В плане на развёртывание более 50 сервисов или вы осознаёте другую причину, по которой k8s необходим.
  • Если вы разрабатываете и тестируете распределённое приложение. Но это уже не совсем про селфхостинг, это скорее работа.

В остальных случаях это переусложнение, которое не сделает вас счастливее.

Непосредственно в системе

Плюс - нулевые накладные расходы: Нет изоляции — нет расходов.

Когда имеет смысл

  • Когда сервис использует общие данные с другими сервисами, в таком случае - расположите их в одной файловой системе.
  • Для демонов вроде SSH, Cron, Samba которые 100% отлажены,
    используются миллионами людей, устанавливаются из репозиториев ОС и не
    требуют большого числа зависимостей, в отличии от python, nodejs или
    ruby приложений. Последние я как раз стараюсь устанавливать в
    контейнеры, несмотря на существование вспомогательных средства
    виртуализации окружений, вроде nvm, pyenv и так далее.

Мой опыт

Мой файловый сервер (дальше NAS) использует samba для монтирования в проводник и для загрузки резервных копий с Macbook в TimeMachine, sftp + rsync для синхронизации архивов фотографий и музыки, Nginx
для лёгкого доступа на чтение с iOS без установки на него
дополнительного ПО. Эти архивы живут непосредственно в ФС физического
сервера.

Причины две:
- Слой изоляции скорее мешал бы.
- Так исторически сложилось. Samba я установил и настроил ещё до LXC.

Ещё непосредственно в системе живёт NTP-сервер. В LXC завести Chrony не получилось, при попытке запустить привилегированный unconfined контейнер, у которого будут права двигать аппаратные часы часы хост-системы - зависали все LXC. Без этого NTP запускался, но отдавал кривое время, сдвинутое аж на 15 минут вбок. Я установил его в корень NAS, не жалею, всё равно +/- штатное ПО. DHCP-сервер роутера отдаёт адрес NAS в качестве NTP-сервера через DHCP-опцию, теперь единственное устройство в
доме, у которого едет время - это духовой шкаф без Wi-Fi.

Да, неосилятор, мог и разобраться, но перезапускать аппаратный сервер ради отладки NTP на пятый раз сильно надоело. Мой сервер, что хочу то и делаю (маленькая прелесть селфхостинга).

LXC

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

Мой опыт

Я выбрал LXC для размещения сервисов дома. Для контекста - аппаратная составляющая. Это не сверхмощный сервер, а компромисс между размером, энергопотреблением, тишиной и производительностью.

  • Платформа: мини-пк ASRock Deskmini 310.
  • Процессор: Pentium G5400 (2 x 3.7GHz + гипертрединг).
  • RAM: 2x16Gb, 2400MHz.
  • Диски: 128gb SSD + RAID1 из 2х2Tb HDD, все с ext4.

Какие цели я преследовал:

  • Экономия ресурсов - меньше памяти в сравнении с виртуальными машинами.
  • Удобство управления - ведёт себя как виртуальная машина, ничего не
    сбрасывается при перезапуске, можно настроить статический IP. У меня был
    некоторый опыт использования LXC, так что отчасти это был вопрос
    привычки.
  • Логическая изоляция - поломка окружения ОС одного сервиса не должна
    ломать остальные; должно быть легко понятно, какой из контейнеров занял место на диске.

Технические детали

Большая часть моих сервисов - веб-приложения.

Приблизительная схема развёртывания сервисов у меня дома.
Приблизительная схема развёртывания сервисов у меня дома.
  • Для удобства адресации я использую API домашнего роутера (Mikrotik
    HEX) для регистрации
    статических DNS-записей.
  • Я использую TLS, несмотря на то, что они доступны
    только дома. У меня есть самопальный "удостоверяющий центр" - ещё один
    LXC-контейнер с самоподписными корневым и промежуточным сертификатами.
  • TLS терминирует Nginx, развёрнутый на самом NAS. Для веб-сервисов я регистрирую два домена. Один для менеджмента (с суффиксом `-ssh`), который резолвится в IP-адрес LXC-контейнера, второй - в адрес самого NAS. Трафик попадает в Nginx и он по SNI разруливает, куда его дальше отправить.
  • Конфиг-файлы Nginx, выпуск SSL-сертификатов, создание DNS-записей на роутере - всё это автоматически выполняется скриптом для развёртывания новых контейнеров.
  • Тот же скрипт подкладывает мой публичный SSH-ключ внутрь контейнеров, чтобы сразу после установки я мог подключаться к ним по SSH без пароля.

Проблемы и возможные решения

Сейчас число контейнеров достигло 15 и мне не нравятся накладные расходы на дисковое пространство от дублирования одинаковых окружений ОС. Я подумываю о переходе на docker-compose, но пока не разобрался с:

  • Сетью: выделением для контейнеров статических IP, маршрутизацией.
  • Автозапуском.
  • Местом для хранения образов.
  • Cronjob внутри контейнера. Как вариант плодить отдельные контейнеры под каждый процесс, пусть и с одним образом.
  • Пробросом и хранением SSH-сертификатов.
  • Я часто делаю что-то вручную внутри контейнеров, с docker такой подход считается проблемным.

Все эти проблемы решаемы, но пока я не хочу их решать.

Слишком требовательные к дисковому пространству контейнеры переезжают с SSD на HDD. Делается это переносом папки `/var/lib/lxc/container_name/` в директорию, расположенную на HDD. На бывшем месте папки создаём симлинк в новое местоположение. Когда появится сервис, требовательный и к пространству и к скорости - обновлю в своём ПК 2Тб NVMe с PCI-E 3.0 на 4.0, а старый воткну в NAS. Может быть стоит сделать это уже сейчас и тогда предыдущая проблема с дублированием окружений не будет меня беспокоить ещё пять лет.

  • Ощущаю, что стоит попробовать k8s. Стандартизирую работу с Nginx, он начнёт называться модным словом ingress.
  • Хочу найти трюк, для использования общих слоёв ФС в LXC. Это трюк
    называется
    ZFS, но я уже начал использовать ext4, боюсь сломать
    работающую систему, выделяя отдельный размер под ZFS-пул со
    snapshot'ами.
  • Возможно гибридное решение - часть сервисов в LXC, часть в docker-compose будет оптимальным. Я смогу запускать новые сервисы в docker-compose, постепенно переводить старые, которым там будет лучше, ничто не будет подстёгивать и я совершу плавную миграцию. Если сервис не получится запустить в docker-compose, остаётся запасной вариант с LXC.

Выводы и советы

  • Не гонитесь за модными инструментами.
  • Селфхостинг — это про контроль, а не про сложность.
  • Используйте то, что понимаете. Понимание — залог контроля.
  • Не хотите — не делайте, SaaS — не порок!