Linux systemctl create service

Systemd: пишем собственные .service и .target

У меня появился Linux на домашнем компьютере, и я поспешил обжиться в новой ОС. Она была установлена с systemd init process. Это было мое первое знакомство с этим новым инструментом. Cвой ноутбук я использую для каждодневной жизни и для программирования. Мне хотелось включать рабочие программы (Apache2 и MySQL) только на время, пока я их использую, чтобы не тратить впустую ресурсы своего компьютера. Дополнительно, для тестирования я написал bash скрипт, который выгружает содержимое одной из MySQL БД c жесткого диска в ОЗУ (в tmpfs) – так тесты выполняются значительно быстрее. По идее, я мог бы начинать свой рабочий день вот так:

systemctl start apache2.service systemctl start mysqld.service /root/scripts/mysqld-tmpfs start 
systemctl stop apache2.service systemctl stop mysqld.service /root/scripts/mysqld-tmpfs stop 

Чего я хотел?

  1. Мне было лень писать 2 команды (запуск apache и запуск mysql), т.к. я знал, что обе программы всегда будут выключаться и включаться синхронно. Хотелось выполнять эту операцию одной командой.
  2. Дело попахивало неприятностями, если компьютер перезагрузится пока моя база данных будет сидеть в tmpfs – все файлы будут потеряны. Конечно, я делал бекапы, но мне опять же было лень восстанавливать их вручную после каждой непредвиденной перезагрузки.

Что я сделал?

В итоге я объединил Apache2 и MySQL в один target. Это позволило запускать оба сервиса одной командой. А свой mysqld-tmpfs скрипт я декларировал в виде сервиса в глазах systemd. Будучи сервисом, я уверен, что systemd выполнит его корректную остановку, если система пойдет на перезагрузку или еще в какую-то нештатную ситуацию, и моя БД без потерь сохранится на жесткий диск.

Читайте также:  Linux сменить язык интерфейса

Что такое 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. В какой-то момент в консоли можно набрать:

systemctl isolate my-another.target 

Все сервисы из my-another.target будут включены, и все включенные сервисы не из my-another.target будут выключены. Это очень похоже на переключение runlevel в openRC. Однако, systemd поддерживает включение более чем 1 target. Вот пример:

# Эксклюзивно включаем my-favorite.target и выключаем все остальные сервисы systemctl isolate my-favorite.target # К уже запущенным сервисам и targets добавляем еще 1 target systemctl start my-another.target 

После выполнения этих команд в системе будет работать объединение сервисов из my-favorite.target и my-another.target.

Как я это сделал?

Description=Mount a MySQL database into tmpfs. # Мой /root/scripts/tmpfs скрипт может работать как при включенном, так и при выключенном mysql сервисе. Но если бы mysql сервис нужен был включенным, к примеру, то я бы добавил эти строки: #Requires=mysqld.service #After=mysqld.service [Service] # Даем знать systemd, что этот сервис представляет из себя лишь 1 процесс. Man page хорошо описывает доступные опции. Type=oneshot # Выполнить эту команду при запуске сервиса. ExecStart=/root/scripts/mysqld-tmpfs start # Выполнить эту команду при остановке сервиса. ExecStop=/root/scripts/mysqld-tmpfs stop # Даем знать systemd, что сервис нужно считать запущенным, даже если основной процесс прекратил свою работу. Как раз то, что мне нужно: мой процесс выполнит монтировку и после этого прекратит свою работу, но должен считаться активным, т.к. монтировка осталась в системе. RemainAfterExit=yes 
[Unit] Description=Working/Programming target Requires=mysqld.service Requires=apache2.service # Сюда я могу дописывать новые сервисы “Requires=another.service”, если они мне понадобятся в повседневной работе. 

Какие были проблемы?

  1. Запустится какой-то другой сервис, который в своей декларации указывает, что он конфликтует с нашим сервисом.
  2. Выполнится systemctl isolate some-another.target или systemctl stop this.service.
  3. Наш сервис может запросить в своей декларации останавливать себя не ленивым образом, а активным, добавив вот такую строку в [Unit] секцию: StopWhenUnneeded=true
Читайте также:  Oracle linux установка пакетов rpm

Декларации “чужих” сервисов можно менять создавая файлы /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

Результат

systemctl start programming.target 
systemctl start mysqld-tmpfs.service 

Когда я хочу демонтировать БД из tmpfs в жесткий диск (хотя на практике я так почти не делаю, а просто оставляю БД в tmpfs на целый день, и при выключении systemd за меня запускает демонтировку из tmpfs в жесткий диск):

systemctl stop mysqld-tmpfs.service 
systemctl stop programming.target 

Cheat sheet

  • Вызывайте 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.
Читайте также:  Veeam proxy server linux

Надеюсь, эта статья кому-то поможет при осваивании systemd. Я попытался сделать ее компактной, и если упустил из внимания какие-то дополнительные вопросы, спрашивайте в комментариях!

Источник

Оцените статью
Adblock
detector