Learning Platform
Глоссарий Troubleshooting
Урок 16.02 · 22 мин
Начальный
systemctlservice managementenablestartstatusdaemon-reload

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.

Что здесь важно:

Анатомия `systemctl status`

Каждая строка отвечает на свой вопрос.

● цветиндикатор active/failed
Loaded:путь + enable status
Active:состояние unit
sinceuptime сервиса
Process:exec history с exit codes
Main PID, Tasks, Memoryресурсы из cgroup
CGroup:дерево процессов
Журнал (последние ~10)последние логи
# Сокращённая форма — не нужна суффикса .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 даст больше деталей (логи других пользователей).

Kubernetes Deployment — аналог systemctl enable в кластере

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
enable vs start: матрица состояний

Сервис может быть в любой из 4 комбинаций. Понимание матрицы — основа управления.

Состояние
Сейчас запущен (active)
Сейчас не запущен (inactive)
enabled (автозапуск)
Production-default: работает, переживёт reboot
Упал, скоро systemd попытается restart или ждёт. Также бывает между stop и start
disabled (без автозапуска)
Manual start. При reboot не запустится. Часто dev-сценарий — запустил вручную, поиграл
Полностью выключено. Manual start нужен явный

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 команды одной таблицей

Шпаргалка systemctl

Команды, которые DE использует ежедневно.

systemctl status SVCстатус + логи (главная!)
systemctl start/stop SVCзапустить/остановить
systemctl restart/reload SVCrestart vs reload
systemctl enable --now SVCautostart при boot + сейчас
systemctl disable --now SVCубрать autostart
systemctl is-active SVCдля скриптов, exit code
systemctl --state=failedчто упало
systemctl cat SVCсодержимое unit-файла
systemctl edit SVCсоздать override
systemctl daemon-reloadпосле правки unit
systemctl reboot/poweroffreboot/shutdown

Попробуй сам

  1. Статус ssh:
    systemctl status ssh
  2. Что у тебя failed:
    systemctl list-units --state=failed
  3. Время загрузки сервисов:
    systemd-analyze blame | head -10
  4. Сколько сервисов работает:
    systemctl list-units --type=service --state=active | wc -l
  5. Какие units включены в автозапуск:
    systemctl list-unit-files --state=enabled | head -10
  6. Посмотри unit-файл одного из сервисов:
    systemctl cat ssh.service

macOS-различия

  • На macOS вместо systemctllaunchctl. Команды: 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.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Чем отличается `systemctl start` от `systemctl enable`?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4