Sleepy NAS – теперь на стероидах!

2022-06-20

Продолжаем историю про сонный сервер, начатую в прошлый раз. Хотелось довести “проект” до некого законченного состояния, ибо оптимизация… оптимизация никогда не кончается.

Ну это как ремонт – её нельзя закончить. Её можно только прекратить.

Тем не менее в коде отросла пара довольно нужных (мне лично) фич, о которых ниже. Пригодятся ли он в реальности – дело вкуса, но стало поудобней, да и понадежней.

Было

Измеряем трафик на интерфейсе, не перешли “черту” – усыпляем всю конструкцию. Проснулись, скрипт продолжил выполнение, начинаем всё по новой.
Никакой магии, один лишь холодный расчёт и суровый прагматизм.

Стало

Иногда так получается, что вроде трафика и нет, но спать серверу совершенно не надо, ибо в данный момент идет, например синхронизация RAID. Я сильно подозреваю, что я ее вижу часто именно из-за того, что сервак уходит в спячку и никак её не закончит.
А ещё – после пробуждения может сломаться какой-нибудь сервис, типа докер-контейнера, написанного в теплой стране руками трудолюбивого копипастера.

В связи с этим Sleepy NAS отрастил механизм хуков, которые выполняются:

  • До спячки и в случае ошибки (код хука вернул ненулевой код возврата) не дают серверу заснуть.
  • После спячки по прошествии backoff time. Тут все проще – код ошибки не проверяется, так что каждый сам себе злобный Буратино.

Страшный секрет – внутри выполняется обычный run-parts. Ибо нехуй усложнять.

Но и это ещё не всё.

На reddit меня вежливо спросили – а мол, как вы там его из спячки выводите. Нет ли “умного” механизма, который не будет отвлекать уважаемых людей от работы ?

И действительно, а хули его нет ?

Так вот у Sleepy NAS отрос механизм пробуждения, правда он требует наличия мегадевайса в этой же сети, работающего 24х7. Вполне сойдет даже первый Raspberry Pi, хотя Orange Pi Zero 2 подойдет как нельзя лучше (меньше, надежнее, быстрее, дешевле).

Smart Wake

Итак, нам понадобится:

  • Приблуда, которая будет запоминать состояние сервера. Она же будет и слать в случае необходимости WOL-пакет. А так же принимать от сервера обновленное состояние, если оный проснулся по естественным причинам
  • Вторая приблуда, которая будет проксировать запросы. Скажем обратились мы к http://24x7шайтанкоробка/git, запрос обнюхается, сервер разбужен в случае, если он признан спящим, запрос поридержан и потом радостно переправлен куда следует.

Выглядит диаграмма примерно так:

диаграмма

Sidecar

Sidecar – это та самая “первая приблуда”. Внутри – приложение на GoLang, простое, как правда. Табличка с серверами. В табличке id, mac, таймаут, состояние и mutex на каждую запись на случай, если желающих поменять состояние будет больше одного.

Функционировать должна на хосте, который 24х7. Имеет несколько REST-вызовов. Подроности – в README, пересказывать его нет смысла, желающие прочтут, кто не в силах – идите в жопу, значит это не для вас.

Пример функционирования:

1
2
3
4
5
6
7
8
9
10
$ time curl http://armbox:10000/go/server
{"id":"server","mac":"10:7B:44:47:60:BE","status":"wake","timeout":10}
real 0m10,090s
user 0m0,000s
sys 0m0,009s
$ time curl http://armbox:10000/go/server
{"id":"server","mac":"10:7B:44:47:60:BE","status":"wake","timeout":10}
real 0m0,012s
user 0m0,009s
sys 0m0,000s

Первый запрос – 10 секунд с хвостиком, второй – сильно быстрее. На первом запросе сервак разбужен, 10 секунд отстояться. На втором – он уже помечен, как “проснувшийся”, ничего делать не надо.

А вот что в логе:

1
2
2022/06/20 19:29:05 Waking server index 0, mac: 10:7B:44:47:60:BE
2022/06/20 19:29:19 Server with index 0 already awake

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

Если работает из докера – контейнер надо запускать с host network, ибо WOL-пакет за пределы докер-сети не выйдет. Впрочем, там есть пример docker-compose, где всё прозрачно.

Wake Proxy

Тут всё сложнее, и возможны варианты. Мне лично нужно было включать сервак при:

  • Любой операции c GIT (push/pull) причем как http(s), так и по ssh
  • Любой операции с docker proxy registry и docker private registry
  • Любой операции с Sonatype Nexus 3

Да, у меня свой nexus и своя Gitea, а что вы хотели – время такое. Не чужие, так свои что-нибудь заблокируют.

Очевидным решением было использовать nginx с lua-расширениями. То есть reverse proxy /git мы попридержим запрос и разбудим целевой сервер. То же самое при обращении через stream proxy на конкретный порт.

После изучения вопроса я остановился на OpenResty. Там была возможность “подоткнуть” свои вызовы практически бесшовно на конкретный URL.

Подробности желающие найдут в readme и примере конфигурации.

При этом при работе через revеrse proxy обрабатывается каждый запрос и тут “тупить” нельзя. Так что почти “чистый” lua, не считая внешнего компонента lua-resty-http.

А вот в случае с stream proxy – тут немного печальнее. API не позволяет повторить фокус с co-socket из-за естественных ограничений, но и код выполнится один раз при открытии соединения. Так что достаточно дернуть curl через os.exec и расслабиться.

Где это будет работать, а где – нет

Если нужно проксировать tcp сервис или сервис за reverse http(s) proxy, то скорее всего проблем не будет. Можно даже проксировать ssh прям через порт 22 на хосте 24х7, правда его родной ssh придется куда-нибудь сдвинуть.
Решительно добавляем желаемый компонент в конфигурацию и наслаждаемся автопобудкой при обращении.

Вполне можно попробовать проксировать Samba. Мне не актуально, на моем хосте 24х7 своя самба.

А вот если для работы нужен еще и UDP порт (вроде бы для NFS нужен) – то тут пока что (?) облом.

Или вот тот же приснопамятный Plex. Тут либо играть с iptables c пробросом всех портов, либо делать развесистый tcp/udp прокси, причем достаточно быстрый и эффективный. Стоит оно того? Не думаю.
Тот же libreelec/openelec имеет настройку “пытаться будить целевой сервер”. Да и от ложных срабатываний тоже придется как-то защититься, у меня ощущение, что они будут.

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

Проект в GitHub, все компоненты я тоже форкнул к себе на всякий случай. Система в эксплуатации уже пару недель, при этом эффект замечательный – открываешь проект в IntelliJ Idea, там интеграция с GIT тесная.
Так вот всё будится, всё работает. Таймаутов нет.

Та же история при pull докер-образов и помещении их в локальный прокси – все прозрачно и автоматично.

Получилась этакая игрушка, но вполне себе летучая. Может пригодится кому-то ещё, может нет. Делалось для себя.

Ну на этом пожалуй хватит внимания этому поделию, пора уже двигаться дальше.


В массы

В трубу