systemctl — главный CLI для systemd
systemctl — это командный интерфейс к systemd. Всё, что ты делаешь с сервисами на современном Linux, начинается с него: проверить статус, запустить, остановить, рестартнуть, посмотреть, что упало.
Команды этого урока ты будешь использовать каждый день, как только окажешься на production-сервере с Airflow, Postgres, Nginx, или любым другим демоном.
systemctl status: первая команда при любом инциденте
$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Wed 2026-05-13 08:42:11 UTC; 2h 12min ago
Docs: man:nginx(8)
Process: 12345 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; ... (code=exited, status=0/SUCCESS)
Process: 12346 ExecStart=/usr/sbin/nginx -g daemon on; ... (code=exited, status=0/SUCCESS)
Main PID: 12347 (nginx)
Tasks: 5 (limit: 9445)
Memory: 14.3M
CPU: 285ms
CGroup: /system.slice/nginx.service
├─12347 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
├─12348 "nginx: worker process"
└─12349 "nginx: worker process"
May 13 08:42:11 prod-vm systemd[1]: Starting nginx.service...
May 13 08:42:11 prod-vm systemd[1]: Started nginx.service.
Что здесь важно:
Каждая строка отвечает на свой вопрос.
# Сокращённая форма — не нужна суффикса .service:
$ systemctl status nginx
$ systemctl status sshd
$ systemctl status postgresql
systemctl status работает без sudo для большинства unit-ов (но с sudo показывает больше, например, выводы logs от других пользователей).
Failed-сервис
$ systemctl status airflow-scheduler
× airflow-scheduler.service - Airflow Scheduler
Loaded: loaded (/etc/systemd/system/airflow-scheduler.service; enabled)
Active: failed (Result: exit-code) since Wed 2026-05-13 09:15:23 UTC; 5min ago
Process: 23456 ExecStart=/opt/airflow/venv/bin/airflow scheduler (code=exited, status=1/FAILURE)
Main PID: 23456 (code=exited, status=1/FAILURE)
CPU: 1.232s
May 13 09:15:21 prod-vm airflow[23456]: Traceback (most recent call last):
May 13 09:15:21 prod-vm airflow[23456]: File "/opt/airflow/dags/etl.py", line 12, in <module>
May 13 09:15:21 prod-vm airflow[23456]: from snowflake.connector import connect
May 13 09:15:21 prod-vm airflow[23456]: ModuleNotFoundError: No module named 'snowflake'
May 13 09:15:23 prod-vm systemd[1]: airflow-scheduler.service: Main process exited, code=exited, status=1/FAILURE
May 13 09:15:23 prod-vm systemd[1]: airflow-scheduler.service: Failed with result 'exit-code'.
Красный крест ×, failed, exit code 1. В журнале — Python traceback с ModuleNotFoundError. Это ровно то, что нужно для быстрого debugging: лог + причина в одной команде.
systemctl start / stop / restart / reload
$ sudo systemctl start nginx
$ sudo systemctl stop nginx
$ sudo systemctl restart nginx
$ sudo systemctl reload nginx
Разница restart vs reload:
- restart = stop + start. Процесс полностью убивается и запускается заново. Все живые соединения рвутся. Pid меняется.
- reload = послать
SIGHUP(или то, что прописано вExecReload=в unit-файле). Процесс читает конфигурацию заново, не теряя соединений. Поддерживают nginx, postgres, sshd. Для большинства python/java сервисов reload не реализован — нужен restart.
Если не уверен, поддерживает ли сервис reload:
$ systemctl show -p ExecReload nginx
ExecReload={ path=/usr/sbin/nginx ; argv[]=/usr/sbin/nginx -g daemon on; master_process on; -s reload ; ... }
Есть ExecReload= — reload работает. Если пусто — только restart.
Sudo для start/stop, без sudo для status
Большинство start, stop, restart, reload, enable, disable требуют root. Это понятно: рестартнуть Postgres = повлиять на всю систему.
status, is-active, is-enabled, list-units, cat — обычно без sudo. Но если нужны логи внутри status, sudo даст больше деталей (логи других пользователей).
enable / disable: автозапуск при boot
Важно понять разницу: start запускает сервис сейчас, enable ставит его на автозапуск при следующем boot.
# Сейчас запустить (один раз)
$ sudo systemctl start nginx
# Сейчас НЕ запускать, но запускать всегда при boot
$ sudo systemctl enable nginx
# И то, и другое одной командой (новый сервис на production):
$ sudo systemctl enable --now nginx
# Остановить и убрать из автозапуска:
$ sudo systemctl disable --now nginx
Сервис может быть в любой из 4 комбинаций. Понимание матрицы — основа управления.
enable создаёт symlink
enable под капотом создаёт symlink в директории, указанной в [Install] секции unit-файла:
# Что делает enable:
$ ls -la /etc/systemd/system/multi-user.target.wants/nginx.service
lrwxrwxrwx 1 root root 36 May 13 08:42 nginx.service -> /usr/lib/systemd/system/nginx.service
Когда systemd при boot достигает multi-user.target, он смотрит на свой .wants/ каталог и запускает всё оттуда. disable удалит symlink — unit останется на диске, но не будет запускаться.
is-active, is-enabled: для скриптов и мониторинга
Эти команды возвращают только exit code (без вывода или с минимальным), для использования в bash-скриптах:
$ systemctl is-active nginx
active
$ echo $?
0
$ systemctl is-active not-existing.service
inactive
$ echo $?
3
# Проверка для cron-скрипта:
if systemctl is-active --quiet airflow-scheduler; then
echo "Airflow scheduler работает"
else
echo "Airflow scheduler упал — отправить alert"
fi
--quiet подавляет вывод, оставляя только exit code.
$ systemctl is-enabled nginx
enabled
$ systemctl is-enabled postgresql
enabled
Возможные значения is-enabled: enabled, disabled, static (не имеет [Install]), masked (заблокирован), not-found.
list-units, list-unit-files
list-units показывает запущенные (или хотя бы загруженные) units:
$ systemctl list-units --type=service
UNIT LOAD ACTIVE SUB DESCRIPTION
airflow-scheduler.service loaded active running Airflow Scheduler
cron.service loaded active running Regular background program processing daemon
dbus.service loaded active running D-Bus System Message Bus
nginx.service loaded active running A high performance web server
[email protected] loaded active running PostgreSQL Cluster 16-main
ssh.service loaded active running OpenBSD Secure Shell server
systemd-journald.service loaded active running Journal Service
systemd-logind.service loaded active running User Login Management
...
Колонки:
LOAD— загрузился ли unit-файл (loaded,error,masked,not-found).ACTIVE— высокоуровневое состояние (active,inactive,failed).SUB— детальное (running,exited,dead,waiting).
Фильтры
# Только failed (что сломалось):
$ systemctl list-units --type=service --state=failed
UNIT LOAD ACTIVE SUB DESCRIPTION
airflow-scheduler.service loaded failed failed Airflow Scheduler
custom-etl.service loaded failed failed Custom ETL daemon
# Все таймеры:
$ systemctl list-units --type=timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Wed 2026-05-13 12:00:00 UTC 1h 23m Wed 2026-05-13 06:00:00 UTC 4h 36min ago etl-daily.timer etl-daily.service
Wed 2026-05-13 23:00:00 UTC 12h ... Tue 2026-05-12 23:00:00 UTC 11h 37min ago backup.timer backup.service
# Все units, в том числе остановленные (загруженные):
$ systemctl list-units --all
list-units показывает только уже загруженные в память systemd. Если ты установил пакет с unit-файлом, но никогда не start-нул — list-units его может не показать.
list-unit-files смотрит на файлы на диске (более широкая выборка):
$ systemctl list-unit-files --type=service | head
UNIT FILE STATE PRESET
accounts-daemon.service enabled enabled
apparmor.service enabled enabled
apport.service enabled enabled
apt-daily-upgrade.service disabled enabled
apt-daily.service disabled enabled
...
ssh.service enabled enabled
systemd-journald.service enabled enabled
...
Полезно для аудита: «какие сервисы у нас вообще установлены и какие из них автозапустятся при reboot».
daemon-reload: после редактирования unit-файла
Когда ты редактируешь /etc/systemd/system/my-service.service или создаёшь override через systemctl edit, systemd не перечитывает файлы автоматически. Нужно явно:
$ sudo systemctl daemon-reload
После этого systemd перечитает все unit-файлы и применит изменения. Без daemon-reload ты увидишь warning при попытке restart:
$ sudo systemctl restart my-service
Warning: The unit file, source configuration file or drop-ins of my-service.service changed on disk. Run 'systemctl daemon-reload' to reload units.
Это типичная ошибка Junior: редактировал unit, запустил restart, удивляешься «почему ничего не поменялось». Ответ: daemon-reload.
Workflow при правке unit:
# 1) Редактировать
$ sudo systemctl edit my-service
# 2) Заставить systemd перечитать
$ sudo systemctl daemon-reload
# 3) Применить через restart
$ sudo systemctl restart my-service
# 4) Проверить
$ systemctl status my-service
journalctl integration: short, follow, since
systemctl status показывает только последние 10 строк журнала. Если нужно больше — journalctl:
# Полный журнал для одного unit
$ journalctl -u nginx
# С определённого времени
$ journalctl -u nginx --since "1 hour ago"
$ journalctl -u nginx --since today
# В режиме live tail
$ journalctl -u nginx -f
Подробно про journalctl — в следующем уроке 03-journalctl-logs.
mask: «заблокировать сервис намертво»
Иногда нужно гарантировать, что сервис никогда не запустится — даже если кто-то случайно сделает start. Для этого mask:
$ sudo systemctl mask cups
Created symlink /etc/systemd/system/cups.service -> /dev/null.
$ sudo systemctl start cups
Failed to start cups.service: Unit cups.service is masked.
mask создаёт symlink на /dev/null в /etc/systemd/system/ — systemd видит «нечего загружать». disable так не делает (только убирает autostart). Чтобы отменить — unmask.
Когда нужен mask на production:
- Хост не должен ни в коем случае слушать порты cups (печать).
- Случайно установился
apache2пакетом —mask, чтобы не запустился. - Тестовая VM, где надо отключить network-online ожидание.
DE-сценарий: рестарт упавшего worker
Реальная задача из дежурной смены:
# 1) PagerDuty: airflow-celery-worker down
$ ssh airflow-prod
# 2) Что не так?
$ systemctl status airflow-celery-worker
× airflow-celery-worker.service - Airflow Celery Worker
Active: failed (Result: exit-code) since 09:15; 23min ago
Main PID: 5432 (code=exited, status=137)
...
May 13 09:15:01 prod-vm systemd[1]: airflow-celery-worker.service: Main process killed by signal 9.
May 13 09:15:01 prod-vm systemd[1]: airflow-celery-worker.service: Main process exited, code=killed, status=9/KILL.
# 3) signal 9 = OOM killer. Подтверждаем:
$ dmesg | grep -i 'killed process'
[83294.231] Out of memory: Killed process 5432 (airflow), UID 1001, total-vm:8GB, RSS:7.9GB...
# 4) Память исчерпана. Можно ли просто рестартнуть?
$ free -h
total used free shared
Mem: 15Gi 12Gi 1.2Gi 128Mi
# 5) Память освобождена (OOM killer убил жирный процесс). Рестарт:
$ sudo systemctl restart airflow-celery-worker
# 6) Проверка:
$ systemctl is-active airflow-celery-worker
active
# 7) Длительная проверка через 1 минуту
$ sleep 60 && systemctl is-active airflow-celery-worker
active
# 8) Логи последних 5 минут — нет повторных crashes?
$ journalctl -u airflow-celery-worker --since "5 minutes ago" | head -50
Это типичный workflow. systemd упрощает: одной командой status ты видишь и состояние, и логи, и exit reason.
Все useful команды одной таблицей
Команды, которые DE использует ежедневно.
Попробуй сам
- Статус ssh:
systemctl status ssh - Что у тебя failed:
systemctl list-units --state=failed - Время загрузки сервисов:
systemd-analyze blame | head -10 - Сколько сервисов работает:
systemctl list-units --type=service --state=active | wc -l - Какие units включены в автозапуск:
systemctl list-unit-files --state=enabled | head -10 - Посмотри unit-файл одного из сервисов:
systemctl cat ssh.service
macOS-различия
- На macOS вместо
systemctl—launchctl. Команды:launchctl load,launchctl unload,launchctl start,launchctl stop. - Для Homebrew-пакетов есть удобная обёртка:
brew services start postgresql,brew services list,brew services stop postgresql. - launchd-конфиги —
.plistфайлы в XML, синтаксис заметно другой.
Главное
systemctl status SVC— главная команда. Статус + uptime + Logs + cgroup в одном выводе.- start/stop/restart/reload: restart = stop+start (теряет соединения), reload = SIGHUP (если ExecReload= задан).
- enable vs start: enable = автозапуск при boot, start = сейчас.
enable --now= оба. is-active,is-enabled— для скриптов и monitoring (exit code).list-units --state=failed— что упало. Первая команда после login.daemon-reload— обязательно после правки unit-файла. Иначе изменения не применятся.systemctl edit SVCсоздаёт override в/etc/systemd/system/SVC.d/— не редактируй основной unit-файл (apt upgradeперезапишет).mask— заблокировать сервис намертво.disable— только убрать autostart.- Sudo: нужен для
start/stop/restart/enable/disable. Не нужен дляstatus/is-active/list-units/cat.