Systemd в Linux: пишем собственные юниты.

Пришло время рассказать о создании собственных юнитов systemd, тем более, что вы сами просили об этом в комментариях. Для примера я напишу сервис, который создает резервную копию директории перед выключением компьютера и подробно прокомментирую каждый этап. Но сначала — немного теории.

Цикл статей о systemd.

  1. Systemd: больше, чем просто демон.
  2. Systemd как средство диагностики неисправностей в Linux.
  3. Systemd в Linux: пишем собственные юниты.
  4. Автоматическое резервное копирование на Яндекс.Диск средствами systemd.
  5. Полезные инструменты, которые предоставляет systemd.

Юниты systemd и их разновидности.

Если вы когда-либо играли в стратегии, то наверняка помните, что юнитами там называли единицу любой разновидности войск. Лучник, инженер, большой шагающий робот — все это юниты.

В контексте systemd юниты — это отдельные объекты, которыми управляет эта система. Как и игровые войска, они имеют свои разновидности, у каждой из которых  есть свое предназначение. Если вы читали предыдущие статьи, то знаете как минимум одну разновидность таких объектов — сервисы. Вот некоторые другие виды юнитов, о которых я, возможно, расскажу в следующих статьях:

  • точки монтирования,
  • таймеры, 
  • таргеты или цели,
  • устройства.

Основными директориями для хранения юнитов в Ubuntu 16.04 являются:

  • /lib/systemd/system — здесь находятся юниты, созданые автоматически при установке пакетов;
  • /etc/systemd/system — пользовательские, вернее, администраторские юниты.

Скриншот выше демонстрирует содержимое директории с файлами юнитов.

Создаем юнит.

Файлы юнитов содержат разделы с набором параметров и их значений, разделенных знаком «=». Слева название параметра, справа значение, все предельно просто. Для начала создадим файл с названием my_backup.service и поместим его в /etc/systemd/system. Впишем в него следующие строки:

Идея этого решения принадлежит человеку с ником mezcalero из IRC чата systemd.

Давайте разберем представленный выше код.

Раздел [Unit] хранит общие сведения о юните. В данном случае он содержит только описание (Description).

Раздел [Service] объединяет сведения, необходимые для выполнения юнитом его задач. Type определяет тип сервиса (не путайте его с разновидностями юнитов), oneshot означает, что сервис должен выполнить разовую задачу и завершиться. ExecStop указывает скрипт, который должен быть выполнен перед остановкой сервиса. Есть еще ExecStart, этот параметр используется чаще и определяет команду, которая должна быть выполнена сразу после запуска сервиса. RemainAfterExit=true предписывает systemd считать процесс активным после его завершения.

Секция [Install] содержит сведения о том, при каких обстоятельствах должен быть запущен сервис. WantedBy=multi-user.target устанавливает запуск при обычной загрузке компьютера.

Но это еще не все. Скрипт, который мы указали в качестве значения ExecStop, на данный момент не существует.

Пишем скрипт.

Приведенный выше код нужно поместить в файл /usr/local/bin/my_backup, а затем сделать его исполняемым:

sudo chmod +x /usr/local/bin/my_backup

Хотя наш скрипт совсем простой, давайте все же разберем его. Первая строка — обязательное начало любого bash скрипта. Вторая получает текущую дату и время в определенном нами формате и помещает ее в переменную current_date. Третья запускает архиватор и сообщает ему, что и куда архивировать. Кстати, не забудьте подставить свои пути вместо русского текста.

Теперь нам осталось лишь добавить наш сервис в автозагрузку и запустить его, чтобы он включился немедленно:

sudo systemctl enable my_backup
sudo systemctl start my_backup

Обратите внимание: в команде выше я использовал my_backup, а не my_backup.service, хотя подразумевал именно это. Дело в том, что если тип юнита не указан, предполагается, что это .serivice. Полный вариант сработал бы точно так же.

Перезагрузите компьютер и проверьте, появился ли архив в указанном месте.

По желанию можно настроить сохранение резервных копий вне локального компьютера, например, в облачном хранилище. В этом случае может потребоваться проверка подключения к сети и доступности самого хранилища. Можно также настроить создание резервных копий не перед выключением, а по расписанию с помощью юнита timer. Возможно, в следующих статьях я продолжу эту тему и покажу, как это можно сделать, а заодно — продемонстрирую работу юнитов других типов.

Далеко не всегда нужно писать собственный скрипт при создании сервиса systemd. Зачастую сервисные файлы пишутся с целью управления уже существующими программами, путь к которым определяется параметрами ExecStart или ExecStop. Наш скрипт тоже использует существующую программу — tar. По большому счету, можно было обойтись и вовсе без него, сразу прописав все необходимые параметры в сервисном файле. Я включил его создание в статью только с целью демонстрации самой возможности. Но пользовательский скрипт все же будет полезен, если вы захотите усложнить задачу: отослать уведомление на электронную почту, удалить самый старый из архивов и т. д.

P.S. 

В скрипте я допустил ошибку, вследствие чего после перезагрузки компьютера резервной копии не обнаружилось. Установить причину было легко:

Вот так с помощью способа, описанного в прошлой статье, я легко нашел и устранил проблему. Вы тоже можете использовать этот способ, если что-то не заработает сразу. При следующей перезагрузке архив уже лежал в отведенном ему месте:

  • https://plus.google.com/110384963591465534552 Владимир Власов

    Спасибо, жду продолжение статей

  • https://plus.google.com/118166993767960656676 Did Mazay

    Отличная статья, хоть и в силу своей специфики может набрать мало просмотров. 😉

  • Алексей

    Вроде даже в книгах читал по модули systemd, но тут очень хорошо так на пальцах всё показано, для дальнейшего понимания очень полезно. Спасибо!