Jump to content
View in the app

A better way to browse. Learn more.

T.M.I IThub

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Введение: Почему SysVinit умер, и при чём тут Systemd

Представьте себе повара, который готовит ужин на 10 человек, но строго по одному блюду за раз — сначала суп, потом только начинает нарезать салат. Именно так работала старая система инициализации SysVinit: запускала службы строго по одной, в заранее заданном порядке. Независимо от того, зависят ли они друг от друга.

С усложнением Linux-систем это стало болью:

  • Медленная загрузка. Служба A ждёт завершения службы B, даже если между ними нет никакой реальной зависимости.

  • Нет контроля за процессами. Запустил — и забыл. Упал дочерний процесс? SysVinit об этом не знает.

  • Хаос в логах. Каждый сервис пишет куда хочет: один в /var/log/nginx/, другой в syslog, третий в /tmp/. Никакой единой точки входа.

  • Хрупкие скрипты. Shell-скрипты в /etc/init.d/ — это огромное поле для ошибок и несовместимостей между дистрибутивами.

В 2010 году Леннарт Поттеринг (Lennart Poettering) представил systemd — систему, которая решала все эти проблемы разом. Параллельный запуск, граф зависимостей, контрольные группы, централизованные логи. Сообщество поначалу встретило его в штыки (споры были жаркими), но сегодня systemd — стандарт де-факто в Fedora, Debian, Ubuntu, Arch, RHEL, CentOS и большинстве других дистрибутивов.

Давайте разберём его по косточкам.


Часть 1. Архитектура systemd — что происходит под капотом

1.1 PID 1 — главный процесс системы

Когда ядро Linux загружается, оно запускает самый первый пользовательский процесс с PID 1. В системах с systemd это и есть демон systemd. Он — прямой родитель всех остальных процессов в системе.

Это важно по двум причинам:

  1. Если PID 1 упадёт — система паникует. Поэтому systemd написан максимально надёжно.

  2. Все процессы, которые становятся «сиротами» (их родитель умер), автоматически переходят под крыло PID 1.

Ядро Linux
    └── systemd (PID 1)
            ├── journald (логирование)
            ├── udevd (устройства)
            ├── networkd (сеть)
            ├── nginx.service (ваш веб-сервер)
            ├── postgresql.service (БД)
            └── ... все остальные сервисы

1.2 Ключевые компоненты системы

systemd (PID 1) Главный дирижёр. Читает юнит-файлы, строит граф зависимостей, запускает процессы в нужном порядке, следит за их состоянием через cgroups.

systemctl Ваш пульт управления. Когда вы пишете systemctl start nginx, эта утилита НЕ запускает nginx напрямую. Она отправляет сообщение по D-Bus демону systemd, который и выполняет работу. Это ключевое отличие от простого вызова скрипта.

journald Централизованная система логирования. Перехватывает stdout и stderr всех сервисов, обогащает каждую запись метаданными (PID, UID, имя юнита, хостнейм) и сохраняет в структурированном бинарном формате. Это позволяет делать сложные запросы к логам — как SQL к базе данных.

udevd Менеджер устройств. Когда вы подключаете USB-флешку, именно udevd создаёт /dev/sdb, загружает нужные модули ядра и может запустить определённый сервис.

networkd, timedated, logind Специализированные демоны для управления сетью, системным временем и пользовательскими сессиями. Они общаются с PID 1 через D-Bus.

1.3 D-Bus — как компоненты разговаривают друг с другом

D-Bus — это системная шина сообщений, аналог внутренней корпоративной почты между процессами. Вместо того чтобы процессы вызывали функции друг друга напрямую (что небезопасно), они отправляют структурированные сообщения через шину.

Практический пример: systemctl start nginx

  1. systemctl формирует D-Bus-сообщение: «Вызови метод StartUnit с аргументом nginx.service»

  2. Сообщение уходит в системную шину

  3. Демон systemd получает его и выполняет

  4. Возвращает ответ через ту же шину

Это даёт безопасность (права проверяются на уровне D-Bus), гибкость (любая программа может управлять сервисами) и расширяемость.


Часть 2. Юниты — строительные блоки systemd

Юнит (unit) — это описание любого системного ресурса в виде декларативного конфигурационного файла. Думайте о нём как о «паспорте» для сервиса, сокета, таймера или точки монтирования.

2.1 Где хранятся юниты

Путь

Назначение

Приоритет

/usr/lib/systemd/system/

Юниты, установленные пакетным менеджером

Низкий

/etc/systemd/system/

Ваши кастомные юниты и переопределения

Высокий

/run/systemd/system/

Временные юниты (исчезают после перезагрузки)

Высший

Важно: Никогда не редактируйте файлы в /usr/lib/systemd/system/ напрямую — они перезапишутся при обновлении пакетов. Для изменения стандартного юнита используйте systemctl edit <имя>, который создаст drop-in файл в /etc/systemd/system/<имя>.d/override.conf.

2.2 Типы юнитов

.service — сервисы (самый частый тип)

Описывает демон или процесс. Именно с ним вы работаете в 90% случаев.

ini

# /etc/systemd/system/myapp.service
[Unit]
Description=My Awesome Application
After=network.target postgresql.service
Requires=postgresql.service

[Service]
Type=simple
ExecStart=/usr/bin/myapp --config /etc/myapp/config.yml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
User=myapp
Group=myapp

[Install]
WantedBy=multi-user.target

Параметр Type= — это важно понимать правильно:

Тип

Поведение

Когда использовать

simple

systemd считает сервис запущенным сразу после старта ExecStart

Большинство современных программ

forking

Программа делает fork() и завершает родительский процесс. systemd ждёт этого.

Старые Unix-демоны (nginx, apache)

notify

Программа сама сигнализирует systemd через sd_notify(), что готова

Программы с поддержкой systemd API

oneshot

Программа выполняется и завершается. systemd ждёт завершения.

Скрипты, одноразовые задачи

dbus

Сервис считается запущенным, когда занял имя на D-Bus

Демоны, использующие D-Bus

idle

Запуск откладывается до завершения всех остальных задач

Фоновые задачи с низким приоритетом

Жизненный цикл и перезапуск:

ini

[Service]
# Варианты для Restart=:
# no          — не перезапускать никогда
# on-success  — только при коде выхода 0
# on-failure  — при любом ненулевом коде, сигнале или таймауте (самый частый выбор)
# on-abnormal — при сигнале или таймауте (не при коде выхода)
# always      — перезапускать всегда (даже при systemctl stop!)
Restart=on-failure
RestartSec=5s

# Ограничение на количество перезапусков:
# Максимум 5 попыток за 30 секунд, потом сдаться
StartLimitIntervalSec=30s
StartLimitBurst=5

.socket — socket-based activation (ленивый запуск)

Это одна из самых мощных и недооценённых фич systemd. Идея простая: зачем держать 20 сервисов запущенными, если большинство из них обращаются раз в час?

Socket-based activation работает так:

  1. systemd открывает и слушает сокет (порт, Unix socket, FIFO)

  2. Сам сервис не запущен

  3. Приходит первое подключение

  4. systemd запускает сервис и передаёт ему уже установленное соединение

  5. Клиент не замечает разницы — соединение не потеряно!

ini

# /etc/systemd/system/echo.socket
[Unit]
Description=Echo Server Socket

[Socket]
ListenStream=12345
Accept=no

[Install]
WantedBy=sockets.target

ini

# /etc/systemd/system/echo.service
[Unit]
Description=Echo Server Service

[Service]
Type=simple
ExecStart=/usr/local/bin/echo-server
# Сервис получит сокет через файловый дескриптор 3
StandardInput=socket

Активация: sudo systemctl enable --now echo.socket — и сервис будет запускаться автоматически при первом подключении.

.timer — замена cron с суперспособностями

Таймеры systemd мощнее cron по нескольким причинам:

  • Поддерживают зависимости (запустить только если работает такой-то сервис)

  • Логируются в journald как обычные юниты

  • Могут «догнать» пропущенные запуски после перезагрузки (Persistent=true)

  • Точность до секунды и поддержка случайных задержек для распределения нагрузки

ini

# /etc/systemd/system/backup.timer
[Unit]
Description=Daily Backup Timer

[Timer]
# Запускать каждый день в 02:30
OnCalendar=*-*-* 02:30:00
# Случайная задержка до 10 минут (не всё одновременно в 02:30!)
RandomizedDelaySec=10m
# Запустить задачу, если она была пропущена (например, система была выключена)
Persistent=true

[Install]
WantedBy=timers.target

ini

# /etc/systemd/system/backup.service
[Unit]
Description=Daily Backup Job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=backup

Активация: sudo systemctl enable --now backup.timer

Проверить все активные таймеры: systemctl list-timers --all

Синтаксис OnCalendar:

Выражение

Значение

daily

Каждый день в 00:00

weekly

Каждый понедельник в 00:00

monthly

1-го числа каждого месяца

*-*-* 09:00:00

Каждый день в 09:00

Mon-Fri *-*-* 08:30:00

По будням в 08:30

*-*-1,15 00:00:00

1-го и 15-го каждого месяца

Проверить выражение: systemd-analyze calendar "Mon-Fri *-*-* 08:30:00"

.target — группы юнитов (замена runlevel)

Target — это не сервис, а точка синхронизации. Думайте об этом как о «состоянии системы», которого нужно достичь.

Target

Аналог runlevel

Значение

poweroff.target

0

Выключение

rescue.target

1

Однопользовательский режим

multi-user.target

3

Многопользовательский без GUI

graphical.target

5

С графическим интерфейсом

reboot.target

6

Перезагрузка

bash

# Узнать текущий target (аналог текущего runlevel)
systemctl get-default

# Сменить target (аналог init 3)
sudo systemctl isolate multi-user.target

# Установить target по умолчанию
sudo systemctl set-default multi-user.target

.path — реакция на события файловой системы

Аналог incron. Запускает сервис при изменениях в файловой системе.

ini

# /etc/systemd/system/watch-uploads.path
[Unit]
Description=Watch for new uploads

[Path]
# Запустить связанный .service когда появится этот файл
PathExists=/var/spool/uploads/trigger.flag
# Или мониторить директорию на изменения
DirectoryNotEmpty=/var/spool/uploads/

[Install]
WantedBy=multi-user.target

2.3 Зависимости между юнитами — граф, а не очередь

Это одно из ключевых отличий systemd от SysVinit. Вместо фиксированного порядка — направленный граф зависимостей.

Директивы зависимостей:

Директива

Тип

Поведение

Requires=

Жёсткая

Если зависимость не запустилась — этот юнит тоже не стартует и останавливается вместе с ней

Wants=

Мягкая

Пробует запустить зависимость, но если та упадёт — не останавливается

BindsTo=

Очень жёсткая

Как Requires, но юнит останавливается если зависимость остановится в любой момент

PartOf=

Односторонняя

Останавливается/перезапускается вместе с зависимостью, но не запускается вместе с ней

Conflicts=

Конфликт

Не может работать одновременно с указанным юнитом

Директивы порядка:

Директива

Поведение

After=

Этот юнит запускается ПОСЛЕ указанного

Before=

Этот юнит запускается ДО указанного

Важный нюанс: After= и Before= задают только порядок, но не зависимость! Если вы напишете только After=postgresql.service, но не Requires=postgresql.service, то ваш сервис стартует после PostgreSQL, но запустится даже если PostgreSQL упал. Обычно нужно использовать оба.

ini

[Unit]
# Правильная комбинация: сначала БД, потом мы, и мы не работаем без БД
After=postgresql.service
Requires=postgresql.service

Часть 3. cgroups — почему systemd знает всё о ваших процессах

3.1 Проблема, которую решают cgroups

Представьте: nginx запущен. Он форкает 4 воркера. Один воркер форкает ещё процесс для CGI. Тот форкает что-то ещё. Итого 10 процессов, и все они «принадлежат» nginx, но в SysVinit это было невозможно отследить.

Control Groups (cgroups) — механизм ядра Linux, который позволяет объединять процессы в иерархические группы и управлять ими совместно.

Systemd автоматически создаёт cgroup для каждого сервиса. Все дочерние процессы — внутри этой группы. Всегда.

/sys/fs/cgroup/
├── system.slice/
│   ├── nginx.service/        ← все процессы nginx здесь
│   │   ├── pid: 1234 (master)
│   │   ├── pid: 1235 (worker 1)
│   │   ├── pid: 1236 (worker 2)
│   │   └── pid: 1237 (cache loader)
│   ├── postgresql.service/   ← и postgres здесь
│   └── redis.service/
└── user.slice/
    └── user-1000.slice/      ← процессы пользователя

3.2 Что даёт cgroup на практике

Точный kill без зомби-процессов: При systemctl stop nginx systemd отправляет сигнал всей cgroup — умирают все 10 процессов, включая те, о которых вы не знали. Больше никаких «phantom workers».

Мониторинг:

bash

# Показать дерево процессов cgroup сервиса
systemd-cgls /system.slice/nginx.service
# Вывод:
# /system.slice/nginx.service
# └─ 1234 /usr/sbin/nginx -g daemon off;
#    ├─ 1235 nginx: worker process
#    ├─ 1236 nginx: worker process
#    └─ 1237 nginx: cache loader process

# Мониторинг ресурсов в реальном времени (как top, но для cgroups)
systemd-cgtop

3.3 Ограничение ресурсов через юнит-файлы

Это магия. Вместо сложных настроек cgroups вручную — просто добавляете строки в секцию [Service]:

ini

[Service]
# === ПАМЯТЬ ===
# Мягкий лимит: systemd начнёт агрессивно освобождать память
MemoryHigh=400M
# Жёсткий лимит: OOM Killer убьёт процесс если превысит
MemoryMax=512M
# Гарантированная память (не будет отдана другим)
MemoryMin=100M

# === CPU ===
# 50% от одного ядра
CPUQuota=50%
# Или: вес CPU (1-10000, default=100)
CPUWeight=200

# === ДИСК (I/O) ===
# Ограничение чтения/записи для конкретного устройства
IOReadBandwidthMax=/dev/sda 50M
IOWriteBandwidthMax=/dev/sda 20M

# === СЕТЬ (через IP accounting) ===
IPAccounting=yes
IPAddressAllow=192.168.0.0/24
IPAddressDeny=any

Проверка текущих лимитов:

bash

# Посмотреть параметры cgroup напрямую в файловой системе
cat /sys/fs/cgroup/system.slice/nginx.service/memory.max
# 536870912 (512 МБ в байтах)

# Или через systemctl
systemctl show nginx.service | grep -E 'Memory|CPU|IO'

Часть 4. journald — логи как база данных

4.1 Почему journald лучше текстовых логов

Обычный syslog — это текстовый файл. Хочешь найти все ошибки nginx за последний час? Пишешь grep "error" /var/log/nginx/error.log | grep "$(date +%b\ %d)" и молишься.

journald — структурированное хранилище с индексами. Каждая запись — не строчка текста, а объект с полями:

_SYSTEMD_UNIT=nginx.service    ← какой сервис
_PID=1234                       ← какой процесс
_UID=www-data                   ← от какого пользователя
_HOSTNAME=web-01                ← на каком хосте
PRIORITY=3                      ← уровень важности (err)
MESSAGE=connection refused...   ← само сообщение
_SOURCE_REALTIME_TIMESTAMP=...  ← точное время

4.2 Полное руководство по journalctl

bash

# === БАЗОВЫЕ ЗАПРОСЫ ===

# Все логи конкретного сервиса
sudo journalctl -u nginx.service

# Последние 50 строк
sudo journalctl -u nginx.service -n 50

# Следить в реальном времени (как tail -f)
sudo journalctl -u nginx.service -f

# С определённого момента
sudo journalctl -u nginx.service --since "2024-01-15 10:00:00"
sudo journalctl -u nginx.service --since "1 hour ago"
sudo journalctl -u nginx.service --since today
sudo journalctl -u nginx.service --since yesterday --until "2024-01-14 23:59:59"

# === ФИЛЬТРАЦИЯ ПО УРОВНЮ ВАЖНОСТИ ===
# 0=emerg, 1=alert, 2=crit, 3=err, 4=warning, 5=notice, 6=info, 7=debug
sudo journalctl -p err                      # только err
sudo journalctl -p err..warning             # от err до warning
sudo journalctl -u nginx -p warning         # предупреждения nginx

# === ФИЛЬТРАЦИЯ ПО ЗАГРУЗКЕ ===
sudo journalctl -b                          # текущая загрузка
sudo journalctl -b -1                       # предыдущая загрузка
sudo journalctl -b -2                       # позапрошлая загрузка
sudo journalctl --list-boots                # список всех загрузок

# === ФОРМАТЫ ВЫВОДА ===
sudo journalctl -u nginx -o json            # JSON (для парсинга)
sudo journalctl -u nginx -o json-pretty     # JSON с форматированием
sudo journalctl -u nginx -o verbose         # Все поля записи
sudo journalctl -u nginx -o cat             # Только текст сообщений

# === ПРОДВИНУТЫЕ ЗАПРОСЫ ===

# Логи конкретного процесса
sudo journalctl _PID=1234

# Логи от конкретного пользователя
sudo journalctl _UID=1000

# Комбинирование условий (OR)
sudo journalctl _SYSTEMD_UNIT=nginx.service + _SYSTEMD_UNIT=php-fpm.service

# Экспорт в файл
sudo journalctl -u nginx --since today -o json > nginx-today.json

# === УПРАВЛЕНИЕ ЖУРНАЛОМ ===

# Размер журнала на диске
sudo journalctl --disk-usage

# Очистка старых логов (оставить только за последние 2 недели)
sudo journalctl --vacuum-time=2weeks

# Очистка до определённого размера
sudo journalctl --vacuum-size=500M

4.3 Настройка journald

ini

# /etc/systemd/journald.conf
[Journal]
# Максимальный размер журнала на диске
SystemMaxUse=1G

# Максимальный размер одного файла журнала
SystemMaxFileSize=100M

# Хранить журналы не дольше
MaxRetentionSec=1month

# Сжатие (по умолчанию включено)
Compress=yes

# Перенаправить в syslog (для совместимости)
ForwardToSyslog=no

# Уровень логирования по умолчанию
MaxLevelStore=debug
MaxLevelSyslog=warning

После изменения: sudo systemctl restart systemd-journald


Часть 5. Практика — реальные сценарии

5.1 Создание production-ready сервиса с нуля

Задача: создать сервис для Go-приложения с полной изоляцией и автоматическим перезапуском.

ini

# /etc/systemd/system/api-server.service
[Unit]
Description=API Server
Documentation=https://github.com/company/api-server
After=network.target
Wants=network-online.target
After=network-online.target

# Если зависит от БД:
Requires=postgresql.service
After=postgresql.service

[Service]
Type=notify
# Путь к бинарнику
ExecStart=/usr/local/bin/api-server
# Путь к конфигу через переменную окружения
EnvironmentFile=/etc/api-server/env
# Или напрямую:
Environment="PORT=8080"
Environment="LOG_LEVEL=info"

# Перезапуск
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60s
StartLimitBurst=3

# Пользователь и группа
User=api
Group=api

# Рабочая директория
WorkingDirectory=/opt/api-server

# === БЕЗОПАСНОСТЬ ===
# Запрет повышения привилегий
NoNewPrivileges=yes
# Изолированный /tmp
PrivateTmp=yes
# Только чтение для /usr, /boot, /etc
ProtectSystem=strict
# Запрет доступа к домашним директориям
ProtectHome=yes
# Изолированная сеть для системных вызовов
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
# Список разрешённых системных вызовов
SystemCallFilter=@system-service
# Разрешить запись только в эти директории
ReadWritePaths=/var/lib/api-server /var/log/api-server

# === РЕСУРСЫ ===
MemoryMax=512M
CPUQuota=200%
# Ограничение открытых файлов
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Применение:

bash

sudo systemctl daemon-reload
sudo systemctl enable --now api-server.service
sudo systemctl status api-server.service

5.2 Drop-in файлы — переопределение без изменения оригинала

Золотое правило: никогда не редактируйте файлы в /usr/lib/systemd/system/. Используйте drop-in файлы.

bash

# Удобный способ — systemctl edit сам создаст файл
sudo systemctl edit nginx.service

Создастся файл /etc/systemd/system/nginx.service.d/override.conf:

ini

[Service]
# Добавим лимит памяти к стандартному nginx
MemoryMax=256M
# Переопределим тип перезапуска
Restart=always
# Добавим переменную окружения
Environment="NGINX_ENVSUBST_OUTPUT_DIR=/etc/nginx"

bash

# После сохранения:
sudo systemctl daemon-reload
sudo systemctl restart nginx.service

# Посмотреть итоговую конфигурацию (оригинал + drop-ins)
sudo systemctl cat nginx.service

5.3 Анализ и оптимизация времени загрузки

bash

# Общее время загрузки
systemd-analyze
# Startup finished in 2.134s (kernel) + 8.643s (userspace) = 10.777s

# Топ «тормозов» при загрузке
systemd-analyze blame
# 4.123s NetworkManager-wait-online.service
# 2.456s plymouth-quit-wait.service
# 1.234s dev-sda1.device
# 0.987s apparmor.service

# Критический путь загрузки — что тормозит конкретный target
systemd-analyze critical-chain graphical.target

# Визуальная диаграмма в SVG (откройте в браузере!)
systemd-analyze plot > boot-plot.svg

# Проверить юнит-файл на ошибки
systemd-analyze verify /etc/systemd/system/myapp.service

Частые причины медленной загрузки и как их лечить:

Проблема

Симптом

Решение

NetworkManager-wait-online.service

20-30 секунд ожидания сети

sudo systemctl disable NetworkManager-wait-online.service (если сеть не нужна при загрузке)

Сервис висит на старте

Долгий timeout

Проверить TimeoutStartSec= и зависимости

Много последовательных зависимостей

Длинный critical chain

Заменить Requires= на Wants= где возможно

5.4 Диагностика падающего сервиса — пошаговый алгоритм

bash

# Шаг 1: Статус сервиса
sudo systemctl status myapp.service
# Ищем: статус (failed/active), последние строки лога, код выхода

# Шаг 2: Последние логи с подробными метаданными
sudo journalctl -u myapp.service -n 100 --no-pager

# Шаг 3: Логи с момента последней загрузки (для проблем при старте)
sudo journalctl -u myapp.service -b

# Шаг 4: Все ошибки в системе в момент падения
sudo journalctl -p err --since "10 min ago" --no-pager

# Шаг 5: Проверить зависимости
systemctl list-dependencies myapp.service
# Все зависимости должны быть зелёными

# Шаг 6: Запустить вручную под тем же пользователем (для воспроизведения)
sudo -u myapp /usr/local/bin/myapp --config /etc/myapp/config.yml

# Шаг 7: Посмотреть все переменные окружения сервиса
sudo systemctl show myapp.service -p Environment

# Шаг 8: Проверить права доступа к файлам
sudo systemctl cat myapp.service | grep -E 'ExecStart|WorkingDirectory|User'
sudo ls -la /usr/local/bin/myapp

Часть 6. Продвинутые техники

6.1 Шаблонные юниты — один файл для многих экземпляров

Если нужно запустить один и тот же сервис с разными параметрами (например, несколько воркеров), используйте шаблоны.

ini

# /etc/systemd/system/worker@.service
# Обратите внимание на @ в имени файла!
[Unit]
Description=Worker Instance %i
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/worker --id=%i --config=/etc/worker/config.yml
User=worker
Restart=on-failure

[Install]
WantedBy=multi-user.target

Запуск нескольких экземпляров:

bash

# %i заменится на значение после @
sudo systemctl start worker@1.service
sudo systemctl start worker@2.service
sudo systemctl start worker@3.service

# Или всех сразу:
sudo systemctl enable worker@{1..5}.service
sudo systemctl start worker@{1..5}.service

# Посмотреть все запущенные экземпляры
systemctl list-units 'worker@*'

6.2 Временные сервисы через systemd-run

bash

# Запустить команду как временный сервис (исчезнет после завершения)
sudo systemd-run --unit=my-task /usr/bin/python3 /opt/scripts/heavy_task.py

# С ограничением ресурсов
sudo systemd-run --unit=cpu-heavy --property=CPUQuota=50% --property=MemoryMax=256M \
    /usr/bin/python3 /opt/scripts/heavy_task.py

# Следить за прогрессом
journalctl -u my-task -f

6.3 Полезные команды, о которых мало кто знает

bash

# Проверить юнит-файл на синтаксические ошибки ДО применения
systemd-analyze verify /etc/systemd/system/myapp.service

# Показать все переопределения (drop-in файлы) для сервиса
systemctl cat nginx.service

# Показать все свойства юнита
systemctl show nginx.service

# Показать конкретное свойство
systemctl show nginx.service -p MainPID
systemctl show nginx.service -p MemoryCurrent

# Перезагрузить конфиги без daemon-reload (для drop-in файлов)
sudo systemctl daemon-reload

# Перечитать конфиги всех сервисов (более мягкий вариант)
sudo systemctl reload-or-restart nginx.service

# Узнать, какой пакет установил юнит
systemctl cat nginx.service | head -1
# # /lib/systemd/system/nginx.service
dpkg -S /lib/systemd/system/nginx.service   # Debian/Ubuntu
rpm -qf /lib/systemd/system/nginx.service  # RHEL/Fedora

# Блокировка: сервис не запустится даже вручную
sudo systemctl mask dangerous-service.service
# Разблокировка
sudo systemctl unmask dangerous-service.service

Шпаргалка — все команды в одном месте

Управление сервисами

Задача

Команда

Запустить

sudo systemctl start <name>

Остановить

sudo systemctl stop <name>

Перезапустить

sudo systemctl restart <name>

Перечитать конфиг (без остановки)

sudo systemctl reload <name>

Reload или restart

sudo systemctl reload-or-restart <name>

Статус

systemctl status <name>

Включить автозапуск

sudo systemctl enable <name>

Выключить автозапуск

sudo systemctl disable <name>

Включить И запустить

sudo systemctl enable --now <name>

Заблокировать навсегда

sudo systemctl mask <name>

Просмотр состояния

Задача

Команда

Все запущенные сервисы

systemctl list-units --type=service --state=running

Все упавшие

systemctl --failed

Проверить автозапуск

systemctl is-enabled <name>

Проверить активность

systemctl is-active <name>

Дерево зависимостей

systemctl list-dependencies <name>

Кто зависит от этого

systemctl list-dependencies --reverse <name>

Все таймеры

systemctl list-timers

Логи (journalctl)

Задача

Команда

Логи сервиса

sudo journalctl -u <name>

Последние N строк

sudo journalctl -u <name> -n 50

В реальном времени

sudo journalctl -u <name> -f

За текущую загрузку

sudo journalctl -u <name> -b

Только ошибки

sudo journalctl -u <name> -p err

С определённого времени

sudo journalctl -u <name> --since "1h ago"

Размер журнала

sudo journalctl --disk-usage

Очистить старые

sudo journalctl --vacuum-time=2weeks

Диагностика производительности

Задача

Команда

Время загрузки

systemd-analyze

Что грузилось дольше всех

systemd-analyze blame

Критический путь

systemd-analyze critical-chain <target>

Визуальная диаграмма

systemd-analyze plot > boot.svg

Проверить юнит-файл

systemd-analyze verify /path/to/unit

Дерево cgroups

systemd-cgls

Ресурсы cgroups в реальном времени

systemd-cgtop


Заключение

Systemd — это не монстр, которого стоит бояться. Это мощный инструмент, понимание которого делает вас значительно эффективнее как системного администратора или разработчика. Несколько ключевых идей, которые стоит унести из этой статьи:

  1. Юниты — декларативные описания ресурсов. Пишите их правильно, используя все доступные настройки безопасности.

  2. cgroups — системd всегда знает, где ваши процессы. Используйте это для мониторинга и ограничения ресурсов.

  3. journald — это база данных, а не текстовый файл. Учитесь делать правильные запросы.

  4. Drop-in файлы — никогда не редактируйте оригинальные юнит-файлы из пакетов.

  5. systemd-analyze — ваш первый инструмент при проблемах с загрузкой.

User Feedback

Create an account or sign in to leave a review

There are no reviews to display.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.