commit -m "better"
Вкратце напомню, что у меня системными сервисами управляет #runit. Поэтому, когда у меня происходит обновление system #realm, происходит перезагрузка всего дерева сервисов. Ну просто потому что меняются inode путей в папке /etc/services, так как /etc - это…
#runit, будни #bootstrap, #herobora #runsvdir.
У используемого и нежно любимого мной runit есть одна неприятная особенность (врочем, как и у остальных init-ов, унаследованных от daemontools).
Он хочет безусловно портить структуру директорий, в которых лежат сервисы.
Простыми словами - он создает директорию ./supervisor, рядом с каждым файликом run каждого сервиса. Там он хранит состояние управляемого сервиса, и прочую лабудень.
Контрольки сервисов (./run файлы) у меня лежат в /etc, которая есть ссылка на какую-то папку в content addressable store.
Из этого следует простой вывод - runit у меня "портил" (и продолжает портить) папки (и данные) в cas, чего допускать, конечно, нельзя.
Я обкатывал несколько разных решений этой проблемы, которые, так или иначе, сводились к "теневой" копии сервисов из /etc "куда-то", где можно писать. Например, регулярным копированием /etc/services куда-то в /var/run/, или, вот, с помощью rw overlay unionfs куда-то в tmpfs.
Короче, совершенно всратые решения, ошметки которых я даже не хочу показывать.
Смотрел на другие "простые" супервизоры, но нет.
В общем, после нескольких лет попыток придумать что-то не столь всратое, я плюнул, и переписал
Эдакий сплав (она же херобора) из обычного runit для pid1, и моей запчасти, с таким же интерфейсом, ее так же зовут скрипты инициализации runit, но с нужной мне семантикой.
Та-да-да-дам!
https://github.com/stal-ix/ix/blob/main/pkgs/bin/ix/runsvdir/run.py
Да, на python, потому что для прототипирования python подходит очень хорошо, и я уже смирился с тем, что он у меня есть в базовой системе (при этом я упаковал в один бинарь со всеми зависимостями, поэтому он не мозолит глаза своей россыпью файлов по всей fs).
Когда его семантика устаканится, перепишу на go, или даже на rust (не хочет кто-то взяться? там строк 50-100 идиоматичного rust-о кода должно быть).
Что я могу сказать?
* Мне кажется, это самый компактный супервизор процессов, который я когда-либо видел/делал, при этом, с приличным набором фич. Он умеет пасти структуру директорий, такую же, как у runit, но ничего не пишет на диск. Сервисы могут добавляться и убираться "на лету".
* Удивительно, но я вот написал этот скриптец, ребутнул машину, ожидая debug и recovery окирпиченного хоста, но ничего такого не случилось - все завелось сразу, с полпинка, потому что поверхность у
* В принципе, теперь я могу там запилить недостающие фичи из runit, типа динамически создаваемых юнитов. Захочу ли - пока не знаю.
У используемого и нежно любимого мной runit есть одна неприятная особенность (врочем, как и у остальных init-ов, унаследованных от daemontools).
Он хочет безусловно портить структуру директорий, в которых лежат сервисы.
Простыми словами - он создает директорию ./supervisor, рядом с каждым файликом run каждого сервиса. Там он хранит состояние управляемого сервиса, и прочую лабудень.
Контрольки сервисов (./run файлы) у меня лежат в /etc, которая есть ссылка на какую-то папку в content addressable store.
Из этого следует простой вывод - runit у меня "портил" (и продолжает портить) папки (и данные) в cas, чего допускать, конечно, нельзя.
Я обкатывал несколько разных решений этой проблемы, которые, так или иначе, сводились к "теневой" копии сервисов из /etc "куда-то", где можно писать. Например, регулярным копированием /etc/services куда-то в /var/run/, или, вот, с помощью rw overlay unionfs куда-то в tmpfs.
Короче, совершенно всратые решения, ошметки которых я даже не хочу показывать.
Смотрел на другие "простые" супервизоры, но нет.
В общем, после нескольких лет попыток придумать что-то не столь всратое, я плюнул, и переписал
runsvdir
- это часть runit, которая отвечает именно за управление деревом процессов.Эдакий сплав (она же херобора) из обычного runit для pid1, и моей запчасти, с таким же интерфейсом, ее так же зовут скрипты инициализации runit, но с нужной мне семантикой.
Та-да-да-дам!
https://github.com/stal-ix/ix/blob/main/pkgs/bin/ix/runsvdir/run.py
Да, на python, потому что для прототипирования python подходит очень хорошо, и я уже смирился с тем, что он у меня есть в базовой системе (при этом я упаковал в один бинарь со всеми зависимостями, поэтому он не мозолит глаза своей россыпью файлов по всей fs).
Когда его семантика устаканится, перепишу на go, или даже на rust (не хочет кто-то взяться? там строк 50-100 идиоматичного rust-о кода должно быть).
Что я могу сказать?
* Мне кажется, это самый компактный супервизор процессов, который я когда-либо видел/делал, при этом, с приличным набором фич. Он умеет пасти структуру директорий, такую же, как у runit, но ничего не пишет на диск. Сервисы могут добавляться и убираться "на лету".
* Удивительно, но я вот написал этот скриптец, ребутнул машину, ожидая debug и recovery окирпиченного хоста, но ничего такого не случилось - все завелось сразу, с полпинка, потому что поверхность у
runsvdir
- очень простая и компактная.* В принципе, теперь я могу там запилить недостающие фичи из runit, типа динамически создаваемых юнитов. Захочу ли - пока не знаю.
🔥26👍5❤3🤔1
commit -m "better"
#runit, будни #bootstrap, #herobora #runsvdir. У используемого и нежно любимого мной runit есть одна неприятная особенность (врочем, как и у остальных init-ов, унаследованных от daemontools). Он хочет безусловно портить структуру директорий, в которых лежат…
Я, когда рассказывал про свою замену #runit, упустил один важный момент.
Если до того, как я заменил #runsvdir, у меня рестартовало вообще все дерево процессов после модификации system #realm (ну потому, что папка с симлинками на сервисы появлялась новая, inode у этих симлинок новый, и runit рестартовал вообще все), то после перестало рестартовать вообще все, даже в тех ситуациях, когда сервис поменялся, и рестарт был нужен.
Потому что мой скрипт смотрит не на inode, а на контент + путь до скрипта, и вот эта вот пара, на самом деле, меняется очень редко.
А меняется она редко, потому что у меня, чаще всего, runit скрипты не являются частью пакета с программой, а идут отдельным пакетом, чтобы программу можно было использовать и без runit скриптов.
Вот и получается, что программа поменялась, а скрипт запуска - нет, и ничего не рестартует.
Самый очевидный способ это починить - сделать так, чтобы runit скрипт зависел (по сборке) от программы, которую он запускает, но это приводит к некоторым проблемам:
* build зависимость всегда host, а нужна зависимость от target.
* может оказаться так, что программа собирается с каким-то пользовательским флагом, тогда, по сути, одна и та же программа соберется два раза (под host, без флага, и под target, с флагом)
В общем, я протащил из графогенерирующего ядра возможность получить uid любого пакета, как если бы мы проинтерпретировали графогенерацию для этого пакета в нашем текущем контексте с флагами, о как.
Ну и записал этот uid в тело runit скрипта - https://github.com/pg83/ix/blob/main/pkgs/etc/services/runit/script/ix.sh#L32
Использование выглядит вот так - https://github.com/pg83/ix/blob/main/pkgs/bin/chrony/runit/ix.sh#L4-L5 По сути, просто передаем в пакет с runit скриптом флаг (srv_deps=...), в котором лежит список всех зависимостей для этого скрипта.
С одной стороны, какое-то странное, неестественное, действие, с другой - теперь можно не рестартовать сервисы, когда что-то поменялось, но не очень хочется (например, пользовательские сессии)
Если до того, как я заменил #runsvdir, у меня рестартовало вообще все дерево процессов после модификации system #realm (ну потому, что папка с симлинками на сервисы появлялась новая, inode у этих симлинок новый, и runit рестартовал вообще все), то после перестало рестартовать вообще все, даже в тех ситуациях, когда сервис поменялся, и рестарт был нужен.
Потому что мой скрипт смотрит не на inode, а на контент + путь до скрипта, и вот эта вот пара, на самом деле, меняется очень редко.
А меняется она редко, потому что у меня, чаще всего, runit скрипты не являются частью пакета с программой, а идут отдельным пакетом, чтобы программу можно было использовать и без runit скриптов.
Вот и получается, что программа поменялась, а скрипт запуска - нет, и ничего не рестартует.
Самый очевидный способ это починить - сделать так, чтобы runit скрипт зависел (по сборке) от программы, которую он запускает, но это приводит к некоторым проблемам:
* build зависимость всегда host, а нужна зависимость от target.
* может оказаться так, что программа собирается с каким-то пользовательским флагом, тогда, по сути, одна и та же программа соберется два раза (под host, без флага, и под target, с флагом)
В общем, я протащил из графогенерирующего ядра возможность получить uid любого пакета, как если бы мы проинтерпретировали графогенерацию для этого пакета в нашем текущем контексте с флагами, о как.
Ну и записал этот uid в тело runit скрипта - https://github.com/pg83/ix/blob/main/pkgs/etc/services/runit/script/ix.sh#L32
Использование выглядит вот так - https://github.com/pg83/ix/blob/main/pkgs/bin/chrony/runit/ix.sh#L4-L5 По сути, просто передаем в пакет с runit скриптом флаг (srv_deps=...), в котором лежит список всех зависимостей для этого скрипта.
С одной стороны, какое-то странное, неестественное, действие, с другой - теперь можно не рестартовать сервисы, когда что-то поменялось, но не очень хочется (например, пользовательские сессии)
GitHub
ix/pkgs/etc/services/runit/script/ix.sh at main · pg83/ix
ix package manager. Contribute to pg83/ix development by creating an account on GitHub.
🤔10👍6❤3🔥1
Тем временем, у моей реализации #runsvdir https://t.iss.one/itpgchannel/1998 уже есть 4 open source альтернативы:
* оригинал из runit
* мой вариант на python
* вариант на Rust (https://github.com/maratik123/runsvdir)
* и мой же вариант на С++ (https://github.com/pg83/ix/blob/main/pkgs/bin/ix/runsvdir/cpp/m.cpp)
На приложенном скриншоте - все 4, на одной и той же конфигурации.
Хуже всех (по потреблению памяти) python, потом идет оригинальный из runit (меня это удивило, он, вроде как, на С), потом вариант на Rust, а пижже всех - мой, на С++.
Оптимизациями памяти я даже не занимался (посмотрите код, он максимально дубовый), можно лучше.
* оригинал из runit
* мой вариант на python
* вариант на Rust (https://github.com/maratik123/runsvdir)
* и мой же вариант на С++ (https://github.com/pg83/ix/blob/main/pkgs/bin/ix/runsvdir/cpp/m.cpp)
На приложенном скриншоте - все 4, на одной и той же конфигурации.
Хуже всех (по потреблению памяти) python, потом идет оригинальный из runit (меня это удивило, он, вроде как, на С), потом вариант на Rust, а пижже всех - мой, на С++.
Оптимизациями памяти я даже не занимался (посмотрите код, он максимально дубовый), можно лучше.
❤17👍6🔥4🤔3🤯2🤡1🆒1
commit -m "better"
В общем, после нескольких лет попыток придумать что-то не столь всратое, я плюнул, и переписал runsvdir - это часть runit, которая отвечает именно за управление деревом процессов.
#herobora
В итоге, мой #runsvdir у меня прижился, и, как понятное следствие, я окончательно отказался от ошметков #runit:
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/ewontfix/main.c - свой элементарный init.
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/rc/ix.sh#L9-L11 - клей между моим init, и схемой загрузки "как в runit", чтобы можно было заменять туда-сюда.
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/halt/main.c https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/reboot/main.c - реализации halt/reboot, они, как ни странно, тоже часть init. Если такой способ (без graceful shutdown) кажется странным - читаем мои заметки про #reboot, https://t.iss.one/itpgchannel/1572.
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/pid1/m.cpp#L157-L175 - пришлось перенести в runsvdir код, который убивает orphane процессы, в runit у меня это был cron job на shell (https://github.com/pg83/ix/blob/main/pkgs/bin/sched/stale/procs/scripts/staleprocs.sh), но в новой схеме так не получается, потому что сервисы сразу начинают наследоваться от pid 1, а не от pid > 1, поэтому инвариант "все, что подвисло к pid 1, но не runsvdir - мусор" перестал работать.
Так что теперь у меня официально полностьювелосипедный in house init!
С точки зрения скриптов инициализации ничего не поменялось, ага.
В итоге, мой #runsvdir у меня прижился, и, как понятное следствие, я окончательно отказался от ошметков #runit:
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/ewontfix/main.c - свой элементарный init.
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/rc/ix.sh#L9-L11 - клей между моим init, и схемой загрузки "как в runit", чтобы можно было заменять туда-сюда.
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/halt/main.c https://github.com/pg83/ix/blob/main/pkgs/bin/ix/init/reboot/main.c - реализации halt/reboot, они, как ни странно, тоже часть init. Если такой способ (без graceful shutdown) кажется странным - читаем мои заметки про #reboot, https://t.iss.one/itpgchannel/1572.
* https://github.com/pg83/ix/blob/main/pkgs/bin/ix/pid1/m.cpp#L157-L175 - пришлось перенести в runsvdir код, который убивает orphane процессы, в runit у меня это был cron job на shell (https://github.com/pg83/ix/blob/main/pkgs/bin/sched/stale/procs/scripts/staleprocs.sh), но в новой схеме так не получается, потому что сервисы сразу начинают наследоваться от pid 1, а не от pid > 1, поэтому инвариант "все, что подвисло к pid 1, но не runsvdir - мусор" перестал работать.
Так что теперь у меня официально полностью
С точки зрения скриптов инициализации ничего не поменялось, ага.
GitHub
ix/pkgs/bin/ix/init/ewontfix/main.c at main · pg83/ix
ix package manager. Contribute to pg83/ix development by creating an account on GitHub.
👍11🔥7❤4🆒3