356

Systemd для самых маленьких. Часть I. Знакомство

Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Внимание! Данный пост не для холивара в стиле "нужен/не нужен", "не unix-way", "когда Поттеринг запилит свою ось?" и т.п. Пост содержит исключительно информацию по работе с systemd.


Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Привет вам, красноглазые братья и сёстры!


Эта статья посвящена, как видно из названия, системе systemd. Первый пост скорее обзорный и начнем мы с вами с исторического экскурса.


----------------------------------------------------

Глава 1. В плену shell-скриптов.

----------------------------------------------------

Давным-давно, в далекой-предалекой галактике примерно 14 млрд. лет назад не было ничего. Ни света, ни пространства, ни времени. Потом произошел Большой взрыв и потребовалось еще очень много времени, пока первый человек встал прямо и начал использовать свой разум. И навострился настолько, что по прошествии еще некоторого времени изобрел транзистор, а потом и компьютер. Компьютер сам по себе штука бесполезная, нужны были проги и операционная система. И родил человек Unix.


Операционной системе нужна была система инициализации (СИ, не путать с языком программирования!). Для совсем новичков, СИ - это действия, совершаемые при загрузке системы. Запуск программ, демонов всего лишь часть СИ.


Думали-думали и придумали в пятой версии Unix систему под названием init (SysVinit). Она позволяла запускать скрипты и вводила концепцию уровней инициализации (т.н. runlevels). Скрипты (обычно они лежат в /etc/init.d/) - это просто скрипты (простите за тавтологию) на языке shell-а, где описаны специальные функции, вроде start(), stop(), reload() и т.п. Это позволяло запускать скрипты вот таким образом (пример - демон web-сервера apache)

/etc/init.d/apache2 start

Запускать, конечно, хорошо, но лучше, чтобы все делалось автоматически при старте. И тут на помощь приходят уровни инициализации (УИииииииии). Всего уровней в системе могло быть до 7 штук (Оффтопик. УИ - это что-то по типу безопасного режима в винде, только тут таких режимов больше и они более настраиваемые). Обычно это:


> 0 - остановка системы;

> 1 - однопользовательский режим (иногда называемый режимом восстановления);

> 2/3 - многопользовательский с/без поддержки сети.

> 5 - графический режим

> 6 - перезагрузка


Для каждого из уровней в каталоге /etc был свой каталог с именем rcN.d, где N - номер уровня. Внутри этих директорий содержались симлинки (символическая ссылка - прим.) на скрипты из каталога /etc/init.d/, которые должны запускаться при переходе на соответ. уровень (или останавливаться при уходе). Какой должен запускаться, а какой останавливаться, а также порядок запуска (остановки) регулировался именем симлинка. В общем случае выглядит это вот так

Snnимя

Knnимя

Здесь S и K - обозначения старта и остановки (S - старт, K - остановка), nn - двухзначное число, используемое для обозначения порядка запуска (чем выше, тем позднее), имя - произвольное имя.

Уровень по умолчанию задавался в файле /etc/inittab, а поменять на лету можно было при помощи команды init номер_уровня. Например,

init 0

для выключения машины. Все скрипты запускались последовательно (это важно!). Позднее Ubuntu запилила свою СИ с блэкджеком и событийной моделью под именем upstart. Но о ней мы говорить не будем, т.к. даже сама Ubuntu отказалась от неё в пользу systemd.

Ладно, переборщил я со вступлением.  Держите скрин и переходим к "виновнику торжества".

Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

--------------------------------------------------

Глава 2. Systemd и все-все-все.

--------------------------------------------------

Systemd (в дальнейшем буду использовать сокращение sd) - это "система инициализации". Именно в кавычках, потому что она вобрала в себя огромную кучу функции. Кстати, именно это является главной причиной ненависти некоторых людей к systemd - нарушения принципа "unix-way".

Примечание: unix-way - принцип, согласно которому, одна программа - одна функция. Т.е. каждая программа должна выполнять одну функцию, но делать это достаточно хорошо, а не иметь 100500 плохо написанных функций.

systemd написана немецким программистом Леннартом Поттерингом (старшим братом Гарри Поттера). Основные причины (имхо) появления sd - попытка избавиться от shell-скриптов, распараллелить загрузку и иметь единую точку контроля всего и вся. Отсюда плюсы sd (копипаст с арчвики):

systemd обеспечивает возможности агрессивной параллелизации, использует сокеты и активацию D-Bus для запускаемых служб, предлагает запуск демонов по необходимости, отслеживает процессы при помощи контрольных групп Linux, поддерживает мгновенные снимки и восстановление состояния системы, монтирование и точки монтирования, а также внедряет основанную на зависимостях логику контроля процессов сложных транзакций.

На сегодняшний день sd применяется в Debian (c 8-й версии), Ubuntu (с 15.04 версии), Fedora (c 15 версии), openSUSE (с 12.1), ArchLinux (12.11) и т.д.

Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Основная базовая единица в sd - это сущность под названием юнит (unit). НЕ стоит думать, что юнит - это просто аналог shell скрипта из SysVinit (см. выше). Юниты бывают разных типов и тип service (наиболее близкий к shell скрипту из SysVinit) всего лишь один из них. Но это я забежал вперед.


Юнит - это текстовой ini-файл с описанием. Файл разделен на секции, внутри секций задаются параметры. Две секции допустимы во всех юнитах, остальные в зависимости от типа юнита. Есть три каталога, где могут храниться юниты.


> /usr/lib/systemd/system - системные юниты, поставляемые обычно вместе с приложениями;

> /run/systemd/system - динамически создаваемые юниты (т.е. на лету);

> /etc/systemd/system - юниты и исправления, внесённые администратором


Расположены директории в порядке повышения приоритета.

Юниты можно запускать и останавливать.

Как я сказал, юниты делятся на типы (с соответ. расширениями файлов):


> service - аналог демона или что-либо, что можно запустить;

> device - факт подключения какого-либо устройства (имя юнита генерируется из sysfs-имени устройства);

> target - ничего не описывает, группирует другие юниты;

> mount - точка монтирования файловой системы (имя юнита должно соотвествовать пути до точки монтирования);

> automount - аналог autofs: точки автомонтирования (должен существовать *.mount-юнит с тем же именем);

> timer - аналог cron. Периодический запуск другого юнита (по умолчанию запускаться будет *.service-юнит с тем же именем);

> socket - аналог xinetd. Запуск юнита при подключении к указанному сокету (по умолчанию запускаться будет *.service-юнит с тем же именем);

> path - запуск юнита по событию доступа к какому-либо пути в файловой системе (по умолчанию запускаться будет *.service-юнит с тем же именем);

> slice - группирует другие юниты в дереве cgroups, позволяя иерархично задавать ограничения по используемым ресурсам;


Примечение: cgroups - это способ объединения процессов, чтобы заюзать для них какие-то правила или ограничения. Например, ограничения на проц или память.

Не пугайтесь, если не все понятно. Москва тоже не сразу строилась. Все типы мы рассматривать не будет, это материал для отдельной статьи. Но для примера, а также чтобы пояснить понятие зависимостей требования/порядка, рассмотрим юнит типа service - sshd.service

Конечно, можно просто открыть файл в текстовом редакторе или использовать утилиту cat, но гораздо удобнее использовать для этого спец. команду;

systemctl cat sshd.service

Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Как я уже сказал, юнит делится на секции. В данном случае их три - [Unit], [Service] и [Install].

Секции [Unit] и [Install] могут быть в любом юните, а секция [Service] - спец. секция юнитов типа service.

Секция [Unit] содержит основную информацию о юните, а также о зависимостях порядка и зависимостях требования. Итак, параметры:


> Description= - тут просто описывается данный юнит. Набор слов, если проще.

> Wants= - о, интересный параметр. Это так называемые зависимости требования. Еще один из них (его тут нет) - это Requires=. И том и в другом случае, юнит хочет, чтобы сервис (или просто программа), указанный в параметре (назовем его зависимым юнитом), были запущенны, но при этом, если указано Wants=, то юниту пофиг на исход запуска. Пусть даже он упал, при старте. Requires= же таких вольностей не прощает и просто прекратит запуск юнита, если зависимый юнит не стартанул. Конкретно в этом случае, будет предпринята попытка запуска сервиса sshdgenkeys, но исход запуска нам по барабану.

> After= и парный ему Before= - это зависимости порядка. Все довольно просто и понятно, запускать данный юнит до или после.

Важно!

Зависимости порядка и зависимости требования НЕ связаны между собой. В данном примере, сказано, что sshd.service должен запустится после network.target. Но это никоим образом не значит, что network.target будет запущен! Однако если он запущен (допустим, его запустил другой сервис), то стартуем после него, если не запущен, то и фиг с ним.


На основе информации о зависимостях порядка и зависимостях требования sd строит так называемое дерево зависимостей. Чтобы понять это, представьте себе перевернутое дерево с корнем наверху, а вместо листьев у него юниты. Что-то похожее делает и sd при старте (сохр, до выключения/перезагрузки - прим.). Далее (тут только моё предположение) все юниты на одном уровне стартую одновременно (ака параллельно), в отличие от SysVinit, где была последовательная загрузка. Параллельный запуск обеспечивает ускорение запуска (хотя в вике написано, что в последних версиях уже нет).

Но вернемся к sshd. Секция [Service] описывает тип юнита service. В других типах своё. Например, в юнитах типа socket есть секция [Socket]


> ExecStart= - как запустить.

> ExecReload= - как перечитать конфиг, тут все просто.

> KillMode= описывает как будет убит процесс. Конкретно в этом случае сказано, что сигнал убийства (мухахахаа - зловещий смех - прим.) будет послан только главному процессу, а как быть со своими потомками ему решать.

> Restart= - описывает когда сервис будет перезапускать процесс при падении (или других катаклизмах). В мане есть табличка, которая объясняет всё немного лучше (это относится и к ману systemd в целом xD)

man systemd.service


Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Секцию [Install] пока просто запомним, ниже расскажу, где она используется.


Пока вы должны понять, что есть такая сущность, как юнит, что юниты делятся на типы и что юниты объединяются в дерево зависимостей на основе зависимостей требования и зависимостей порядка.


------------------------------------

Глава 3. Одна за всех.

------------------------------------

Прежде чем начинать описывать команды, хотелось бы пару слов сказать про юнит типа target. Как кратко было сказано выше, этот тип юнита не делает ничего, просто объединяя другие юниты. Технически этот юнит представляет из себя директорию с симлинкми на другие юниты.

Target-ы являются аналогами уровней в SysVinit. Т.е., допустим, target с именем multi-user является аналогом 2/3 уровня и содержит симлинки на юниты, которые будут запущены при выполнении этого target-а. По умолчанию выполняется target с именем default.target, который обычно является псевдонимом для graphical.target (аналог 5 уровня).


Итак команды. Основная команда, это

systemctl

Примечание: В дальнейшем unit_name - имя юнита, заменяйте на нужный. Команды запускались от рута.

systemctl, запущенная без параметров, является псевдонимом для более полной команды systemctl list-units. Она покажет список юнитов, а также их состояния. С помощью ключа -t можно задать тип юнитов, а --all выведет все юниты, в том числе и неактивные. Например:

systemctl list-units -t target --all

Команда

systemctl status

покажет общее состояние системы и перечислит юниты, которым соответствуют какие-либо запущенные процессы. В то же самое время, эта команда, дополненное именем юнита покажет более подробную информацию о юните. Например:

systemctl status sshd.service


Команда

systemctl cat unit_name

покажет содержимое юнита.

Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Переходим к самому интересному - запуск и остановка юнита. Снова systemctl.

systemctl start unit_name

systemctl stop unit_name

Примечание: по умолчанию принимается тип service. Таки образом команды

systemctl start sshd.service

и

systemctl start sshd

эквивалентны.

Тут все просто и понятно. Единственное, что стоит уточнить, так это то, что эти манипуляции применяются только в текущей сессии. При рестарте все вернется на круги своя.

А что тогда делать, если мы хотим добавить юнит в автозагрузку? Опять systemctl

systemctl enable unit_name

systemctl disable unit_name

Еще помните секцию Install, которую я сказал, что опишу позднее? Если не помните, то вот она:

[Install]

WantedBy=multi-user.target

Ну так вот, эта секция используется командами systemctl enable/disable для добавления симлинка в нужный target (создания иск. зависимости). Конкретно в этом случае, при выполнении команды

systemctl enable sshd.service

в папке multi-user.target будет создан симлинк на sshd.service и при выполнении данного target-a sshd будет запущен.

Кстати, проверить наличие юнита в автозагрузке можно командой

systemctl is-enabled unit_name

Она вернет enabled/disabled. Логично же)


Даже выключенный и убранный из "автозагрузки" unit может быть запущен как зависимость. Но что, если мы хотим совсем выключить юнит, чтобы нельзя было запустить даже как зависимость? Для этого юниты из /usr/lib/systemd/system и  /run/systemd/system - можно замаскировать командой

systemctl mask unit_name

Это команда создает симлинк на /dev/null в /etc/systemd/system с именем маскируемого юнита. (Напомню, этот каталог имеет наивысший приоритет). Тут проявляется ограничение - нельзя замаскировать юнит из папки /etc/systemd/system. Обратная команда

systemctl unmask unit_name

просто удаляет симлинк.


Возвращаясь к target-ам. В начале главы я сказал, что target-ы - аналоги уровней в SysVinit и то, что multi-user.target - 3 уровень, а graphical.target - 5 уровень. Вполне логично предположить, что есть и для оставшихся уровней.

> 0 - poweroff.target либо halt.target

> 1 - rescue.target

> 6 - reboot.target

Само собой, что можно просто запустить нужный target. Например:

systemctl start poweroff.target

Но гораздо проще использовать сокращенный аналог, убрав start и target, т.е.:

systemctl poweroff

systemctl halt

systemctl reboot

systemctl rescue

Также у нас имеется "лицензия на убийство"

systemctl kill unit_name

По умолчанию посылается сигнал TERM (не уверен), но можно послать определенный сигнал c помощью опции -s. Имена сигналов можно получить набрав команду kill -l

systemctl kill -s HUP unit_name


Хотите перезапустить все юниты и перестроить дерево зависимостей? Не проблема

systemctl daemon-reload

Systemd для самых маленьких. Часть I. Знакомство Linux, Systemd, Урок, Длиннопост

Разумеется, что описать всё и вся в одной статье не получится. Лично я планировал X статей с описанием systemd, Y статей с самописными примерами и Z c тем, что я наслоупочил. (X,Y,Z - произвольные натуральные числа), но когда это будет я не решусь сказать.


-----------------------------------------------

Использованная литература:

-----------------------------------------------


Арчвики, цикл видеоподкастов "Systemd In Action", цикл статей на Rus-LInux.



Спасибо за внимание.


Bonus. Хозяйке на заметку.

Команда

systemd-analyze

покажет время загрузки системы.

Дубликаты не найдены

+17
Иллюстрация к комментарию
+5

На счет однопоточности SysVInit автор не прав. Когда началась движуха в распараллеливании и появился upstart, то параллельность быстренько припилили и в SysVInit. Можно например открыть скрипт /etc/init.d/nginx чтоб убедиться в этом:


### BEGIN INIT INFO

# Provides: nginx

# Required-Start: $local_fs $remote_fs $network $syslog $named

# Required-Stop: $local_fs $remote_fs $network $syslog $named

# Default-Start: 2 3 4 5

# Default-Stop: 0 1 6

# Short-Description: starts the nginx web server

# Description: starts nginx using start-stop-daemon

### END INIT INFO


Это было еще до появления systemd. =)

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

Кстати скорость загрузки это действительно сильно увеличило и systemd в этом плане ничего особенного уже не дал.


P.S. Это тоже не холивара ради. Просто так оно было и есть. Я сам прошел через все эти системы.

P.P.S. В той же википедии написано: Сокет-активные и шина-активные службы, которые иногда приводят к лучшему распараллеливанию взаимозависимых служб.

раскрыть ветку 3
+2

Используй OpenRC, Люк!

0

Спасибо за информацию, правда я кое-чего не понял.

Required-Start/Stop - это по сути зависимости порядка запуска, тогда при чем здесь параллельность? Или просто все скрипты, не имеющие зависимости, стартуют параллельно?

раскрыть ветку 1
0

Такая же параллельность как и в systemd: запускает все "удовлетворенные Required-Start" приложения параллельно.

Например если программам А, B и C нужен только диск, у них будет в зависимости прописано только $local_fs. Соответственно сразу после монтирования диска A, B и C будут параллельно запущены. А если Required-Start не был бы прописан, то система сначала бы запустила A, дождалась бы пока скрипт запуска вернул управление, далее запустила бы B и т.д. ... последовательно.

+2

реквестую нечто подобное по по пшшаудио

+1

Ох спасибо огромное =) Как-то не сталкивался еще с данной СИ , на серверных ОС еще использую SysVinit (CentOS 5-6), а разобраться не хватало ни сил ни желания.

+1
Статью не читал но не осуждаю) И как бывший красноглазик ставлю плюс.
+1

В данном примере, сказано, что sshd.service должен запустится после network.target. Но это никоим образом не значит, что network.target будет запущен!

Вот тут немножко рвёт шаблон. Я вот этот момент и из манов не понимал, и сейчас смысл ускользает. Можно пояснить?)

раскрыть ветку 6
0

Стоит заметить, что здесь использована зависимость after, которая всего лишь указывает на порядок запуска. Есть и другие типы, которые могут быть скомбинированы для достижения нужного эффекта.

0

если в двух словах - сервис sshd не требует network, но если оно есть - то запуститься после него


например, iptables или firewalld - для работы сервиса они не нужны. Но если они все же есть - нужно запуститься после них, чтоб можно было добавить правила

раскрыть ветку 4
0
То есть, если я правильно понял, мы можем написать

After=abracadabra.target

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

Я правильно понял?

раскрыть ветку 3
+1

Мне кажется, что данный пост тянет на статейку на каком-нибудь geektimes

раскрыть ветку 2
+1

"Поставил линукс - напиши на хабр гиктайм"
Не надо, пожалуйста, там уже манагеры и маркетологи всех задрали, а вы еще пикабушников хотите ))

0

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

0

Данный пост не для холивара в стиле

А о чем можно холиварить? Кучу непойми-как связанного дерьма заменили одной однородной и понятной системой. К тому же очень производительной. И объединяющей разные дистрибутивы.


Там, где я раньше писал несколько десятков длинных нечитабельных строк, теперь хватит и пяти простых и понятных.

раскрыть ветку 15
+12

Всегда есть о чём холиварить.
Конкретно тут, о том, что "не Unix-way".
Кучу разнофункциональных утилит заменили одной комплексной неделимой системой.

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

раскрыть ветку 12
0
"не Unix-way"
Да и хуй с ним. Напридумали догматов, как фанатики. Линус насчёт всех этих священных принципов хорошо выразился однажды.
раскрыть ветку 4
-2

Конкретно тут, о том, что "не Unix-way".

Linux (ядро) тоже не Unix-way.

А вот ядро в OS X (Mach) - это Unix-way.

Неожиданно?


а в потере гибкости.

В какой потере?

-3
одной комплексной неделимой системой

Один из мифов http://0pointer.de/blog/projects/the-biggest-myths.html


в потере гибкости. Пользователя лишили выбора

Аналогично.

раскрыть ветку 5
+2
Холиварить можно о том, что например ночью надо спать(ну или дела делать), а не консоль дрочить, красноглазый. Сильно не бейте, я не хейтер.
раскрыть ветку 1
0

Я разработчик ПО под линукс, это для меня работа.

А по вечерам я отдыхаю ;)

0

У меня есть служба, запускаемая из xinetd через tcpd. Как запустить её из systemd, не используя xinetd  более-менее понятно. А как прикрутить tcpd?

0

э а где продолжение!?!?!)))

0
буду кроаток
1)как udev отключить не перелопачивая всю систему?

2)как заставит систему поднять сеть ДО монтирования шифрованных фаловых и ждать ввода паролдя на шифрованный раздел а не падать в сингмод? при этом 5 часов не отлавлмивать зависимости?

в sysv это делалось за 2 минуты
0

Большое спасибо. Жду продолжения.

0

@Stalus Подскажи пожалуйста почему система при загрузке loopback может зависать, причем если ребутнуть по питанию при следующей загрузке все в порядке. вообщем такая ерунда по рандому и только при загрузке redhat.

раскрыть ветку 3
0
Боюсь, что из меня довольно фиговый помощник.

Я не волшебник, я только учусь (с)

А вы уверены, что в этом дело? Смотрели, что в логах сказано?

раскрыть ветку 2
0

в том то и дело что ничего. просто не может почему-то поднять интерфейс петлю и все дела(

0

Можно ли как то прописать чтобы петля поднималась в самом конце загрузки ОС ?

0
нормально изложено) и как раз вовремя, сейчас активно этим занимаюсь. Несколько правок. по умолчантю команда kill шлет TERM сигнал, но его можно изменить настройкой SigKill для каждого юнита. И еще, daemon-reload насколько я знаю не перезапускает юниты, а только перестраивает дерево юнитов, и запускать ее нужно если были какие-то изменеия в файлах юнитов.

P.S. Сам я в восторге от этой системы. И согласен с топовым комментом, что из большой кучи стало все организовано.
-2

славный пост, systemd удобна, в свое время перешел без проблем.

время покажет везде ли применим unix-way

раскрыть ветку 2
+2

systemd это не unix-way, а конкретный прыжок в сторону от него

раскрыть ветку 1
0

я знаю) я к тому, что ее раз сейчас внедряют везде, то время покажет, завоюет она эту нишу и сердца админов в конце концов или нет. это и будет показателем того, что везде ли так хорош unix-way или в данном случае с systemd - нет.

-1

Прям как в windows сделали, прикольно.

0

О, годнота пошла. Спасибо!

-1

Но ведь ненужно!

-2

За тему и текст плюс, но tldr.

Похожие посты
162

Systemd vs SysVinit

При написании предыдущего поста про systemd наткнулся на интересную таблицу, где приводилось соответствие между командами systemd и SysVinit. Единственный "минус" был в том, что таблица была на английском, поэтому решил перевести и выложить, вдруг кому-то надо.


Перевод (кликните для увеличения):

Systemd vs SysVinit Linux, Systemd, Sysvinit, Перевод, Длиннопост

И оригинал (кликните для увеличения):

Systemd vs SysVinit Linux, Systemd, Sysvinit, Перевод, Длиннопост

Взято отсюда - http://linoxide.com/linux-command/systemd-vs-sysvinit-cheatsheet/

Там еще есть и pdf-версия. Русскую pdf-версию кинул на мыльное облако.


Если есть ошибка/неточность - пишите. Исправлю.


ps.

Очень удобно редактировать векторный pdf в Inkscape.

Показать полностью 2
Похожие посты закончились. Возможно, вас заинтересуют другие посты по тегам: