Мой домашний датацентр, часть 1: Весело, оживленно

Как положено любому уважающему себя айтишнику, у меня дома стоит датацентр. Как положено любому настоящему айтишнику, датацентр в относительно прискорбном состоянии. Как положено любому уважающему себя айтишнику, я храню обещание, что однажды даже с ним разберусь. В рамках программы повторного использования техники, в качестве домашнего датацентра работает Mac Mini 2011 года под управлением Mac OS 10.15. Под катом будет рассказано, как дойти до такой жизни, и с чем мириться.

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

Почему macOS?

У выбора операционной системы есть достаточно простая историческая причина. Так как машина стоит рядом с моей кроватью, шуметь она должна только в моменты использования (когда я не сплю), а в остальное время (когда я сплю) должна быть максимально возможная тишина. Изначально в качестве операционной системы был выбран CentOS (ынтерпрайзности ради), но они отказались от поддержки техники Apple: новое оборудование с T2, что требует большого количества времени на реверс и написание драйверов, более старая техника уже старая. Сидеть еще и на старой CentOS это, конечно, Ынтерпрайзно (выбор большинства компаний), но как-то не хотелось. Далее выбор пал на Debian. Установился он без особых проблем, но драйверов для WiFi модуля в коробке не было. Инструкция же для их сборки состояла из таких интересных шагов, как:

  1. Поставить ядреные хедера
  2. Скачать исходники ядра
  3. Запустить набор команд sed
  4. До шага 3 запустить другой набор команд sed
  5. Собрать ядро, и настроить загрузчик, чтобы с него бутаться

Где-то между шагами 4 и 5 (депрессия и принятие) стало понятно, что не иметь мне свое ядро с рабочим WiFi. Ладно, жить будем, от попыток пользоваться МТС ТВ осталось два PLC-адаптера, которые с помощью физики и микросхем делают Ethernet сеть поверх электрической. Естественно, так как датацентр планируется расширять, то на выходе из PLC должен стоять свитч, и естественно, так как мы уже ребята гламурные, свитч должен быть соответствующим. Из подсобки достается Apple Time Capsule, и начинает выполнять роль сетевого оборудования. Да, датацентр уже начинает пахнуть смузи и гироскутерами.

Сеть есть, Debian установлен, живём. Так как запах смузи в воздухе дурманит, в качестве платформы для своих сервисов нужны Kubernetes. Полноценные куберы в рамках одной машины совершенно ни к чему, да и etcd (база данных k8s) крайне чувствительна к скорости записи данных, потому она совершенно не оценит HDD 2011 года. Берем k3s, которые заменили etcd на SQLite (одобряем), и устанавливаем их. Благо скрипт очень простой, надо всего лишь сделать curl | bash1. Отлично, теперь у нас есть и кубернеты. А что это так жужжит? На стоячей машине, которая еще и не думала выполнять какие-либо полезные задачи, потребляется 20% процессора. Старенький CPU 2011 года, конечно, не так хорош, но чем оно там занимается в простое?!

Не стоит переживать, баг в гитхабе уже заведен до нас2, а значит, его однажды починят. Но это значит, что если мы хотим легковесности и тишины, то надо отказаться от кубернетов и пользоваться обычным podman3. Сносим k3s (грустный смайлик), сидим и читаем про Podman. А что это так жужжит?

Оказалось, что серверная версия Debian, достаточно аскетичная в своей поставке, тем не менее греет компьютер и заставляет его вентиляторы крутиться, крайне усиливая звуковое загрязнение моей комнаты. Попытки ставить несвободные драйвера (установка отдельно) и программы для управления кулерами не показали никакого результата. Для сравнения перезагружаемся в macOS и наслаждаемся тишиной и спокойствием. Кажется, время для того, чтобы делать органический безлактозный датацентр от Apple и выигрывать на конкурсе хипстеров.

Радости настройки

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

Багетный менеджер

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

  • Мне нужна какая-нибудь тула, распространяемая среди прочего в Homebrew
  • Я забываю о прошлых страданиях и пишу brew install <package>
  • Тула зависит от OpenSSL, который с последних моих приключений успел обновиться (там уже версия 1.1.1l, то есть это уже двенадцатый билд)
  • Homebrew устанавливает тулу и новый OpenSSL, снося предыдущий (потому что это с его точки зрения новая версия [email protected], а не новый пакет)
  • За предыдущим OpenSSL летит обновляться все, что от него зависит (Python, node, ruby, you name it)
  • Я сижу около часа, размышляя о своем поведении
  • С прошлых моих приключений успел выйти новый python@3, поэтому ставится новый минорный релиз, выкидывая все модули, установленные в предыдущий
  • Я остаюсь без powerline-status, раскрашивающего мой zsh
  • Перед моими глазами грустный и недоумевающий шелл, который оставили без темы

И так было каждый раз.5 Помножить частоту выхода пакетов на количество моих девайсов, и все мои взаимодействия с Homebrew вызывают исключительно боль и страдания. Наверное, я бы не смог сделать лучше, но это стало одним6 из основных драйверов чтобы съехать с powerline и сделать мой шелл самодостаточным.

Также стоит отметить, что он не предназначен работать в системах с несколькими пользователями, и все его свершения в /usr/local/ живут под единственным юзером. Это добавляет боли, если хочется разграничивать права различных своих демонов, и не запускать их от того же самого пользователя, что имеет доступ к Apple ID.

launchctl

Общеизвестно, что любимый многими7 systemd вдохновлялся launchctl, PID1 на macOS. Что касается внутреннего устройства, наверное, они похожи, но поверхность яблочного демона крайне шероховата:

  • Демон - это программа с аргументами, нет различных ExecPre/ExecPost, чтобы подготавливать приложение к запуску. Лечится написанием shell-скрипта в качестве обертки, но это неэргономично

  • Нет restart/reload команд. Хотите перезапустить демона - launchctl unload && launchctl load. Вроде мелочь, но приходится делать свой однострочник вида kill -HUP $(pgrep nginx) ради того, чтобы перезагрузить веб-сервер, не отключая его

  • Если после launchctl unload && launchctl load ваш демон на самом деле не поднялся а пошел падать по кругу, то вы этого не узнаете, если не будете запускать в цикле pgrep и не заметите, что PID почему-то меняется.

  • Если нужна socket активация, то приложение должно быть “в курсе” про существование launchctl. Systemd имеет аналогичную проблему, но в мире серверных программ его поддержку встретить почему-то гораздо проще.

Все это является следствиями одного и того же фактора - никто не подразумевает, что пользователь будет сам ковыряться в процессах и демонах. Демоны и агенты это глубоко подкапотная история, в отличие от мира Linux, в котором любая домохозяйка должна уметь перезапустить networking.service, когда wpa_supplicant в очередной раз отвалился. Но, раз уж мы завязались на macOS, придется жить по местным обычаям.

Также стоит отметить, что если какой-то софт для macOS пакуется в виде приложения, то удобного способа запускать его при старте машины нет, кроме как добавить его в автозапуск. Автозапуск автозапускается лишь при логине пользователя, поэтому также стоит включить и автологин. Воистину, данное занятие учит доверять домашним.

Доступность софта

По причине шумности мы не можем пользоваться контейнерами8, а большая часть интересного софта недоступна на macOS в качестве собранных артефактов. Это учит любви к Go и Rust, которые, как правило, можно собрать самому за какое-то конечное время, без особых страданий в процессе. Например, когда возникла идея перехода9 на Bitwarden со своего текущего облачного менеджера паролей, проще всего оказалось скомпилировать bitwarden-rs, и запустить его у себя. Благо все равно удалось найти интересный софт, чтобы было, ради чего столько страдать.

На этом первая часть подходит к концу (дабы не утомлять читателя), во второй части уже не будет страданий10, и будет рассказ о самих сервисах.


  1. Небезопасного в этом немного. Большинство пакетных менеджеров поддерживает запуск произвольных команд в процессе установки. Если вы ставите пакет из репозитория, не поддерживаемого, например, самим дистрибутивом (у них хоть репутация на кону, да процессы есть), вы подставляетесь ровно так же. ↩︎

  2. Здесь можно было бы приложить конкретный баг, но дело было давно, скорее всего, этот уже починили. Для меня даже было небольшим удивлением, что его исправили, потому что тот же Docker For Mac отвечает на жалобы про пожирание более одного ядра, когда встроенные кубернеты не гоняют никакой нагрузки чем-то вроде “Congrats on the new wafflemaker, but we don’t really care”. ↩︎

  3. На момент изысканий Docker еще не умел ни в rootless режим, ни daemonless, потому у него был демон, потреблявший несколько сотен ресурсов. ↩︎

  4. Та же претензия и к iOS. ↩︎

  5. Я начал писать этот пост на новом ноутбуке. Чтобы Jekyll работал как надо, нужен несистемный Ruby. Пишу на автомате brew install ruby@2. К чему это привело, думаю, рассказывать даже и ненужно. Зато я поужинал. ↩︎

  6. Второй причиной была скорость работы терминала. Возможно, истории про его разгон будет посвящена еще одна статья. ↩︎

  7. И нелюбимый немногими. ↩︎

  8. Контейнеров нет, но, если совсем захочется изоляции и/или безопасности, то все еще остался недокументированный sandbox-exec, который умеет на основе политик, написанных на диалекте лиспа запускать ваше приложение в урезанной среде. Его вроде как грозятся депрекнуть уже довольно давно, но пока сами яблочники не перестанут его использовать, мы в безопасности. ↩︎

  9. Впоследствии решение было пересмотрено. Все девятки, которые гарантируются моим домашним датацентром - это Балтики, а остаться без пароля от Очень Важного Сервиса, когда под рукой есть только телефон, а VPN до дома оторвался совершенно не хочется. ↩︎

  10. Это ложь. ↩︎