Юниты и systemctl
systemd управляет всем через юниты — типизированные объекты с объявленными зависимостями. systemctl — инструмент для проверки, запуска, остановки, включения и отключения юнитов. Enabled означает запуск при загрузке; active — запущен прямо сейчас.
Ты вводишь sudo systemctl restart nginx после изменения конфига, и сервис поднимается меньше чем за секунду — никаких shell-скриптов, охоты за PID-файлами, ручного /etc/init.d/nginx stop && sleep 2 && /etc/init.d/nginx start. Но когда сервер перезагружается и nginx непонятно почему не работает, ты вводишь systemctl status nginx и сразу видишь: он завершился с кодом 1 через три секунды после загрузки, потому что /var/log/nginx ещё не существовал. Ты узнал за десять секунд то, на что ушло бы десять минут архивного исследования логов до эпохи systemd. Именно такую скорость отладки даёт модель юнитов systemd.
После этого урока ты сможешь назвать шесть основных типов юнитов и что каждый из них управляет, использовать systemctl для запуска, остановки, включения, отключения и проверки юнитов, объяснить разницу между enabled и active, и читать вывод systemctl status для определения причины сбоя сервиса.
Всё, чем управляет systemd, является юнитом — типизированным объектом с именем, оканчивающимся на расширение типа. Шесть типов, которые ты встретишь чаще всего:
| Расширение | Что управляет |
|---|---|
.service | Демон или однократный процесс |
.socket | Сетевой или IPC-сокет (для socket activation) |
.timer | Запланированный триггер (замена cron) |
.target | Именованная точка синхронизации или группа |
.mount | Монтирование файловой системы (автогенерируется из fstab) |
.path | Слежение за путём в файловой системе |
Имена юнитов следуют шаблону имя.тип: sshd.service, multi-user.target, apt-daily.timer. Тип сообщает systemd, какие ключи unit-файла допустимы и какую модель активации использовать.
# Список всех загруженных юнитов с их состоянием
systemctl list-units
# Только юниты типа service
systemctl list-units --type=service
# Все известные юниты, включая незагруженные
systemctl list-unit-filessystemctl status — первая команда, которую ты запускаешь при проблемах. Она сообщает много. Вывод насыщенный, но структурированный:
systemctl status nginx.serviceТипичный вывод здорового сервиса:
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-01-15 09:22:34 UTC; 3h 12min ago
Docs: man:nginx(8)
Main PID: 1234 (nginx)
Tasks: 2 (limit: 4672)
Memory: 5.8M
CPU: 421ms
CGroup: /system.slice/nginx.service
├─1234 "nginx: master process /usr/sbin/nginx -g daemon off;"
└─1235 "nginx: worker process"
Jan 15 09:22:34 hostname systemd[1]: Starting A high performance web server...
Jan 15 09:22:34 hostname systemd[1]: Started A high performance web server.Ключевые поля: Loaded показывает, разобрал ли systemd unit-файл и включён ли юнит. Active — состояние во время выполнения: active (running), active (exited), inactive (dead) или failed. Блок CGroup показывает точное дерево процессов. Хвост лога — последние записи журнала только для этого юнита.
Start, stop и restart управляют состоянием во время выполнения. Эти изменения действуют только до следующей перезагрузки — они не влияют на автозапуск юнита:
# Запустить остановленный юнит
sudo systemctl start nginx.service
# Остановить запущенный юнит (отправляет SIGTERM, затем SIGKILL по таймауту)
sudo systemctl stop nginx.service
# Перезапустить: стоп, затем старт (заменяет процесс)
sudo systemctl restart nginx.service
# Reload: отправить SIGHUP для перезагрузки конфига без остановки (если сервис поддерживает)
sudo systemctl reload nginx.service
# Reload-or-restart: предпочесть reload, откатиться на restart
sudo systemctl reload-or-restart nginx.serviceСуффикс .service можно опустить при отсутствии неоднозначности — systemctl restart nginx работает так же, как systemctl restart nginx.service.
Enable и disable управляют тем, запускается ли юнит при загрузке — это отдельно от того, запущен ли он сейчас. Enable устанавливает симлинки в директорию target; disable их удаляет:
# Enable: создать симлинк для запуска при загрузке
sudo systemctl enable nginx.service
# Enable И запустить прямо сейчас (часто используется для новых сервисов)
sudo systemctl enable --now nginx.service
# Disable: удалить симлинк (не останавливает запущенный сервис)
sudo systemctl disable nginx.service
# Disable И остановить прямо сейчас
sudo systemctl disable --now nginx.serviceПосле enable строка Loaded: в выводе systemctl status меняется с disabled на enabled. Теперь юнит подключён к multi-user.target (или к тому, что указано в WantedBy= в секции [Install]). После disable симлинк удаляется — юнит не запустится при следующей загрузке, но если он сейчас работает, то продолжает работать до остановки или перезагрузки.
Active vs enabled — самый частый источник путаницы у новых операторов. Это независимые оси:
| Enabled (запускается при загрузке) | Disabled (не запускается при загрузке) | |
|---|---|---|
| Active (запущен сейчас) | Нормальный production-сервис | Запущен вручную в этой сессии |
| Inactive (не запущен) | Запустится при следующей загрузке | Полностью выключен |
Сервис может быть запущен, но disabled (запустили вручную, не переживёт перезагрузку), или enabled, но не запущен (не смог запуститься). Используй is-active и is-enabled для скриптинга:
# Код выхода 0 если active, ненулевой если нет
systemctl is-active nginx.service
# Код выхода 0 если enabled, ненулевой если нет
systemctl is-enabled nginx.service
# Проверить оба условия
if systemctl is-active --quiet nginx && systemctl is-enabled --quiet nginx; then
echo "nginx работает и будет стартовать при загрузке"
fiДиагностика сервиса, который работал вчера, но не работает сегодня.
После незапланированной перезагрузки разработчик сообщает, что их кастомный API-сервис не отвечает. Вот рабочий процесс оператора:
# Шаг 1: проверить текущее состояние
systemctl status myapi.service
# Вывод: Active: inactive (dead)
# Loaded: loaded (/etc/systemd/system/myapi.service; disabled; ...)
# Шаг 2: 'disabled' говорит всё
# Сервис был запущен вручную, но никогда не включался — не пережил перезагрузку.
# Шаг 3: исправить сейчас И для будущих загрузок
sudo systemctl enable --now myapi.service
# Шаг 4: проверить
systemctl status myapi.service
# Active: active (running)
# Loaded: loaded (...; enabled; ...)Ошибка была в том, что тот, кто деплоил сервис, запустил systemctl start, но не systemctl enable. Сервис работал нормально до первой перезагрузки.
▸Почему это работает
macOS использует launchctl и plist-файлы launchd вместо unit-файлов systemd. Концепции совпадают: .plist в /Library/LaunchDaemons/ аналогичен .service-файлу с WantedBy=multi-user.target. launchctl load похож на systemctl enable --now. В launchd нет разделения на enabled и active — загрузка plist сразу регистрирует и запускает его.
▸Частая ошибка
Распространённая ошибка: редактировать /lib/systemd/system/nginx.service напрямую вместо создания переопределения в /etc/systemd/system/. Файлы в /lib/ принадлежат пакетному менеджеру и будут молча перезаписаны при следующем apt upgrade. Всегда помещай локальные настройки в /etc/systemd/system/ — либо полный файл замены, либо drop-in директорию (nginx.service.d/override.conf).
Ты запускаешь `systemctl enable myapp.service` без ошибок. Час спустя коллега проверяет и обнаруживает, что myapp не запущен. Что из следующего лучше всего объясняет это?
systemd моделирует всю систему как юниты — типизированные объекты (.service, .socket, .timer, .target, .mount, .path) с объявленными зависимостями. systemctl — CLI для управления ими. Самое важное концептуальное разделение: enabled (симлинк для загрузки установлен) не зависит от active (запущен прямо сейчас). systemctl start запускает что-то сейчас; systemctl enable обеспечивает выживание после перезагрузок. systemctl status показывает обе оси плюс хвост журнала — это первая команда при любых проблемах. Всегда помещай локальные кастомизации юнитов в /etc/systemd/system/, никогда в /lib/systemd/system/.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.