ссылки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
https://systemd.io/ https://www.freedesktop.org/wiki/Software/systemd/ https://www.freedesktop.org/software/systemd/man/systemd.service.html https://manpages.ubuntu.com/manpages/xenial/en/man5/systemd.service.5.html https://habr.com/ru/post/535872/ https://habr.com/ru/post/535930/ https://habr.com/ru/post/536040/ https://t.me/ru_systemd https://linux-notes.org/pishem-systemd-unit-fajl/ https://wiki.archlinux.org/title/Systemd_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9) https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units-ru https://habr.com/ru/company/southbridge/blog/255845/ https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6 https://habr.com/ru/post/540096/ - rastic |
daemon / service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
Помощь: man systemd.unit man systemd.service man systemd.exec man systemctl man sysusers.d man systemd-sysusers /usr/lib/systemd/system/ – юниты из установленных пакетов RPM — всякие nginx, apache, mysql и прочее /run/systemd/system/ — юниты, созданные в рантайме — тоже, наверное, нужная штука /etc/systemd/system/ — юниты, созданные системным администратором — а вот сюда мы и положим свой юнит. Юнит представляет из себя текстовый файл с форматом, похожим на файлы .ini Microsoft Windows. /etc/systemd/system/NAME-UNIT.service - расположение юнита NAME-UNIT /etc/sysusers.d/NAME-UNIT.conf - расположение конфига NAME-UNIT (не обязательный файл) Пример простого юнита MyUnit: vim /etc/systemd/system/myunit.service ----------------------------------------- [Unit] #описание юнита Description=MyUnit #Запускать юнит после какого-либо сервиса или группы сервисов After=syslog.target After=network.target After=nginx.service After=mysql.service #Для запуска сервиса необходим запущенный сервис mysql Requires=mysql.service #Для запуска сервиса желателен запущенный сервис redis Wants=redis.service [Service] #Тип сервиса (Type=simple, Type=forking) Type=forking #Определить PIDFile=, чтобы systemd могла отслеживать основной процесс (не обязательный) PIDFile=/work/www/myunit/shared/tmp/pids/service.pid #Рабочий каталог, он делается текущим перед запуском стартап команд (не обязательный) WorkingDirectory=/work/www/myunit/current #Пользователь и группа, под которым надо стартовать сервис: User=myunit Group=myunit #Переменные окружения (не обязательный) Environment=RACK_ENV=production #логи SyslogIdentifier=MyUnit SyslogFacility=daemon #Запрет на убийство сервиса вследствие нехватки памяти и срабатывания механизма OOM OOMScoreAdjust=-1000 #Команды на старт/стоп и перезапуск сервиса 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 #Таймаут в секундах, сколько ждать system отработки старт/стоп команд TimeoutSec=300 #Попросим systemd автоматически рестартовать наш сервис, если он вдруг перестанет работать Restart=always RestartSec=5 Restart=on-failure [Install] #В секции [Install] опишем, в каком уровне запуска должен стартовать сервис WantedBy=multi-user.target ----------------------------------------- Директива Type= может быть одной из следующих: Type=simple Основной процесс службы указан в стартовой строке. Это значение по умолчанию, если директивы Type= и Busname= не установлены, но установлен ExecStart=. Любое сообщение должно обрабатываться вне устройства через второй блок соответствующего типа (например, через блок .socket, если эта служба должна обмениваться данными с помощью сокетов). Type=forking Этот тип службы используется, когда служба форкает дочерние процессы при мгновенном покидании родительского процесса. Это сообщает systemd, что процесс все еще работает, даже несмотря на то, что родитель завершил сеанс. Хорошо подходит, например для запуска php-fpm, nginx, tomcat. Type=oneshot Этот тип указывает, что процесс будет недолговечным и система должна ждать завершения процесса, прежде чем продолжить работу с другими устройствами. Значение по умолчанию для Type= и ExecStart= не установлены. Он используется для одноразовых задач. Type=dbus Это означает, что устройство будет использовать имя от D-Bus шины. Когда это произойдет, systemd продолжит обработку следующего блока. Type=notify Это указывает на то, что служба отправит уведомление, когда закончит запуск. Процесс systemd будет ждать, пока это произойдет, прежде чем переходить к другим устройствам. Type=idle Это означает, что служба не будет запущена до тех пор, пока не будут отправлены все задания. multi-user.target или runlevel3.target соответствует нашему привычному runlevel=3"Многопользовательский режим без графики". Пользователи, как правило, входят в систему при помощи множества консолей или через сеть После изменения\добавления файла юнита необходимо: systemctl daemon-reload - перечитать демоны systemctl enable NAME-UNIT - добавить в автозагрузку systemctl start NAME-UNIT - запустить systemctl -l status NAME-UNIT - проверить systemctl --state=failed - показать сбойные юниты |
Приме пример демона из документации:
1 2 3 4 5 6 7 8 9 |
[Unit] Description=Simple notifying service [Service] Type=notify ExecStart=/usr/sbin/simple-notifying-service [Install] WantedBy=multi-user.target |
timer \ замена cron
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
Помощь: man systemd.timer man systemd.time man systemd-system.conf man systemd-analyze man tzselect Пример из поставки systemd: cat /usr/lib/systemd/system/man-db.timer ---------------------------------------- [Unit] Description=Daily man-db regeneration Documentation=man:mandb(8) [Timer] OnCalendar=daily AccuracySec=12h Persistent=true [Install] WantedBy=timers.target ---------------------------------------- Простой, коротенький таймер. Почему не указано что мы запускаем? Всё нормально! По умолчанию, если в секции [Timer] отсутствует параметр Unit=, с указанием запускаемого юнита, systemd будет искать одноимённый *.service юнит. Проверяем что делает: cat /usr/lib/systemd/system/man-db.service ------------------------------------------ [Unit] Description=Daily man-db regeneration Documentation=man:mandb(8) ConditionACPower=true [Service] Type=oneshot # Recover from deletion, per FHS. ExecStart=+/usr/bin/install -d -o root -g root -m 0755 /var/cache/man # Expunge old catman pages which have not been read in a week. ExecStart=/usr/bin/find /var/cache/man -type f -name *.gz -atime +6 -delete # Regenerate man database. ExecStart=/usr/bin/mandb --quiet User=root Nice=19 IOSchedulingClass=idle IOSchedulingPriority=7 ------------------------------------------ Сервис стартует начиная с 00:00 (OnCalendar=daily) , с точностью 12 часов (AccuracySec=12h), то-есть он может сработать в любой момент между полуночью и полднем, в зависимости от загрузки системы systemctl status man-db.timer - проверяем состояне Событийные таймеры Таймеры привязанные к каким-либо событиям в системе. OnBootSec= Таймер сработает через указанное время после старта системы. OnStartupSec= Для системных таймеров действие аналогично предыдущему, для пользовательских таймеров, это время после первого логина пользователя в систему. OnActiveSec= Через какое время, после активации таймера системным менеджером, запускать юнит RandomizedDelaySec= Этакий рандомный джиттер. Перед срабатыванием добавляется случайный таймаут от нуля, до заданного значения. По умолчанию -- отключено. FixedRandomDelay= Связанный с предыдущим параметром булевый параметр. Если включено, то при первом срабатывании таймера, джиттер запомнится (и для этого таймера станет постоянным), но запомнится хитро. Сама генерация рандома будет основана на имени пользователя, имени таймера, а самое главное MachineID, о котором будет рассказано в одной из следующих статей и который гарантированно разный, на разных хостах. Для чего это нужно? Например имеем сеть с кучей хостов, которые, например в начале рабочего дня, запускают таймеры, юниты которых ломятся на сервер, устраивая шторм запросов. Что-бы таймеры гарантированно срабатывали в разное время и следует использовать этот параметр. OnClockChange=, OnTimezoneChange= Булевые параметры, определяющие будет ли таймер реагировать на перевод системных часов или смену временной зоны. По умолчанию, оба параметра, false. Persistent= Записывать-ли на диск состояние таймера сразу после запуска юнита. Актуально для параметра OnCalendar=. По умолчанию — false. WakeSystem= Действует на монотонные таймеры. По умолчанию отключён. Логика следующая. При отключённом параметре все монотонные таймеры запоминают своё состояние, перед уходом системы в спящий режим и встают на паузу. После выхода системы из спящего режима, отсчёт продолжается с того момента с которого система "ушла в спячку". Если-же параметр поставить в true, то таймеры продолжают работать и в спящем режиме (должно поддерживаться и железом) и по наступлении события выводят систему из спячки и запускают юнит. RemainAfterElapse= По умолчанию true. Смысл этого параметра примерно следующий, после срабатывания таймера он остаётся загруженным, но если поставить false, то после срабатывания таймер выгружается и перестаёт отслеживать время. Хорошо для одноразовых юнитов (Transient Units) о которых мы поговорим в одной из следующих статей. Или для таймеров которые должны сработать один раз, как это делают задания старой, доброй at. |
Примеры таймеров
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Самый простой таймер: --------------------- #задача запуска сервиса раз в полтора часа, начиная с часа ночи [Unit] Description=Test timer [Timer] OnCalendar=01:00 OnUnitActiveSec=1.5h --------------------- Например мы хотим что-б наш юнит запускался каждую пятницу 13-е… OnCalendar=Fri *-*-13 12:00:00 Полный формат календарной формы выглядит так: Mon 2025-12-01 12:00:00.000000 Europe/Moscow Камчатка уже отпраздновала Новый год: OnCalendar=yearly Asia/Kamchatka Нормализованная форма будет выглядеть так (эти строчки указывают на одно и то-же время): OnCalendar=*-01-01 00:00:00 Asia/Kamchatka Проверять таймстампы на валидность можно при помощи утилиты systemd-analyze systemd-analyze calendar 'Mon *-12-01/1' systemd-analyze timespan 1.5h systemd-analyze timestamp 01:00:30.9999 Посмотреть все таймеры в системе: systemctl list-timers |
triger
1 2 3 4 5 6 7 8 9 10 |
Помощь: man systemd.path man 7 inotify man inotifywait man inotifywatch man systemd.automount man systemd.mount man systemd-mount man 5 fstab man systemd.time |
Пример запуск скрипта с таймером:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
vim /etc/systemd/system/sctipt-test.service ------------------------------------------- [Unit] Description=sctipt-test [Service] Type=oneshot ExecStart=/usr/bin/sctipt-test.sh Restart=on-failure [Install] WantedBy=multi-user.target ------------------------------------------- vim /etc/systemd/system/sctipt-test.timer ----------------------------------------- # Каждые 30 сек запуск скрипта [Unit] Description=sctipt-test [Timer] OnUnitActiveSec=30 [Install] WantedBy=timers.target ----------------------------------------- systemctl daemon-reload systemctl enable sctipt-test.service systemctl enable sctipt-test.timer systemctl status sctipt-test.service systemctl status sctipt-test.timer systemctl list-timers systemctl list-timers sctipt-test.timer |