В операционной системе Linux, так же как и в Windows, кроме обычных программ, с которыми может взаимодействовать пользователь есть еще один вид программ. Это работающие в фоне службы. Важность служб тяжело переоценить, они следят за состоянием системы, обеспечивают автоматическое подключение внешних устройств и сети, позволяют процессам взаимодействовать с оборудованием (dbus), а также в виде служб реализованы различные веб-серверы и серверы баз данных.
Поскольку службы выполняются в фоновом режиме, вы не можете взаимодействовать с ними привычными способами. Вы узнаете, как посмотреть запущенные службы Linux, а также останавливать и запускать их самому.
Чтобы всем этим управлять нужна основная служба - система инициализации, которая будет запускать службы Linux в нужный момент, следить чтобы они нормально работали, записывать сообщения логов, и самое главное предоставлять пользователям интерфейс для управления службами. Саму систему инициализации запускает ядро Linux.
Раньше, для управления службами использовались скрипты. Тогда каждая служба запускалась в фоновом режиме одна за другой, без возможности параллельного запуска. Скрипт инициализации получал PID процесса для каждой службы, сохранял его и потом с помощью него можно было проверить работает ли служба и остановить службу Linux если это нужно. Все это можно сделать и вручную.
Но потом на смену этому методу пришла новая модель и система инициализации Systemd. Эта система позволяет запускать службы параллельно, поэтому появилась необходимость настраивать зависимости между службами. Таким образом, теперь порядок запуска служб определяет сложное дерево зависимостей. После запуска Systemd собирает весь вывод службы в лог, и следит за ее работой, если служба аварийно завершилась, то автоматически ее перезапускает при необходимости.
Служба в Systemd описывается файлом юнита, в нем описано каким образом эту службу надо запускать, а также как с ней себя вести. Существуют такие типы юнитов:
В этой статье мы рассмотрим только обычные службы, то есть *.service, и совсем немного *.target, но мы перечислили здесь все остальные типы юнитов, чтобы вы смогли взглянуть на картину немного шире.
Ещё все службы Systemd можно поделить на две группы:
Кроме того, у Systemd есть задачи (Jobs), они выполняются и видны только когда к какой нибудь службе применяется действие, например, запуск или остановка.
Основы рассмотрели, теперь будет настройка служб LInux. Давайте познакомимся с утилитой для управления службами.
В Systemd есть специальный инструмент для управления службами в Linux - команда systemctl. Эта утилита позволяет делать очень много вещей, начиная от перезапуска службы linux и проверки ее состояния, до анализа эффективности загрузки службы. Синтаксис у этой утилиты такой:
$ systemctl опции команда служба служба...
Опции настраивают поведение программы, подробность вывода, команда - указывает что нужно сделать со службой, а служба, это та самая служба, которой мы собираемся управлять. В некоторых случаях утилита может использоваться без указания команды и службы.
Опции очень сильно зависят от команд, поэтому рассмотрим их позже, а пока пройдемся по командам:
Команда systemctl поддерживает и другие команды, но в этой статье перечислены только самые популярные.
А теперь основные опции:
Большинство действий выполняются именно командами, а опции только помогают сделать вывод более удобным.
Теперь, когда вы уже знаете все основы, команды и параметры можно переходить к делу. Со всеми остальными тонкостями разберемся по пути.
Сначала давайте посмотрим все загруженные в память службы Linux. Для того чтобы отобразить только службы можно использовать фильтр по типу с помощью опции type:
systemctl list-units --type service
Обратите внимание, что команда не просто выводит текст, она передает этот текст утилите less. Здесь доступна прокрутка вверх и вниз, а также вправо и влево с помощью клавиш стрелок. Для того чтобы выйти обратно в терминал нажмите клавишу q.
Команда отобразила все службы, которые известны systemd, они сейчас запущены или были запущены. Systemd не пересматривает все файлы юнитов при выполнении этой команды. В выводе утилиты есть несколько колонок:
Дальше больше. Вы можете отфильтровать список служб systemctl по состоянию с помощью опции state. Например, только выполняющиеся:
systemctl list-units --type service --state running
Или те, которые завершились с ошибкой:
systemctl list-units --type service --state failed
В предыдущем пункте было показано как посмотреть список служб, которые уже загружены в память systemd. Но для того чтобы посмотреть все службы необходимо обратиться к файлам юнитов, потому что далеко не все службы загружаются в память.
Для этого понадобится команда list-unit-files. Например, для вывода вообще всех юнитов воспользуйтесь такой командой:
systemctl list-unit-files
Здесь тоже есть несколько колонок с информацией, в первой колонке выводится добавлен ли юнит в автозагрузку, а во второй должен ли он быть добавлен в автозагрузку по умолчанию. Теперь отфильтруем только службы Linux:
systemctl list-unit-files --type service
Здесь вы тоже можете использовать фильтры по состоянию, но значения будут уже другие. Теперь вы знаете как посмотреть запущенные службы Linux.
Если вы хотите найти определенную службу, но не знаете её полное имя, то можете использовать фильтр по паттерну. Например, так можно вывести все службы, которые начинаются со слова mysql:
systemctl list-unit-files 'mysql*'
Для того чтобы запустить службу используется команда start. Ей необходимо передать имя службы в качестве параметра:
sudo systemctl start имя_службы.service
Например, для запуска Nginx выполните:
sudo systemctl start nginx.service
Причем расширение service можно опустить, оно и так подставляется по умолчанию. Если запуск прошел хорошо, программа ничего не выведет.
Остановить службу linux можно командой:
sudo systemctl stop <имя_службы.service>
Например, для остановки Nginx можно использовать такую команду:
sudo systemctl stop nginx
Кроме того, вы можете остановить несколько сервисов одной командой используя фильтрацию по паттерну. Например, для остановки всех сервисов, имена которых начинаются с php выполните:
sudo systemctl stop 'php*.service'
Но это будет работать только для запущенных служб. Запускать службы таким образом нельзя. Сопоставление по паттерну работает только для загруженных в память юнитов, а поэтому невозможно быть уверенным что список для запуска будет полным.
Есть два способа перезагрузки служб. Это полная перезагрузка с помощью команды restart, которая включает завершение программы и её запуск, а также так называемая мягкая перезагрузка, когда systemd просит программу перечитать конфигурацию с диска. Такая перезагрузка выполняется с помощью команды reload, однако далеко не все сервисы её поддерживают.
Для полной перезагрузки Nginx выполните такую команду:
sudo systemctl restart nginx
Для того чтобы попросить программу перечитать свою конфигурацию используйте команду reload:
sudo systemctl reload nginx
Если служба не поддерживает этого, вы получите ошибку. Для того чтобы избежать этого и перезапустить службу полностью если мягкая перезагрузка не поддерживается используйте команду reload-or-restart. Например:
sudo systemctl reload-or-restart nginx
Посмотреть состояние службы позволяет команда status:
sudo systemctl status имя_службы
Например, для Nginx:
sudo systemctl status nginx
Здесь вы можете видеть текущее состояние процесса в поле Active. Возможные значения: active, inactive, failed, etc. Ещё тут выводится статистика по использованию памяти, количеству запущенных процессов и PID основного процесса. А также 10 последних строчек вывода программы, которые очень помогут решить проблему с запуском если она возникнет. Если этих данных вам не достаточно, то вы можете указать количество строк для вывода используя опцию --lines. Например:
sudo systemctl status --lines=50 avahi-daemon
Если на экран не помещается вся строка логов, вы можете использовать стрелки вправо и влево для прокрутки. В некоторых случаях строка может обрезаться по размеру окна терминала. Для того чтобы этого избежать используйте опцию -l:
sudo systemctl status -l nginx
Для того чтобы добавить службу в автозагрузку используйте команду enable. Например, команда добавления Nginx в автозагрузку будет выглядеть вот так:
sudo systemctl enable nginx
А для удаления из автозагрузки используйте команду disable. Например:
sudo systemctl disable nginx
Более подробно об автозагрузке в Systemd вы можете прочитать в статье Автозагрузка сервисов Linux.
Иногда возникает необходимость отредактировать файл службы. Например, для того чтобы добавить дополнительные переменные окружения или настроить автоматический перезапуск. Но редактировать сам файл сервиса в папке /usr/lib или /lib не желательно, поскольку при следующем обновлении пакета он будет перезаписан.
Вы можете скопировать файл юнита в папку /etc/systemd/system/ и редактировать его там. Специально для таких случаев была разработана команда edit. Если её использовать с опцией --full она создаст файл в папке /etc/systemd/* в котором вы можете изменять всё что вам нужно. Например, вы можете выполнить следующую команду для того чтобы отредактировать конфигурационный файл Nginx:
sudo systemctl edit --full nginx
Внесите нужные изменения и сохраните файл. Например, можно добавить переменную окружения SITE со значением losst:
Environment="SITE=losst"
Если же вы выполните команду edit без опции --full, то будет создана папка /etc/systemd/system/nginx.service.d, в которой появится файл override.conf. Здесь нужно разместить только параметры, которые вы хотите добавить или значения которых нужно переопределить Например, для добавления той же переменной окружения нужно добавить такую строку:
sudo systemctl edit nginx
Envirnoment="SITE=losst"
После внесения изменений необходимо обновить конфигурацию Systemd с диска:
sudo systemctl daemon-reload
Затем вы можете перезапустить сервис и убедится, что настройки применились.
Удалить службу можно удалив пакет, вместе с которым она поставляется. Однако если это стандартная служба, то это сделать не получится. Существует способ отключать юниты, если вы не хотите чтобы кто-то их использовал. Это маскировка. Для этого используйте команду mask:
sudo systemctl mask имя_сервиса
Например, для Nginx:
sudo systemctl mask nginx
Эта команда создает в папке /etc/systemd/system символическую ссылку на /dev/null с именем файла службы, после чего служба считается отключённой. Обратите внимание, что если вы редактировали файл юнита и в папке /etc/systemd/system уже существует его файл, то вы можете получить ошибку Failed to mask unit: File /etc/systemd/system/*.service already exists. В таком случае все ваши изменения нужно удалить командой revert. При выполнении этой команды ваши изменения будут удалены. Например:
sudo systemctl revert nginx
Информацию о том, что служба замаскирована можно увидеть в выводе команды status:
sudo systemctl status nginx
Для того чтобы вернуть всё как было выполните команду unmask:
sudo systemctl unmask nginx
Кроме системных служб Systemd поддерживает службы, работающие от имени обычного пользователя. Они не требуют прав суперпользователя, запускаются при авторизации пользователя в системе и завершаются после завершения его последней сессии. Юнит файлы для этих служб выглядят так же как и для обычных только расположены они в домашней папке пользователя $USER/.config/systemd/user или в системной папке /usr/lib/systemd/user/.
Все команды для управления такими службами аналогичны обычным, только нужно добавить опцию --user. Например, для того чтобы получить список всех служб которые могут работать от имени пользователя выполните:
systemctl --user list-unit-files --type service
Для просмотра состояния службы используется команда status. Например для службы dbus команда будет выглядеть так:
systemctl --user status dbus.service
Задание 1:
Написать свою службу которая автоматически будет отправлять уведомления о статусе виртульной машины при её включении. Как код отправляющий все в ТГ можно использовать этот:
#!/bin/bash
TOKEN="YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID="YOUR_CHAT_ID"
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
MEMORY_USAGE=$(free | grep Mem | awk '{print $3/$2 * 100.0}')
DISK_USAGE=$(df -h | grep '/$' | awk '{print $5}')
MESSAGE="Machine Status:\nCPU Usage: ${CPU_USAGE}%\nMemory Usage: ${MEMORY_USAGE}%\nDisk Usage: ${DISK_USAGE}"
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" -d "chat_id=$CHAT_ID&text=$MESSAGE&parse_mode=Markdown"
Достаточно факта отправки сообщения в ТГ через бота при включении виртуальной машины.