systemd
| Тип | система инициализации и менеджер служб |
|---|---|
| Авторы | Леннарт Поттеринг, Кай Сиверс |
| Первый выпуск | 2010 |
| Язык | C |
| Лицензия | LGPL 2.1+ |
| Основные утилиты | systemctl, journalctl, systemd-analyze, loginctl |
| По умолчанию в | Debian, Ubuntu, Fedora, RHEL, Arch Linux, openSUSE |
| Сайт | systemd.io |
systemd — система инициализации и менеджер служб для Linux. Ядро запускает её первым процессом (PID 1), и дальше systemd поднимает всё остальное: монтирует файловые системы, настраивает сеть, запускает службы, следит за ними и перезапускает при сбоях, а при выключении корректно всё останавливает. Помимо этого, в проект входят журнал (journald), управление сеансами пользователей (logind), сетевые настройки (networkd), DNS-резолвер (resolved), синхронизация времени и другие компоненты.
Почти все популярные дистрибутивы используют systemd по умолчанию, поэтому systemctl и journalctl — повседневные инструменты любого администратора.
История
Классическая система инициализации SysV init запускала службы shell-скриптами строго по очереди, не умела надёжно отслеживать упавшие процессы и медленно загружала систему. Ubuntu в 2006 году перешла на событийный Upstart, но в 2010 году Леннарт Поттеринг и Кай Сиверс из Red Hat предложили более радикальный подход в статье «Rethinking PID 1».[2]
Fedora 15 (2011) стала первым крупным дистрибутивом с systemd по умолчанию, затем последовали Arch Linux, openSUSE и RHEL 7. В 2014 году после долгого и бурного обсуждения на systemd перешёл Debian (выпуск Debian 8, 2015), а вслед за ним Ubuntu 15.04. Критики упрекали проект в нарушении философии Unix «одна программа — одна задача»; часть сообщества ушла в форки вроде Devuan, но большинство дистрибутивов осталось с systemd.
Юниты
Всё, чем управляет systemd, описывается юнитами (units) — текстовыми файлами в формате INI. Тип юнита задаётся расширением:
| Тип | Назначение |
|---|---|
.service |
служба (демон или разовая задача) |
.socket |
сокет; служба запускается при первом подключении |
.timer |
запуск по расписанию — замена cron (см. cron и таймеры systemd) |
.target |
группа юнитов, аналог уровней запуска (multi-user.target) |
.mount, .automount |
точки монтирования |
.path |
реакция на изменение файла |
Системные юниты лежат в /usr/lib/systemd/system/ (от пакетов) и /etc/systemd/system/ (локальные, имеют приоритет). Зависимости задаются директивами Requires=, Wants=, After=, и systemd запускает независимые службы параллельно, что ускоряет загрузку.
Пример службы
# /etc/systemd/system/myapp.service
[Unit]
Description=My web app
After=network-online.target
Wants=network-online.target
[Service]
User=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/opt/myapp/.venv/bin/uvicorn app:app --port 8000
Restart=on-failure
RestartSec=5
# песочница
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
Restart=on-failure перезапускает службу при падении, а параметры песочницы ограничивают её доступ к системе: запрещают повышение привилегий, делают файловую систему доступной только для чтения, кроме указанных путей.[3][5] Служба запускается от отдельного пользователя — см. Права доступа в Unix.
systemctl
sudo systemctl daemon-reload # перечитать unit-файлы после изменений
sudo systemctl enable --now myapp # включить автозапуск и запустить сразу
systemctl status myapp # состояние, PID, последние строки лога
sudo systemctl restart myapp
systemctl list-units --failed # что упало
systemctl list-timers # таймеры и время следующего запуска
systemctl cat myapp # итоговый unit-файл с переопределениями
sudo systemctl edit myapp # переопределение без правки исходного файла
systemd-analyze blame # какие юниты дольше всего грузились
Команда systemctl edit создаёт файл-переопределение (drop-in) в /etc/systemd/system/myapp.service.d/, поэтому обновление пакета не затрёт локальные изменения.
Журнал
Компонент journald собирает вывод всех служб, сообщения ядра и syslog в единый структурированный журнал (см. journald и логи). Службе не нужно самой писать логи в файлы — достаточно выводить их в стандартный поток:[6]
journalctl -u myapp -f # следить за логом службы
journalctl -u myapp --since "1 hour ago"
journalctl -p err -b # только ошибки с момента загрузки
Таймеры
Таймер — пара юнитов name.timer и name.service. В отличие от cron, таймеры пишут вывод в журнал, учитывают зависимости, умеют догонять пропущенные запуски (Persistent=true) и добавлять случайную задержку, чтобы не нагружать сервер одновременно:[4]
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=10m
systemd и контейнеры
Внутри Docker-контейнеров systemd обычно не запускают: контейнер содержит один процесс, а перезапуском занимается сам контейнерный рантайм или Kubernetes. На хосте же systemd управляет и демоном Docker, и cgroups, через которые ограничиваются ресурсы любых служб (MemoryMax=, CPUQuota=).[1]