systemd

TL;DR: systemd — система инициализации (PID 1) и менеджер сервисов. systemctl start/stop/enable/status — управление сервисами. journalctl -u service — логи. Unit-файлы в /etc/systemd/system/.

Что такое systemd

systemd — PID 1, первый процесс при загрузке Linux. Заменил SysVinit и Upstart. Управляет сервисами, монтированием, логированием, сетью, таймерами.

Архитектура

systemd (PID 1)
├── systemctl        CLI для управления юнитами
├── journald         централизованное логирование
├── networkd         настройка сети
├── resolved         DNS
├── timedated        время и timezone
├── logind           управление сессиями
└── tmpfiles         временные файлы

Units (юниты)

Unit — объект, которым управляет systemd. Описывается в .unit-файле.

ТипРасширениеНазначение
Service.serviceДемон/сервис (nginx, sshd, postgresql)
Timer.timerЗадача по расписанию (замена cron)
Socket.socketАктивация сервиса при подключении
Mount.mountМонтирование файловой системы
Target.targetГруппа юнитов (аналог runlevel)
Path.pathРеакция на изменение файла
Slice.sliceГруппировка ресурсов (cgroups) → Подробнее: cgroups

Расположение файлов

ПутьПриоритетОписание
/etc/systemd/system/ВысшийВаши и переопределённые юниты
/run/systemd/system/СреднийRuntime (временные)
/usr/lib/systemd/system/НизшийЮниты из пакетов (не редактировать!)

Структура Service-файла

[Unit]
Description=My Application
Documentation=https://example.com/docs
After=network.target postgresql.service
Requires=postgresql.service
Wants=redis.service
 
[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
EnvironmentFile=/opt/myapp/.env
ExecStartPre=/opt/myapp/pre-start.sh
ExecStart=/usr/bin/node /opt/myapp/server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
 
[Install]
WantedBy=multi-user.target

Секция [Unit]

ПараметрОписание
DescriptionЧеловекочитаемое описание
AfterЗапускать после этих юнитов (порядок)
BeforeЗапускать перед этими юнитами
RequiresЗависимость: если зависимость упала, этот тоже останавливается
RequisiteКак Requires, но если зависимость ещё не запущена — сразу ошибка (не пытается запустить)
WantsМягкая зависимость: если зависимость упала, этот продолжает
BindsToЖёсткая привязка: если зависимость остановлена по любой причине, этот тоже
ConflictsВзаимоисключение: запуск одного останавливает другой
ConditionPathExistsЗапускать только если путь существует

After/Before vs Requires/Wants. Это ортогональные понятия: Requires/Wants = «запустить вместе», After/Before = «в каком порядке». Без After зависимости запускаются параллельно (ключевое преимущество systemd над SysV init).

# Просмотр зависимостей
systemctl list-dependencies nginx.service
systemctl list-dependencies --reverse nginx.service   # кто зависит от nginx

Секция [Service]

ПараметрОписание
Typesimple (default), forking, oneshot, notify
ExecStartКоманда запуска (обязательно абсолютный путь)
ExecReloadКоманда reload (обычно kill -HUP)
Restarton-failure, always, on-abnormal, no
RestartSecЗадержка перед перезапуском
User/GroupОт какого пользователя запускать
EnvironmentПеременные окружения
EnvironmentFileФайл с переменными

Секция [Install]

Определяет поведение systemctl enable/disable.

ПараметрОписание
WantedBy=multi-user.targetВключить при загрузке в multi-user (стандарт для серверов)
WantedBy=graphical.targetВключить при загрузке GUI
RequiredBy=...Жёсткая зависимость в обратную сторону

Как работает enable/disable. systemctl enable nginx создаёт символическую ссылку:

/etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service

systemctl disable nginx удаляет эту ссылку. При загрузке systemd обходит каталоги .wants/ и .requires/ каждого target и запускает найденные юниты. Таким образом enable — это не «запуск», а «включение автозапуска».

Targets (цели)

Группа юнитов = состояние системы (аналог runlevel).

TargetАналогОписание
poweroff.targetrunlevel 0Выключение
rescue.targetrunlevel 1Однопользовательский (recovery)
multi-user.targetrunlevel 3Многопользовательский (без GUI)
graphical.targetrunlevel 5С графическим интерфейсом
reboot.targetrunlevel 6Перезагрузка
# Текущий target
systemctl get-default
 
# Сменить default
sudo systemctl set-default multi-user.target
 
# Переключиться сейчас
sudo systemctl isolate multi-user.target

Timers (замена cron)

# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup
 
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
 
[Install]
WantedBy=timers.target
# Активировать таймер
sudo systemctl enable --now backup.timer
 
# Список таймеров
systemctl list-timers

journalctl (логи)

journalctl -u nginx          # логи конкретного сервиса
journalctl -u nginx -f       # follow (реальное время)
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -p err   # только ошибки
journalctl -b                # с последней загрузки
journalctl --disk-usage      # сколько занимают логи

Полный справочник journalctl, приоритеты, syslog, ротация логов: logging.

Процесс загрузки

BIOS/UEFI → Bootloader (GRUB) → Kernel → systemd (PID 1) → default.target
                                              ↓
                                    Параллельный запуск юнитов
                                    (network, sshd, nginx...)
# Анализ времени загрузки
systemd-analyze
systemd-analyze blame         # самые медленные юниты
systemd-analyze critical-chain

Socket Activation

systemd может создавать сокеты до запуска сервиса и передавать их при первом подключении. Это позволяет:

  • Запускать сервисы по требованию (не тратя ресурсы на неиспользуемые)
  • Не терять соединения при перезапуске сервиса (systemd буферизирует)
  • Избежать проблем с порядком запуска (сокет готов, даже если сервис ещё загружается)
# /etc/systemd/system/echo.socket
[Unit]
Description=Echo socket
 
[Socket]
ListenStream=7777
Accept=true
 
[Install]
WantedBy=sockets.target
# /etc/systemd/system/echo@.service
[Unit]
Description=Echo service
 
[Service]
ExecStart=/usr/bin/cat
StandardInput=socket

Accept=true — systemd создаёт отдельный экземпляр сервиса для каждого входящего соединения (шаблон echo@.service, @ = инстанс).

systemctl enable --now echo.socket     # активировать сокет
systemctl list-sockets                 # все сокеты

System V init (историческая справка)

До systemd большинство дистрибутивов использовали SysV init. Основные отличия:

SysV initsystemd
КонфигурацияShell-скрипты в /etc/init.d/Декларативные unit-файлы
Запуск сервисовПоследовательныйПараллельный
ЗависимостиНет (только порядок через номер: S01, S02…)Явные (Wants, Requires, After)
Runlevels/Targets0–6 (числовые)Именованные targets
Управлениеservice nginx start, /etc/init.d/nginx startsystemctl start nginx
ЛогированиеКаждый сервис самЦентрализованный journald

SysV использовал каталоги /etc/rc0.d//etc/rc6.d/ с символическими ссылками вида S85nginx/etc/init.d/nginx (S = Start, число = порядок, K = Kill).

systemd сохраняет обратную совместимость: скрипты в /etc/init.d/ автоматически получают unit-обёртки. Но новые сервисы всегда следует создавать как unit-файлы.

Аварийная загрузка

При проблемах с загрузкой systemd предоставляет несколько аварийных режимов:

РежимКак попастьЧто доступно
rescue.targetsystemd.unit=rescue.target в параметрах ядраМинимальная система, сеть отключена, root shell
emergency.targetsystemd.unit=emergency.targetТолько корневая FS (read-only), ещё минимальнее
init=/bin/bashПараметр ядра init=/bin/bashПрямой shell без systemd, FS read-only
# В GRUB: нажать e, добавить в строку linux:
systemd.unit=rescue.target     # мягкий вариант
init=/bin/bash                 # жёсткий вариант (без systemd)
# Загрузить: Ctrl+X

Подробнее об аварийной загрузке: boot-process.

Подводные камни

СитуацияСовет
Отредактировали юнит — не работаетsudo systemctl daemon-reload после изменений
Сервис enabled, но не запущенenable = автозапуск при boot. start = запустить сейчас. enable --now = оба
ExecStart с относительным путёмТолько абсолютные пути! /usr/bin/node, не node
Сервис постоянно перезапускаетсяjournalctl -u svc -n 50 → найти причину падения
Логи занимают много местаjournalctl --vacuum-size=500M

Связанные материалы