Что такое target
Target - это не процесс и не сервис. Это .target-unit, который не
делает ничего сам, но через Wants= / Requires= тянет за собой набор
других unit'ов. Достижение target = «все нужные сервисы подняты».
Аналогия из SystemV: target ≈ runlevel, но с зависимостями вместо
пронумерованных скриптов в /etc/rc3.d/.
Маппинг с SystemV runlevels
| SystemV runlevel | systemd target | Что значит |
|---|---|---|
| 0 | poweroff.target | Выключение |
| 1 / S | rescue.target | Single-user, ФС смонтирована, root-shell |
| 1 (deeper) | emergency.target | Только emergency-shell, ФС не монтируется |
| 2 | multi-user.target | Многопользовательский без NFS (раньше) |
| 3 | multi-user.target | CLI-сервер: всё крутится, без GUI |
| 5 | graphical.target | Сервер + display manager (GUI) |
| 6 | reboot.target | Перезагрузка |
Алиасы runlevel3.target → multi-user.target сохранены для обратной
совместимости со старыми скриптами и командой init 3.
default.target - куда грузится система
/etc/systemd/system/default.target - symlink на canonical target:
ls -l /etc/systemd/system/default.target
▸/usr/lib/systemd/system/graphical.target
Это то, что systemd подхватывает при старте если в kernel cmdline
не передан systemd.unit=.... Менять руками ln -s не надо - есть команда:
systemctl get-default # текущий
sudo systemctl set-default multi-user.target # для серверов без GUI
Системные target'ы - полная цепочка boot
Они образуют дерево зависимостей. Идут от низкоуровневых к высокоуровневым:
sysinit.target ← маунты, swap, sysctl, journald
↓
basic.target ← timers.target, sockets.target, slices.target
↓
multi-user.target ← все обычные демоны (sshd, nginx, postgres)
↓
graphical.target ← + display-manager.service (gdm/lightdm)
↓
default.target ← symlink на одно из вышеперечисленного
Параллельно есть «синхронизирующие» target'ы:
network.target- все network-units сконфигурированы (НЕ значит онлайн)network-online.target- сеть реально готова, IP получен (для сервисов которые без интернета бесполезны)local-fs.target- все локальные ФС из mount-and-fstab смонтированыremote-fs.target- все NFS/SMB смонтированыtime-sync.target- время синхронизировано (см. chrony-and-ntp)
Как target собирает свои unit'ы
Два механизма:
1) Через [Install] секцию сервиса - когда ты делаешь systemctl enable nginx,
создаётся symlink:
/etc/systemd/system/multi-user.target.wants/nginx.service
→ /usr/lib/systemd/system/nginx.service
Эта папка .wants/ (и .requires/) - то, что target подхватывает при старте.
2) Через директиву WantedBy= в самом target-файле - для системных целей.
cat /usr/lib/systemd/system/graphical.target
# [Unit]
# Description=Graphical Interface
# Requires=multi-user.target
# Wants=display-manager.service
# After=multi-user.target display-manager.service
# AllowIsolate=yes
AllowIsolate=yes - критично: без этого target нельзя сделать default
и нельзя переключиться через isolate.
Переключение между target'ами на лету
sudo systemctl isolate multi-user.target # уйти в CLI без reboot
sudo systemctl isolate graphical.target # вернуть GUI
sudo systemctl isolate rescue.target # ремонт без перезагрузки
sudo systemctl rescue # то же что isolate rescue.target
sudo systemctl emergency # экстренный shell
isolate останавливает всё что НЕ нужно для нового target и стартует
то что нужно. Имя странное - но это оно.
Передача target через GRUB при загрузке
Если система не грузится в default.target - можно один раз перебить из
GRUB. На экране меню - e для редактирования, в строке linux ... дописать:
systemd.unit=rescue.target
Дальше Ctrl+X для загрузки. Только этот раз - default не меняется.
Дебаг - что входит в target
systemctl list-units --type=target # активные target'ы
systemctl list-dependencies multi-user.target # дерево всех unit'ов
systemctl list-dependencies --reverse nginx # в какие target'ы попадает nginx
systemctl cat multi-user.target # итоговый файл
Создавать свой target имеет смысл редко - например для группы
собственных сервисов которые включаются/выключаются вместе. Чаще
достаточно WantedBy=multi-user.target в обычных юнитах.