?

Log in

No account? Create an account

Тоже про систему инициализации в юниксах - БЭСМ-6

2014, Nov 20

22:51:00 - Тоже про систему инициализации в юниксах

Previous Entry Share Next Entry

Навеяно постом Витуса (http://vitus-wagner.dreamwidth.org/1028969.html, http://vitus-wagner.dreamwidth.org/1028969.html). В порядке выноса из комментов.

Задача запуска сервисов при старте системы и их мониторинга имеет три существенных подзадачи:

1. При старте системы (или при первом обращении, тоже вариант) каждый сервис должен запуститься только после того, как запустились до работоспособного состояния все его (жесткие) зависимости. А не просто после них.

2. Если сервис внезапно вымер, это должно быть замечено, и по этому поводу должны быть предприняты какие-то действия. Если он вымер внутризапно (остановлен админом) - тоже, но другие.

3. У админа должна быть возможность в считанные минуты, а лучше секунды, поправить инструкцию запуска под нужды своей системы.

Последняя задача требует, чтобы язык, на котором пишется эта инструкция, был простым, понятным админу (т.е. человеку с минимумом программистского скилла), лаконичным для этого класса задач, и его интепретатор, учитывая потребности embedded систем, должен быть компактным, считая зависимости. И, что важно, он должен быть один, потому что учить его придется каждому админу.

На, гм, общефилософском уровне я вижу два подхода. Один криво реализован в нынешнем SysV init, и заключается в том, что инструкции запуска пишутся на Тьюринг-полном языке, лаконичном для запуска процессов. И соглашение, в соответствии с которым централизованная система запуска может по такой инструкции определить ее зависимости и обеспечить их запуск до выполнения этой инструкции.

На практике в качестве языка для этих инструкций годится, помимо используемого в жизни sh, разве что tcl. Остальные либо непросты, либо не лаконичны, а чаще и то, и другое.

Плюсы: можно удовлетворить в принципе любые требования к запуску. Тьюринг-полная система.

Минусы:

- требуется дополнительно разрабатывать соглашения о взаимодействии с init и зависимостями, также простые и лаконичные. Это сложная задача, до сих пор ее толком не решили. LSB-style комментарии - слишком слабый язык для выражения зависимостей.

- как следствие, требуется еще один язык, будь он выражен в виде протокола с init или библиотеки. И этот DSL уже обязан НЕ быть Тьюринг-полным, от него требуется разрешимость, и более того, практическая разрешимость, т.е. решение задачи быстро.

Подзадача 2, помимо этого, требует еще одного DSL, в котором как минимум будут события "сервис упал" с некоторым количеством параметров (см. "respawning too fast" у нынешнего init) и "сервис остановлен админом". При наложении на систему зависимостей появляются еще понятия "перезапускать или нет зависимый сервис, если его зависимость упала и перезапущена". Заведомо нужны варианты мягких зависимостей - так, например, у меня на сервере exim, я считаю, обязан принимать почту даже если не может достучаться до spamd, spamtrapd и greylistd - но если может, надо их использовать. Т.е. это мягкие зависимости вида "надо поднять их до подъема exim, но если они не поднялись, стартовать все равно". Бывают и другие типы мягких зависимостей.

Удобнее всего такая конструкция решалась бы, если соглашение о зависимостях выразить в виде библиотеки для языка инструкций запуска, причем не столько в виде запросов от init к скриптам, сколько наоборот, от скриптов к init. Тогда в инструкцию запуска exim я (админ) перед запуском exim пишу "дорогой init, запусти мне spamd, spamtrapd и greylistd", дожидаюсь выполнения команд запуска, но игнорирую результат (могу и учесть, но в любом случае, exim я запущу). Причем пишу это я, админ, поскольку только я знаю, что в моей конфигурации используются spamd и greylistd из пакетов, а spamtrapd у меня вообще самопальный.

А инструкция запуска системы целиком звучит "запусти мне подсистемы dm, dns, mta, udev, autofs, acpi, network, sshd, cron, ntpd и вон те вон два lxc-контейнера". А уже их скрипты запуска, опять же, по моей команде, в курсе, что dm у меня нынче - nodm, dns - dnsmasq, и dns надо запускать до network (чтобы при подъеме сетевого интерфейса, который настраивается по DHCP, resolvconf пнул уже запущенный dnsmasq - а вообще-то тут вполне себе место, чреватое циклом), mta нынче - exim, и ему нифига не требуется DNS, такая конфигурация, а зато вот было бы клево поднятую сеть... А на сервере ему как раз требуется DNS, он там пытается адреса верифицировать. Ну и т.д.

Но тогда система зависимостей внезапно становится Тьюринг-полной, и проверить ее нет никакой возможности. Только отлавливать циклы зависимостей уже при старте системы, а это, знаете ли, поздновато...

Другой подход, насколько я понимаю, реализован в systemd. Суть подхода в том, что для описания всей системы запуска сразу берется декларативный Тьюринг-неполный DSL, и запуск полностью управляется init'ом.

Плюс: систему зависимостей в теории можно проверить заранее. Осилил ли это Поттеринг на практике, не очевидно (боюсь, со всеми костылями - нет) и что делать, если при этой проверке пойман цикл - вопрос открытый.

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

Origin: http://filin.dreamwidth.org/9717.html, comment count unavailable comments

Comments:

[User Picture]
From:vitus_wagner
Date:2014, Nov 21, 04:19:41 (UTC)
(Link)
По-моему, тут немного неправильно выбрана терминиология на которой говорится о задаче. Использован термин "язык". А тут нужно взять более что-то более общее. Поскольку под "языком" большая часть программистов будет понимать "какой-то синтаксис, к которому есть компилятор/интерпретатор".

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

Основные проблемы тут такие:

1. 90% случаев - это простые конфигурации. Простые вещи должны делаться просто. А значит в этих 90% случаев просто принесение файликов пакетным менеджером плюс простейшие автоматические операции вроде update-rc.d должны давать именно тот результат, которого хочется добиться.

2. Сложные вещи должны быть возможны. Для того самого админа, который нифига не программист.

3. Даже админ, в силу п.1. лазает в эту систему нерегулярно. Поэтому помнит
а) общие концепции, как оно в принципе работает (если мы их не поленимся внятно сформулировать и куда-то написать, где он их прочитает)
б) те инструменты, которыми он пользуется каждый день для решения других задач.

Этих двух вещей ему должно хватить для того чтобы в условиях дефицита времени (а админ не полезет чинить то, что не сломалось, значит дефицит времени будет всегда) придумать решение своей задачи, которое является более-менее прямым в рамках с формулированных концепций

4. Разработчик программы тем более не желает помнить особенностей конкретной системы инициализации. У него десяток поддерживаемых ОС,
(Reply) (Thread)
[User Picture]
From:vitus_wagner
Date:2014, Nov 21, 06:44:21 (UTC)
(Link)
И еще мысль - для разных задач, выполняемых в процессе инициализации системы нужны разные подходы. Например, чекалку локальных файловых систем все же лучше на императивном языке писать. И нужен некий уровень абстракции, на котором все эти задачи, независимо от того, на каком языке написаны, выглядят единообразно.
(Reply) (Thread)
[User Picture]
From:abbra
Date:2014, Nov 21, 07:18:06 (UTC)
(Link)
Ты упустил еще две задачи инит-системы: выделение ресурсов в нужном объеме для каждой из запускаемых подсистем и воспроизводимая среда запуска подсистемы вне зависимости от внешних условий. Тот же sysV init не обеспечивает второй задачи, поскольку контекст запуска инит-скрипта влияет прямым образом на контекст запускаемых приложений/демонов. Описание требований в данном случае -- это типичная конфигурация, о которой выше пишет Витус.
(Reply) (Thread)
[User Picture]
From:besm6
Date:2014, Nov 21, 09:07:19 (UTC)
(Link)
Начнем с того, что любое вычисление в монаде IO по определению зависит от контекста RealWorld :)

Хотя да, пару раз приходилось вставать на грабли с тем, что при старте системы с отлаженным из консоли инит-скриптом внезапно некий скрипт недоступен, потому что он в /usr/local/sbin, который в моем шелле в PATH есть, а /etc/rc его сам по себе не прописывает, надо в инит-скрипте дописывать явно.

Но в целом задача воспроизводимой среды для меня стоит не столь остро, чтобы страстно хотеть автомагического обеспечения ее от инит-системы.

А что до выделения ресурсов, то это, в общем небезынтересная мысль - переформулировка понятия зависимости в другую ассоциативную схему. Она может привести к другому подходу к решению. Понятно, что любую зависимость можно интерпретировать как ресурс, и обеспечение любого ресурса - как зависимость. А ассоциации уже другие.
(Reply) (Parent) (Thread)
[User Picture]
From:abbra
Date:2014, Nov 21, 09:46:39 (UTC)
(Link)
В случае, если среда запуска подразумевает определенные ограничения, воспроизводимость запуска крайне важна. Например, если в политике SELinux разрешены определенные переходы состояний, то запуск из другого изначального состояния может привести к отказу в доступе к выданным ресурсам, потому что это состояние могло быть менее привилегированным и из него мог быть запрещен переход в нужное состояние. Даже если первоначальное состояние было более привилегированным (типичная ситуация с sysV, где администратор запускает демонов "из-под рута"), то как результат получится создание файлов с неправильными контекстами, переход в неразрешенное состояние и так далее, совсем не то, что ожидалось администратором. В systemd эта проблема решается тем, что подсистемы готовит к запуску привилегированный процесс, который получает сообщения о том, что нужно запустить, посредством коммуникации с клиентским агентом.

Контроль за выделением ресурсов сейчас в Linux сделано единообразно через контроллеры ресурсных групп. Эти группы можно иерархически выстраивать и ограничивать, конфигурации подсистем в systemd как раз и позволяют все это поведение нормально настраивать. И да, можно часть подсистем исполнять в рамках иерархии другого выделенного ресурса (slices, scopes). Вот пример из тестовой виртуальной машины (F21) в следующем комментарии, так как ЖЖ не дает так много текста вставить.
(Reply) (Parent) (Thread)
[User Picture]
From:abbra
Date:2014, Nov 21, 09:46:51 (UTC)
(Link)
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 20
├─system.slice
│ ├─dbus.service
│ │ └─546 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
│ ├─krb5kdc.service
│ │ └─15201 /usr/sbin/krb5kdc -P /var/run/krb5kdc.pid
│ ├─lvm2-lvmetad.service
│ │ └─504 /usr/sbin/lvmetad -f
│ ├─abrtd.service
│ │ └─533 /usr/sbin/abrtd -d -s
│ ├─crond.service
│ │ └─561 /usr/sbin/crond -n
│ ├─system-pki\x2dtomcatd.slice
│ │ └─pki-tomcatd@pki-tomcat.service
│ │   └─15491 /usr/lib/jvm/jre/bin/java -DRESTEASY_LIB=/usr/share/java/resteasy -classpath /usr/share/tomcat/bin/bootstrap.jar:/usr/share/tomcat/bin/tomcat-juli.jar:/usr/lib/java/commons-dae
│ ├─oddjobd.service
│ │ └─4522 /usr/sbin/oddjobd -n -p /var/run/oddjobd.pid -t 300
│ ├─atd.service
│ │ └─562 /usr/sbin/atd -f
│ ├─systemd-journald.service
│ │ └─429 /usr/lib/systemd/systemd-journald
│ ├─ntpd.service
│ │ └─1645 /usr/sbin/ntpd -u ntp:ntp -g -x
│ ├─auditd.service
│ │ └─517 /sbin/auditd -n
│ ├─sssd.service
│ │ ├─4548 /usr/sbin/sssd -D -f
│ │ ├─4549 /usr/libexec/sssd/sssd_be --domain f21.test --debug-to-files
│ │ ├─4551 /usr/libexec/sssd/sssd_nss --debug-to-files
│ │ ├─4552 /usr/libexec/sssd/sssd_sudo --debug-to-files
│ │ ├─4553 /usr/libexec/sssd/sssd_pam --debug-to-files
│ │ ├─4554 /usr/libexec/sssd/sssd_ssh --debug-to-files
│ │ └─4555 /usr/libexec/sssd/sssd_pac --debug-to-files
│ ├─systemd-logind.service
│ │ └─558 /usr/lib/systemd/systemd-logind
│ ├─ipa_memcached.service
│ │ └─15237 /usr/bin/memcached -d -s /var/run/ipa_memcached/ipa_memcached -u apache -m 64 -c 1024 -P /var/run/ipa_memcached/ipa_memcached.pid
│ ├─system-getty.slice
│ │ └─getty@tty1.service
│ │   └─5497 /sbin/agetty --noclear tty1 linux
│ ├─sshd.service
│ │ └─26945 /usr/sbin/sshd -D
│ ├─systemd-udevd.service
│ │ └─470 /usr/lib/systemd/systemd-udevd
│ ├─mcelog.service
│ │ └─560 /usr/sbin/mcelog --ignorenodev --daemon --foreground
│ ├─certmonger.service
│ │ └─15050 /usr/sbin/certmonger -S -p /var/run/certmonger.pid -n
│ ├─abrt-oops.service
│ │ └─536 /usr/bin/abrt-dump-journal-oops -fxtD
│ ├─rngd.service
│ │ └─531 /sbin/rngd -f
│ ├─polkit.service
│ │ └─821 /usr/lib/polkit-1/polkitd --no-debug
│ ├─NetworkManager.service
│ │ ├─621 /usr/sbin/NetworkManager --no-daemon
│ │ └─947 /sbin/dhclient -d -sf /usr/libexec/nm-dhcp-helper -pf /var/run/dhclient-eth0.pid -lf /var/lib/NetworkManager/dhclient-e368d05a-a832-4d93-b5d6-87e696ff2d94-eth0.lease -cf /var/lib/N
│ ├─kadmin.service
│ │ └─15207 /usr/sbin/kadmind -P /var/run/kadmind.pid
│ ├─ipa-dnskeysyncd.service
│ │ └─15584 /usr/bin/python /usr/libexec/ipa/ipa-dnskeysyncd
│ ├─httpd.service
│ │ ├─15252 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15254 /usr/libexec/nss_pcache 1966088 off /etc/httpd/alias
│ │ ├─15255 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15256 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15258 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15259 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15260 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15262 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15264 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15527 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15723 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15724 /usr/sbin/httpd -DFOREGROUND
│ │ ├─15725 /usr/sbin/httpd -DFOREGROUND
│ │ └─15729 /usr/sbin/httpd -DFOREGROUND
│ ├─rsyslog.service
│ │ └─530 /usr/sbin/rsyslogd -n
│ ├─smartd.service
│ │ └─529 /usr/sbin/smartd -n -q never
│ ├─named-pkcs11.service
│ │ └─15226 /usr/sbin/named-pkcs11 -u named
│ └─system-dirsrv.slice
│   └─dirsrv@F21-TEST.service
│     └─15154 /usr/sbin/ns-slapd -D /etc/dirsrv/slapd-F21-TEST -i /var/run/dirsrv/slapd-F21-TEST.pid -w /var/run/dirsrv/slapd-F21-TEST.startpid
└─user.slice
  └─user-0.slice
    ├─user@0.service
    │ ├─16646 /usr/lib/systemd/systemd --user
    │ └─16648 (sd-pam)                                                          
    └─session-76.scope
      ├─16638 sshd: root@pts/0    
      ├─16650 -bash
      ├─16825 systemd-cgls
      └─16826 less
(Reply) (Parent) (Thread)
(Deleted comment)
[User Picture]
From:besm6
Date:2014, Nov 21, 08:59:13 (UTC)
(Link)
У меня была мысль про lua, но я его еще не сподобился изучить, хотя читать доку уже начал (он мне попался как встроенный язык imapfilter). Может быть, и lua. Надо посмотреть, что у него с контролем файловой системы и процессов.
(Reply) (Parent) (Thread)