- Systemd: пишем собственные .service и .target
- Чего я хотел?
- Что я сделал?
- Что такое service?
- Что такое target?
- Как я это сделал?
- Какие были проблемы?
- Результат
- Cheat sheet
- Systemd за пять минут
- Добавить сервис в systemd
- systemd (Русский)
- Contents
- Основы использования systemctl
- Использование юнитов
- Управление питанием
- Написание файлов юнитов
- Обработка зависимостей
- Типы служб
- Редактирование файлов юнитов
- Замещение файла юнита
- Drop-in файлы
- Откат изменений
- Примеры
- Получение информации о текущих целях
- Создание пользовательской цели
- Соответствие уровней SysV целям systemd
- Изменение текущей цели
- Изменение цели загрузки по умолчанию
- Порядок выбора цели по умолчанию
- Компоненты systemd
- systemd.mount — монтирование
- Автомонтирование GPT-раздела
- systemd-sysvcompat
- systemd-tmpfiles — временные файлы
- Советы и рекомендации
- Программы настройки с графическим интерфейсом
- Запуск сервисов после подключения к сети
- Включение установленных юнитов по умолчанию
- Песочница для приложений
- Уведомление о неработающих службах
- Решение проблем
- Неудачно запущенные службы
- Диагностика загрузки системы
- Диагностика службы
- Выключение/перезагрузка происходят ужасно долго
- По-видимому, процессы с кратким сроком жизни не оставляют записей в логах
- Время загрузки системы увеличивается с течением времени
- systemd-tmpfiles-setup.service не запускается во время загрузки
- Отключение emergency mode на удалённой машине
Systemd: пишем собственные .service и .target
У меня появился Linux на домашнем компьютере, и я поспешил обжиться в новой ОС. Она была установлена с systemd init process. Это было мое первое знакомство с этим новым инструментом. Cвой ноутбук я использую для каждодневной жизни и для программирования. Мне хотелось включать рабочие программы (Apache2 и MySQL) только на время, пока я их использую, чтобы не тратить впустую ресурсы своего компьютера. Дополнительно, для тестирования я написал bash скрипт, который выгружает содержимое одной из MySQL БД c жесткого диска в ОЗУ (в tmpfs) – так тесты выполняются значительно быстрее. По идее, я мог бы начинать свой рабочий день вот так:
И заканчивать его:
Но мне хотелось сделать вещи “как надо”.
Чего я хотел?
Я хотел достичь 2 целей:
- Мне было лень писать 2 команды (запуск apache и запуск mysql), т.к. я знал, что обе программы всегда будут выключаться и включаться синхронно. Хотелось выполнять эту операцию одной командой.
- Дело попахивало неприятностями, если компьютер перезагрузится пока моя база данных будет сидеть в tmpfs – все файлы будут потеряны. Конечно, я делал бекапы, но мне опять же было лень восстанавливать их вручную после каждой непредвиденной перезагрузки.
Что я сделал?
В итоге я объединил Apache2 и MySQL в один target. Это позволило запускать оба сервиса одной командой. А свой mysqld-tmpfs скрипт я декларировал в виде сервиса в глазах systemd. Будучи сервисом, я уверен, что systemd выполнит его корректную остановку, если система пойдет на перезагрузку или еще в какую-то нештатную ситуацию, и моя БД без потерь сохранится на жесткий диск.
Что такое service?
Это некоторая программа, которая выполняется в фоне и предоставляет полезную функциональность. К примеру, Apache веб сервер. Сервисы можно запускать и останавливать. Некоторые сервисы могут запускаться и останавливаться автоматически по определенным событиям (загрузка ОС, выгрузка ОС и тп). Так же их можно запускать/останавливать вручную. Сервис декларируется в /etc/systemd/system/my-name.service файлах (с суффиксом “.service”).
Что такое target?
Target в systemd очень похож на runlevel в openRC, но это все-таки разные вещи. Во-первых, target позволяет группировать 1 и более сервисов в единый блок. Группируя сервисы в targets, ими проще управлять. Во-вторых, systemd автоматически включает/выключает targets по событиям. “Включение” target означает включение всех сервисов, которые он объединяет в себе. К примеру, если в systemd настроен target по умолчанию my-favorite.target, то при загрузке системы systemd включит все сервисы, которые задекларированы внутри my-favorite.target. В какой-то момент в консоли можно набрать:
Все сервисы из my-another.target будут включены, и все включенные сервисы не из my-another.target будут выключены. Это очень похоже на переключение runlevel в openRC. Однако, systemd поддерживает включение более чем 1 target. Вот пример:
После выполнения этих команд в системе будет работать объединение сервисов из my-favorite.target и my-another.target.
Как я это сделал?
В итоге у меня получился вот такой mysqld-tmpfs.service файл:
И вот такой programming.target файл:
Какие были проблемы?
При остановке programming.target почему-то нижележащие apache2.service и mysqld.service не останавливались. Почитав как следует man page, я нашел проблему: systemd останавливает сервисы “лениво” — если никто не требует запущенный сервис, и он не был запущен явным образом, а как зависимость для какого-то другого сервиса, то systemd остановит его только при одном из 3 обстоятельств:
- Запустится какой-то другой сервис, который в своей декларации указывает, что он конфликтует с нашим сервисом.
- Выполнится systemctl isolate some-another.target или systemctl stop this.service.
- Наш сервис может запросить в своей декларации останавливать себя не ленивым образом, а активным, добавив вот такую строку в [Unit] секцию: StopWhenUnneeded=true
Декларации “чужих” сервисов можно менять создавая файлы /etc/systemd/system/name-i-alter.service.d/*.conf. Я просто создал /etc/systemd/system/apache2.service/auto-stop.conf и /etc/systemd/system/mysqld.service.d/auto-stop.conf и поместил туда ту строку.
Другая проблема, на которую я, наткнулся была в том, что systemd не очень любит symlinks. Я не большой любитель “загаживать” системные директории типа /etc, /bin, /usr своими локальными продуктами жизнедеятельности, поэтому изначально я попытался свой /etc/systemd/system/mysqld-tmpfs.service сделать symlink на /root/scripts/mysqld-tmpfs.service файл, т.е. хранить сам файл в домашнем каталоге root пользователя. Но systemctl команда отказывалась работать с таким сервисом выдавая малопонятные ошибки. Оказалось, что определенную часть своей внутренней кухни systemd делает именно на symlinks, и ему тогда “трудно” отличать внутреннюю кухню (свои symlinks) от сторонних *.service файлов (если они тоже являются symlinks). Удалив symlink из /etc/systemd/system/mysqld-tmpfs.service и скопировав туда содержимое настоящего файла, я решил эту проблему. Более подробное описание этой проблемы можно прочитать тут: bugzilla.redhat.com/show_bug.cgi?id=955379
Результат
Я достиг своей цели. Начиная рабочий день:
Когда нужно выполнить тесты на своем проекте:
Когда я хочу демонтировать БД из tmpfs в жесткий диск (хотя на практике я так почти не делаю, а просто оставляю БД в tmpfs на целый день, и при выключении systemd за меня запускает демонтировку из tmpfs в жесткий диск):
Когда я закончил работать и хочу остановить рабочие программы:
Cheat sheet
Некоторые полезности при работе с systemd:
- Вызывайте systemctl daemon-reload, если вы изменили декларацию чего-либо (systemd считает файлы декларации заново)
- systemctl start my-name.(service|target) – запуск сервиса или target
- systemctl stop my-name.(service|target) – остановка сервиса или target
- systemctl enable my-name.service – сервисы могут декларировать при каких включенных targets они должны включаться. Для этого используется [Install] секция в файле декларации сервиса. Вы, как сисадмин, имеете власть на установку этого “пожелания” сервиса. Часто сервисы “устанавливаются” в target по умолчанию multi-user.target или в похожее.
- systemctl disable my-name.service – обратная операция по отношению к enable: деассоциировать связь между my-name.service и targets, которые он запросил в [Install] секции своей декларации.
- systemctl isolate my.target — включить все сервисы из my.target и выключить все остальные включенные сервисы.
- systemctl status my-name.(service|target) — узнать статус (запущен/остановлен) у сервиса или target.
Надеюсь, эта статья кому-то поможет при осваивании systemd. Я попытался сделать ее компактной, и если упустил из внимания какие-то дополнительные вопросы, спрашивайте в комментариях!
Источник
Systemd за пять минут
Наша компания занимается администрированием веб-серверов на базе CentOS. Довольно часто наши клиенты используют веб-приложения на базе python, ruby или java. Для автозапуска подобных приложений есть готовые шаблоны для написания стартап-скриптов. Но прогресс не стоит на месте, вышел уже второй релиз CentOS 7 и, следуя старой традиции «не ставить dot-zero релизы на продакшен», мы начинаем предлагать клиентам сервера на базе CentOS 7.1 (1503).
В CentOS7, так же как и в его родителе RHEL7, используется systemd — менеджер системы и служб для Linux, совместимый со скриптами инициализации SysV и LSB. systemd обеспечивает возможности агрессивной параллелизации и много всего прочего.
Огромный монстр с множеством возможностей, гибкими настройками и мегабайтами документации…
Но что делать, если стоит задача быстро-быстро, вот прямо вчера, сделать автозапуск некоего сервиса?
Давайте выжмем из документации минимально необходимый набор информации для создания простых старт-стоп скриптов.
Systemd запускает сервисы описанные в его конфигурации.
Конфигурация состоит из множества файлов, которые по-модному называют юнитами.
Все эти юниты разложены в трех каталогах:
/usr/lib/systemd/system/ – юниты из установленных пакетов RPM — всякие nginx, apache, mysql и прочее
/run/systemd/system/ — юниты, созданные в рантайме — тоже, наверное, нужная штука
/etc/systemd/system/ — юниты, созданные системным администратором — а вот сюда мы и положим свой юнит.
Юнит представляет из себя текстовый файл с форматом, похожим на файлы .ini Microsoft Windows.
[Название секции в квадратных скобках]
имя_переменной = значение
Для создания простейшего юнита надо описать три секции: [Unit], [Service], [Install]
В секции Unit описываем, что это за юнит:
Названия переменных достаточно говорящие:
Далее следует блок переменных, которые влияют на порядок загрузки сервисов:
Запускать юнит после какого-либо сервиса или группы сервисов (например network.target):
After=syslog.target
After=network.target
After=nginx.service
After=mysql.service
В итоге переменная Wants получается чисто описательной.
Если сервис есть в Requires, но нет в After, то наш сервис будет запущен параллельно с требуемым сервисом, а не после успешной загрузки требуемого сервиса
В секции Service указываем какими командами и под каким пользователем надо запускать сервис:
(по умолчанию): systemd предполагает, что служба будет запущена незамедлительно. Процесс при этом не должен разветвляться. Не используйте этот тип, если другие службы зависят от очередности при запуске данной службы.
systemd предполагает, что служба запускается однократно и процесс разветвляется с завершением родительского процесса. Данный тип используется для запуска классических демонов.
Также следует определить PIDFile=, чтобы systemd могла отслеживать основной процесс:
Команды на старт/стоп и релоад сервиса
ExecStart=/usr/local/bin/bundle exec service -C /work/www/myunit/shared/config/service.rb —daemon
ExecStop=/usr/local/bin/bundle exec service -S /work/www/myunit/shared/tmp/pids/service.state stop
ExecReload=/usr/local/bin/bundle exec service -S /work/www/myunit/shared/tmp/pids/service.state restart
Тут есть тонкость — systemd настаивает, чтобы команда указывала на конкретный исполняемый файл. Надо указывать полный путь.
Таймаут в секундах, сколько ждать system отработки старт/стоп команд.
Попросим systemd автоматически рестартовать наш сервис, если он вдруг перестанет работать.
Контроль ведется по наличию процесса из PID файла
В секции [Install] опишем, в каком уровне запуска должен стартовать сервис
multi-user.target или runlevel3.target соответствует нашему привычному runlevel=3 «Многопользовательский режим без графики. Пользователи, как правило, входят в систему при помощи множества консолей или через сеть»
Вот и готов простейший стартап скрипт, он же unit для systemd:
myunit.service
Кладем этот файл в каталог /etc/systemd/system/
Смотрим его статус systemctl status myunit
Видим, что он disabled — разрешаем его
systemctl enable myunit
systemctl -l status myunit
Если нет никаких ошибок в юните — то вывод будет вот такой:
Запускаем сервис
systemctl start myunit
Смотрим красивый статус:
systemctl -l status myunit
Если есть ошибки — читаем вывод в статусе, исправляем, не забываем после исправлений в юните перегружать демон systemd
Источник
Добавить сервис в systemd
В этой заметке я расскажу о том, как настроить сервис Linux для автоматического запуска демона после сбоя или перезагрузки. В качестве примера я буду использовать Nginx и PHP но вы можете этот способ для любых приложений.
Уже прошло достаточно много времени с того момента, как большинство популярных дистрибутивов Linux перешли на системный менеджер systemd . Тем не менее, до сих пор старая система инициализации SysV продолжает параллельно функционировать на ряду с systemd . И как и раньше, большинство пакетов после установки добавляют стартовый скрипт в каталог init.d .
Не буду вдаваться в подробности про механизмы параллелизации systemd и скорость загрузку системы. Это все хорошо и прекрасно. Но для меня главный аргумент в ползу перехода на systemd — это наличие встроенных функций отслеживания и контроля состояния сервисов. Что бы было понятнее, давайте представим следующую ситуацию.
Для примера мы установили OpenVPN, для которого по умолчанию используется механизм запуска System V. Во время установки пакета в каталог /etc/init.d будет скопирован скрипт инициализации, который будет отвечать за автоматический запуск приложения после перезагрузки. Если в один прекрасный день OpenVPN упадет, без дополнительных настроек, нужно будет каждый раз запускать этот процесс вручную.
Теперь возьмем ситуацию, когда для запуск сервиса выполнен через systemd . Если произойдет крэш или даже если вы захотите специально убить процесс, то systemd автоматически это обнаружит и повторно запустит процесс. При этом systemd обратно совместим с командами System V и сценариями инициализации.
А теперь давайте рассмотрим, как быстро добавить сервис в systemd . Демон systemd запускает сервисы описанные в его конфигурации. Конфигурация состоит из файлов, которые называют юнитами. Для юнитов созданных вручную используется каталог:
В простом варианте юнит состоит из трех секции: [Unit] , [Service] , [Install] .
Секция [Unit]
Далее указываем порядок загрузки, после какого сервиса systemd запустить наш юнит:
Секция [Service]
Задаем тип сервиса:
Используется по умолчанию. Служба будет запущена незамедлительно. Процесс при этом не должен разветвляться. Не используйте этот тип, если другие службы зависят от очередности при запуске данной службы.
Указывают если служба запускается однократно и процесс разветвляется с завершением родительского процесса.
Рабочий каталог приложения:
Пользователь и группа, под которым будет запускаться сервис:
Задаем приоритет убийства процесса при нехватке памяти:
Минимальное значение -1000 — полный запрет.
Команды запуска, остановки и перезапуска сервиса:
Таймаут запуска или остановки сервиса:
Контроль запуска сервиса и автоматический запуск в случае крєша:
Секция [Install]
Уровень запуска сервиса:
В итоге мы получили следующий юнит:
Добавляем юнит в каталог:
Включаем, запускаем и смотрим статус юнита:
А теперь привожу примеры работающих юнитов.
Источник
systemd (Русский)
systemd — набор базовых строительных кирпичиков Linux-системы. Представляет собой менеджер системы и служб, который выполняется как процесс с PID 1 и запускает остальную часть системы. systemd обеспечивает возможности агрессивной параллелизации, сокет- и D-Bus-активацию для запуска служб, запуск демонов по запросу, отслеживание процессов с помощью контрольных групп Linux, обслуживание точек (авто)монтирования, а также предлагает развитую транзакционную логику управления службами на основе зависимостей. systemd поддерживает сценарии инициализации SysV и LSB и работает как замена sysvinit. Среди прочих элементов и функций — демон журнала, утилиты управления базовой конфигурацией системы (имя хоста, дата, языковой стандарт), ведение списков вошедших в систему пользователей, запущенных контейнеров, виртуальных машин, системных учётных записей, каталогов и настроек времени выполнения, а также демоны для управления несложными сетевыми конфигурациями, синхронизации времени по сети, пересылки журналов и разрешения имён.
Contents
Основы использования systemctl
Главная команда для работы с systemd — systemctl. Она позволяет (среди прочего) отлеживать состояние системы и управлять системой и службами. Подробнее см. systemctl(1) .
Использование юнитов
Юнитами могут быть, например, службы (.service), точки монтирования (.mount), устройства (.device) или сокеты (.socket).
При работе с systemctl обычно необходимо указывать полное имя юнита с суффиксом, например, sshd.socket . Существует несколько возможных сокращений:
- Если суффикс не указан, systemctl предполагает, что это .service. Например, netctl равнозначно netctl.service .
- Точки монтирования автоматически преобразуются в юнит .mount. Например, /home равнозначно home.mount .
- Аналогично точкам монтрования, имена устройств автоматически преобразуются в юнит .device. Например, /dev/sda2 равнозначно dev-sda2.device .
Если говорить точнее, systemd сначала попытается найти юнит, название которого полностью совпадёт с название@строка.суффикс , и лишь в случае неудачи создаст экземпляр шаблона название@.суффикс . Тем не менее, такие «конфликты» довольно редки, так как по соглашению символ @ должен использоваться только в названиях юнитов-шаблонов. Также помните, что вызвать юнит-шаблон без идентификатора экземпляра не получится, поскольку в этом случае нечего будет подставить вместо спецификатора %i .
Действие | Команда | Примечание |
---|---|---|
Анализ состояния системы | ||
Состояние системы | $ systemctl status | |
Список запущенных юнитов | $ systemctl или $ systemctl list-units | |
Список юнитов, запустить которые не удалось | $ systemctl —failed | |
Список установленных файлов юнитов 1 | $ systemctl list-unit-files | |
Информация о процессе по его PID | $ systemctl status pid | cgroup slice, занимаемая память и родительский процесс |
Состояние юнита | ||
Страница руководства юнита | $ systemctl help юнит | если юнит её предоставляет |
Состояние юнита | $ systemctl status юнит | в т. ч. работает ли он в данный момент |
Проверить, добавлен ли юнит в автозапуск | $ systemctl is-enabled юнит | |
Запуск, перезапуск, перезагрузка юнита | ||
Незамедлительно запустить юнит | # systemctl start юнит | |
Незамедлительно остановить юнит | # systemctl stop юнит | |
Перезапустить юнит | # systemctl restart юнит | |
Перезагрузить юнит с новыми настройками | # systemctl reload юнит | |
Перезагрузить настройки systemd 2 | # systemctl daemon-reload | сканировать систему на наличие новых или изменённых юнитов |
Включение юнита (автозапуск) | ||
Включить юнит, добавив его в автозапуск | # systemctl enable юнит | |
Включить юнит и сразу запустить | # systemctl enable —now юнит | |
Отключить юнит | # systemctl disable юнит | |
Включить юнит заново 3 | # systemctl reenable юнит | т.е. отключить и снова включить |
Маскировка юнита | ||
Замаскировать юнит, сделав невозможным его запуск 4 | # systemctl mask юнит | |
Снять маскировку юнита | # systemctl unmask юнит |
- В руководстве systemd.unit(5) § UNIT FILE LOAD PATH приведён перечень каталогов, в которых могут храниться файлы юнитов.
- Перезагружаются только настройки systemd, но не юнитов. Для юнитов необходимо использовать команду reload.
- Например, если раздел [Install] изменился с момента последнего включения.
- Как вручную, так и по зависимости, что делает маскировку несколько опасной.
Управление питанием
Для управления питанием от имени непривилегированного пользователя необходим polkit. Если вы находитесь в локальном пользовательском сеансе systemd-logind и нет других активных сеансов, приведенные ниже команды сработают, даже если будут выполнены не от root. В противном случае (например, другой пользователь вошел в систему через tty) systemd автоматически запросит у вас пароль суперпользователя.
Действие | Команда |
---|---|
Завершить работу и перезагрузить систему | $ systemctl reboot |
Завершить работу и выключить компьютер | $ systemctl poweroff |
Перевести систему в ждущий режим | $ systemctl suspend |
Перевести систему в спящий режим | $ systemctl hibernate |
Перевести систему в режим гибридного сна (suspend-to-both) | $ systemctl hybrid-sleep |
Написание файлов юнитов
Синтаксис файлов юнитов systemd (см. systemd.unit(5) ) вдохновлён desktop-файлами XDG Desktop Entry Specification, а они, в свою очередь, основаны на синтаксисе файлов .ini Microsoft Windows. Файлы юнитов загружаются из целого ряда мест (команда systemctl show —property=UnitPath выведет полный список), ключевыми из которых являются следующие (в порядке увеличения приоритета):
- /usr/lib/systemd/system/ : юниты, добавленные пакетами при установке;
- /etc/systemd/system/ : юниты, созданные системным администратором.
При создании собственных юнитов за образец можно взять юниты установленных пакетов или примеры из systemd.service(5) § EXAMPLES .
Обработка зависимостей
В systemd зависимости определяются правильным построением файлов юнитов. Простой пример — юниту A требуется, чтобы юнит B был запущен перед запуском самого юнита A. Для этого добавьте строки Requires=B и After=B в раздел [Unit] юнит-файла A. Если зависимость является необязательной, укажите Wants=B и After=B соответственно. Обратите внимание, что Wants= и Requires= не подразумевают After= . Если After= не указать, то юниты будут запущены параллельно.
Зависимости обычно указываются для служб, но не для целей. Так, цель network.target будет «подтянута» ещё на этапе настройки сетевых интерфейсов одной из соответствующих служб, и можно спокойно указывать эту цель как зависимость в пользовательской службе, поскольку network.target будет запущена в любом случае.
Типы служб
Службы различаются по типу запуска, и это следует учитывать при написании юнитов. Тип определяется параметром Type= в разделе [Service] :
- Type=simple (по умолчанию): systemd запустит эту службу незамедлительно. Процесс при этом не должен разветвляться (fork). Если после данной службы должны запускаться другие, то этот тип использовать не стоит (исключение — служба использует сокетную активацию).
- Type=forking : systemd считает службу запущенной после того, как процесс разветвляется с завершением родительского процесса. Используется для запуска классических демонов за исключением тех случаев, когда в таком поведении процесса нет необходимости. Укажите параметр PIDFile= , чтобы systemd мог отслеживать основной процесс.
- Type=oneshot : удобен для сценариев, которые выполняют одно задание и завершаются. Если задать параметр RemainAfterExit=yes , то systemd будет считать процесс активным даже после его завершения.
- Type=notify : идентичен параметру Type=simple , но с уточнением, что демон пошлет systemd сигнал готовности. Реализация уведомления находится в библиотеке libsystemd-daemon.so.
- Type=dbus : служба считается находящейся в состоянии готовности после появления указанного BusName в системной шине DBus.
- Type=idle : systemd отложит выполнение двоичного файла службы до окончания запуска остальных («более срочных») задач. В остальном поведение аналогично Type=simple .
Редактирование файлов юнитов
Не стоит редактировать юнит-файлы пакетов напрямую, так как это приведёт к конфликтам с pacman. Есть два безопасных способа редактирования: создать новый файл, который полностью заменит оригинальный, или создать drop-in файл, который будет применяться поверх оригинального юнита. В обоих случаях после редактирования необходимо перезагрузить юнит, чтобы изменения вступили в силу. Это выполняется либо путем редактирования блока с помощью команды systemctl edit , которая автоматически перезагружает юнит, либо перезагрузкой всех юнитов командой:
Замещение файла юнита
Чтобы полностью заместить файл юнита /usr/lib/systemd/system/юнит , создайте файл с таким же именем /etc/systemd/system/юнит и включите заново юнит для обновления символических ссылок.
Эта команда откроет файл /etc/systemd/system/юнит в текстовом редакторе (если файл ещё не существует, будет скопирован оригинал) и автоматически перезагрузит юнит после завершения редактирования.
Drop-in файлы
Чтобы создать drop-in файл для /usr/lib/systemd/system/юнит , создайте каталог /etc/systemd/system/юнит.d/ и поместите в него файлы .conf с добавленными или изменёнными опциями. systemd будет анализировать эти файлы и применять их поверх оригинального юнита.
Самый простой способ — использовать команду:
Команда откроет /etc/systemd/system/юнит.d/override.conf в текстовом редакторе (файл будет создан, если его ещё нет) и автоматически перезапустит юнит после завершения редактирования.
Откат изменений
Отменить все изменения, сделанные с помощью systemctl edit , можно командой:
Примеры
Например, если вы просто хотите добавить дополнительную зависимость к юниту, можно создать следующий файл:
Другой пример: для замены ExecStart в юните (кроме типа oneshot ) создайте следующий файл:
Обратите внимание, что ExecStart необходимо очистить перед присвоением нового значения [1]. Это относится ко всем параметрам, которые позволяют прописать несколько значений, вроде OnCalendar в таймерах.
Пример настройки автоматического перезапуска службы:
Systemd использует юнит типа цель (target) для группировки юнитов по зависимостям и в качестве стандартизированных точек синхронизации. Они выполняют ту же задачу, что и уровни запуска, но действуют немного по-другому. Каждая цель имеет имя, а не номер, и предназначена для конкретных задач; несколько целей могут быть активны одновременно. Некоторые цели реализованы путём наследования служб из других целей с добавлением собственных. В systemd также имеются цели, имитирующие общие уровни запуска SystemVinit, поэтому вы можете переключаться между целями, используя привычную команду telinit RUNLEVEL .
Получение информации о текущих целях
В systemd для этого предназначена следующая команда (заменяющая runlevel ):
Создание пользовательской цели
Уровни запуска, имеющие определённое значение в sysvinit (0, 1, 3, 5 и 6), один в один соответствуют конкретным целям systemd. К сожалению, не существует хорошего способа сделать то же самое для пользовательских уровней 2 и 4. Их использование предполагает, что вы создаёте новый юнит-цель с названием /etc/systemd/system/цель , который берет за основу один из существующих уровней запуска (взгляните, например, на /usr/lib/systemd/system/graphical.target ), создаёте каталог /etc/systemd/system/цель.wants , а после этого — символические ссылки на те службы из каталога /usr/lib/systemd/system/ , которые вы хотите включить при загрузке.
Соответствие уровней SysV целям systemd
Уровнень запуска SysV | Цель systemd | Примечания |
---|---|---|
0 | runlevel0.target, poweroff.target | Выключение системы |
1, s, single | runlevel1.target, rescue.target | Однопользовательский уровень запуска |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | Уровни запуска, определенные пользователем/специфичные для узла. По умолчанию соответствует уровню запуска 3 |
3 | runlevel3.target, multi-user.target | Многопользовательский режим без графики. Пользователи, как правило, входят в систему при помощи множества консолей или через сеть |
5 | runlevel5.target, graphical.target | Многопользовательский режим с графикой. Обычно эквивалентен запуску всех служб на уровне 3 и графического менеджера входа в систему |
6 | runlevel6.target, reboot.target | Перезагрузка |
emergency | emergency.target | Аварийная оболочка |
Изменение текущей цели
В systemd цели доступны посредством целевых юнитов. Вы можете переключать их такой командой:
Данная команда только изменит текущую цель и не повлияет на следующую загрузку системы. Она соответствует командам Sysvinit вида telinit 3 и telinit 5 .
Изменение цели загрузки по умолчанию
Стандартная цель — default.target , которая по умолчанию ссылается на graphical.target (примерно соответствующего прежнему уровню запуска 5).
Узнать текущую цель можно так:
Для установки новой цели загрузки по умолчанию измените ссылку default.target . С помощью команды systemctl это делается так:
Альтернативный способ — добавить один из следующих параметров ядра в загрузчик:
- systemd.unit=multi-user.target (что примерно соответствует прежнему уровню запуска 3).
- systemd.unit=rescue.target (что примерно соответствует прежнему уровню запуска 1).
Порядок выбора цели по умолчанию
systemd выбирает default.target в следующем порядке :
- Параметр ядра, описанный выше.
- Символическая ссылка /etc/systemd/system/default.target .
- Символическая ссылка /usr/lib/systemd/system/default.target .
Компоненты systemd
Некоторые (не все) составные части systemd:
- systemd-boot — простой менеджер загрузки для UEFI;
- systemd-firstboot — инициализация системных настроек при первой загрузке;
- systemd-homed — переносимые аккаунты пользователей;
- systemd-logind — управление сеансами;
- systemd-networkd — управление сетевыми настройками;
- systemd-nspawn — приложение для контейнеризации процессов;
- systemd-resolved — разрешение сетевых имён;
- systemd-sysusers(8) — создание системных пользователей/групп и добавление пользователей в группы при установке пакетов и загрузке системы;
- systemd-timesyncd — синхронизация системных часов по сети;
- systemd/Журнал — системные логи;
- systemd/Tаймеры — таймеры для управления событиями и службами, альтернатива cron.
systemd.mount — монтирование
systemd полностью отвечает за монтирование разделов и файловых систем, описанных в файле /etc/fstab . systemd-fstab-generator(8) преобразует записи из /etc/fstab в юниты systemd; это выполняется при каждой загрузке системы, а также при перезагрузке конфигурации системного менеджера.
systemd расширяет возможности fstab и предлагает дополнительные опции монтирования. Они могут влиять на зависимости юнита монтирования: например, могут гарантировать, что монтирование выполняется только после подключения к сети или после монтирования другого раздела. Полный список опций монтирования systemd (обычно они имеют префикс x-systemd ) описан в systemd.mount(5) § FSTAB .
Примером этих опций может быть т.н. автомонтирование (здесь имеется в виду не автоматическое монтирование во время загрузки, а монтирование при появлении запроса от устройства). Подробнее смотрите fstab#Автоматическое монтирование с systemd.
Автомонтирование GPT-раздела
На UEFI-системах systemd-gpt-auto-generator(8) автоматически монтирует GPT-разделы в соответствии с Discoverable Partitions Specification, поэтому их можно не указывать в файле fstab.
- Загрузчик должен установить EFI-переменную LoaderDevicePartUUID, по которой можно будет определить системный раздел EFI. Эта возможность поддерживается в systemd-boot, а также в rEFInd (по умолчанию отключена). Это проверяется наличием строки Boot loader sets ESP partition information в выводе команды bootctl .
- Корневой раздел должен быть на одном физическом диске с системным разделом EFI. Автомонтируемые разделы должны быть на одном физическом диске с корневым разделом. Очевидно, монтируемые разделы должны оказаться на одном диске и с ESP.
Для автомонтирования раздела /var его PARTUUID должен совпадать с хэш-суммой SHA256 HMAC, вычисленной на основании UUID типа раздела. В качестве ключа хэша используется machine ID. Необходимый PARTUUID можно получить командой:
systemd-sysvcompat
Пакет systemd-sysvcompat (зависимость пакета base ) содержит традиционный бинарный файл init. В системах под управлением systemd init — символическая ссылка на исполняемый файл systemd .
Кроме того, в этом пакете находятся 4 команды SysVinit — halt(8) , poweroff(8) , reboot(8) и shutdown(8) . Это символические ссылки на systemctl , и их работа обусловлена логикой systemd. Подробнее см. #Управление питанием.
В systemd-системах отказаться от совместимости с System V можно либо задав параметр загрузки init= (см. BBS#233387), либо с помощью собственных аргументов команды systemctl .
systemd-tmpfiles — временные файлы
Утилита systemd-tmpfiles создает, удаляет и очищает непостоянные и временные файлы и каталоги. Она читает конфигурационные файлы из /etc/tmpfiles.d/ и /usr/lib/tmpfiles.d/ , чтобы понять, что необходимо делать. Конфигурационные файлы в первом каталоге имеют приоритет над теми, что расположены во втором.
Конфигурационные файлы обычно предоставляются вместе с файлами служб и имеют названия вида /usr/lib/tmpfiles.d/программа.conf . Например, демон Samba предполагает, что существует каталог /run/samba с корректными правами доступа. Поэтому пакет samba поставляется в следующей конфигурации:
Конфигурационные файлы также могут использоваться для записи значений при старте системы. Например, если вы используете /etc/rc.local для отключения пробуждения от устройств USB при помощи echo USBE > /proc/acpi/wakeup , вместо этого вы можете использовать следующий tmpfile:
Советы и рекомендации
Программы настройки с графическим интерфейсом
- systemadm — Графический поисковик юнитов systemd. Выводит список юнитов, возможна фильтрация по типу.
https://cgit.freedesktop.org/systemd/systemd-ui/ || systemd-ui
- SystemdGenie — Утилита управления systemd на основе инструментов KDE.
https://invent.kde.org/system/systemdgenie || systemdgenie
Запуск сервисов после подключения к сети
Чтобы запустить сервис только после подключения к сети, добавьте такие зависимости в .service файле:
Также должна быть включена служба ожидания сети того приложения, которое управляет сетью; только тогда network-online.target будет соответствовать состоянию сети.
- В NetworkManager служба NetworkManager-wait-online.service включается вместе с NetworkManager.service . Проверить состояние службы можно командой systemctl is-enabled NetworkManager-wait-online.service . Если служба не включена, то включите заново NetworkManager.service ещё раз.
- В случае netctlвключите службу netctl-wait-online.service .
- Для пользователей systemd-networkd юнит systemd-networkd-wait-online.service включается вместе со службой systemd-networkd.service ; проверьте это командой systemctl is-enabled systemd-networkd-wait-online.service . Если нет, то включите заново systemd-networkd.service .
Подробнее можно почитать в systemd wiki: Running services after the network is up.
Если служба отправляет DNS-запросы, она должна запускаться также после nss-lookup.target :
Чтобы цель nss-lookup.target работала как положено, должна быть служба, которая запускает её параметром Wants=nss-lookup.target и размещает себя перед ней ( Before=nss-lookup.target ). Обычно это выполняет локальный DNS-распознаватель.
Чтобы узнать, какие службы зависят от nss-lookup.target , выполните:
Включение установленных юнитов по умолчанию
This article or section needs expansion.
Arch Linux поставляется с файлом /usr/lib/systemd/system-preset/99-default.preset , в котором указан параметр disable * . Это означает, что systemctl preset отключает по умолчанию юниты и пользователь должен сам их включать после установки пакетов.
Если такое поведение не устраивает, создайте символическую ссылку /etc/systemd/system-preset/99-default.preset на /dev/null для переопределения файла конфигурации. Это заставит systemctl preset включать юниты новых пакетов — вне зависимости от типа — кроме указанных в других файлах из каталога настроек systemctl preset. Пользовательских юнитов это не касается. Подробнее смотрите systemd.preset(5) .
Песочница для приложений
Юнит может быть использован в качестве песочницы для изоляции приложений и их процессов в виртуальном окружении. Systemd использует механизм namespaces, белые и чёрные списки capabilities, а также control groups для контейнеризации процессов при помощи настраиваемых окружений — см. systemd.exec(5) .
Добавление к существующему юниту systemd функциональности песочницы обычно происходит методом проб и ошибок вкупе с использованием различных инструментов логирования — strace , stderr и journalctl(1) . В таких случаях имеет смысл предварительно поискать соответствующую документацию от разработчиков. В качестве отправной точки для поиска путей повышения безопасности изучите вывод команды:
Рекомендации по созданию песочницы с помощью systemd:
- Параметр CapabilityBoundingSet определяет список разрешённых capabilities, но с его помощью можно также и запрещать некоторые capabilities для определённого юнита.
- Например, можно задать capability CAP_SYS_ADM , необходимую для создания безопасной песочницы: CapabilityBoundingSet=
Уведомление о неработающих службах
Для уведомления о неудачном запуске службы используется директива OnFailure= в соответствующем файле службы или drop-in файле. Чтобы эта директива возымела эффект для всех служб одновременно, её необходимо добавть в drop-in файл верхнего уровня, см. systemd.unit(5) .
Создайте drop-in верхнего уровня:
Это добавит строку OnFailure=failure-notification@%n в файл каждой службы. Если какой-то_юнит завершится с ошибкой, запустится экземпляр службы failure-notification@какой-то_юнит для создания уведомления (или любой другой задачи, которая была назначена).
Создайте юнит-шаблон failure-notification@ :
После этого создайте сценарий failure-notification.sh , в котором определите, каким именно способом будет создаваться уведомление (mail, gotify, xmpp). Параметр %i будет заменён на название неудачно завершившегося юнита и будет передан сценарию в качестве аргумента.
Чтобы предотвратить регрессию экземпляров failure-notification@.service , создайте пустой файл drop-in настроек с именем, совпадающим с названием drop-in файла верхнего уровня (пустой файл «уровня служб» будет иметь приоритет над файлом «верхнего уровня»):
Решение проблем
Неудачно запущенные службы
Следующая команда найдёт все службы, которые не смогли выполнить запуск:
Чтобы определить причину, по которой служба не запустилась, необходимо изучить записи её логов. Подробнее см. systemd/Журнал#Фильтрация вывода.
Диагностика загрузки системы
В systemd есть несколько опций для диагностики проблем процесса загрузки. В статье об отладке загрузки описано, как получить доступ к сообщениям, выданным процессом загрузки до того, как systemd перехватил управление. Также смотрите документацию по отладке systemd.
Диагностика службы
Если какая-либо служба systemd ведет себя не так, как ожидается, и вы хотите получить дополнительную информацию о том, что происходит, присвойте переменной окружения SYSTEMD_LOG_LEVEL значение debug . Например, чтобы запустить демон systemd-networkd в режиме отладки:
Добавьте drop-in файл для службы:
Или, как вариант, пропишите переменную окружения вручную:
После этого перезапустите systemd-networkd и следите за журналом службы с помощью опции -f / —follow .
Выключение/перезагрузка происходят ужасно долго
Если процесс выключения занимает очень долгое время (или выглядит зависшим), то, вероятно, виновата служба, которая не может завершить свою работу. Systemd ожидает некоторое время, пока каждая служба прекратит работу самостоятельно, и только потом пробует завершить её принудительно. Если вы столкнулись с такой проблемой, обратитесь к Shutdown completes eventually в systemd-вики.
По-видимому, процессы с кратким сроком жизни не оставляют записей в логах
Если команда journalctl -u foounit не даёт вывода для службы с коротким сроком жизни, вместо названия службы используйте её PID. Например, если загрузка службы systemd-modules-load.service завершилась неудачно и команда systemctl status systemd-modules-load показывает, что она была запущена с PID 123, то вы сможете посмотреть вывод процесса в журнале под данным PID, то есть командой journalctl -b _PID=123 . Поля метаданных для журнала вроде _SYSTEMD_UNIT и _COMM собираются асинхронно и полагаются на каталог /proc в случае с действующими процессами. Для решения проблемы требуется внести исправления в ядро, чтобы эти данные можно было собирать через сокет, наподобие SCM_CREDENTIALS . В общем, это баг. Имейте в виду, что быстро падающие службы могут не успеть оставить сообщения в журнале из-за особенностей systemd.
Время загрузки системы увеличивается с течением времени
После использования systemd-analyze некоторые пользователи заметили, что время загрузки системы значительно увеличилось. После использования systemd-analyze blame NetworkManager запускался необычно долго.
Проблема связана с тем, что файл /var/log/journal стал слишком большим. При этом также может уменьшаться скорость работы других команд, например, systemctl status или journalctl . Для решения проблемы можно удалить все файлы из каталога журнала (в идеале — сделав где-нибудь резервные копии, хотя бы временно), а затем ограничить размер журнала.
systemd-tmpfiles-setup.service не запускается во время загрузки
Начиная с версии Systemd 219, /usr/lib/tmpfiles.d/systemd.conf определяет ACL-атрибуты для каталогов в /var/log/journal и, следовательно, требует включённой поддержки ACL для той файловой системы, в которой находится журнал.
Отключение emergency mode на удалённой машине
Вам может понадобиться отключить emergency mode на удалённой машине, например на виртуальных машинах Azure или Google Cloud. Это связано с тем, что в случае ухода системы в emergency mode она отключится от сети и лишит вас возможности подключения к ней.
Источник