Такие платформы, как Kubernetes, Nomad или любая облачная платформа как услуга (Paas), предлагают множество мощных возможностей. Эти оркестраторы рабочих нагрузок оптимизированы для масштабирования инфраструктуры различными способами — от масштабирования рабочих нагрузок до управления секретами и стратегий развертывания.
Но всегда ли операторам приходится платить за максимальную масштабируемость? Иногда стоимость сложности и абстракции перевешивает их преимущества. Вместо этого многие разработчики полагаются на радикально простые архитектуры развертывания для простоты управления. Два виртуальных частных сервера за балансировщиком нагрузки — это значительно более простой в управлении стек по сравнению с разросшимся кластером микросерверов в парке хостов-контейнеров. Это может начать приносить дивиденды, когда будет меньше движущихся частей, требующих отладки при возникновении проблем или обновления, когда придет время их обслуживать.
Основой многих современных дистрибутивов Linux является systemd , который обладает мощным набором функций, которые часто можно сравнить с оркестраторами контейнеров или системами PaaS. В этой статье мы рассмотрим, как вы можете использовать новейшие функции systemd, чтобы получить многие возможности других больших систем без головной боли в управлении и превратить любой обычный Linux- сервер в очень функциональную платформу приложений.
На одном хосте написание файла systemd .service
— идеальный способ запустить управляемый процесс. В большинстве случаев вам даже не нужно менять приложение: systemd поддерживает множество различных видов сервисов и может адаптироваться соответствующим образом.
Например, рассмотрим этот простой .service
, который определяет, как запустить простой веб-сервис:
[Unit] Description=a simple web service [Service] ExecStart=/usr/bin/python3 -m http.server 8080
Помните значения по умолчанию для служб systemd: ExecStart=
должен быть абсолютным путем, процессы не должны переходить в фоновый режим, и вам может потребоваться установить необходимые переменные среды с помощью параметра Environment=
.
При помещении в файл типа /etc/systemd/system/webapp.service
создается служба, которой вы можете управлять с помощью systemctl
:
systemctl start webapp
запустит процесс.systemctl status webapp
отобразит, запущена ли служба, время ее работы и выходные данные stderr
и stdout
, а также идентификатор процесса и другую информацию.systemctl stop webapp
завершит работу службы.
Кроме того, весь вывод, выводимый на потоки stderr
и stdout
, будет агрегирован с помощью Journald и доступен через системный журнал (с помощью journalctl
) или будет предназначен специально с использованием флага --unit
:
journalctl --unit webapp
Поскольку Journald по умолчанию осуществляет ротацию и управление своим хранилищем, сбор журналов через журнал является хорошей стратегией управления хранилищем журналов.
В оставшейся части этой статьи будут рассмотрены варианты улучшения такой услуги.
Оркестраторы контейнеров, такие как Kubernetes, поддерживают возможность безопасного внедрения Secrets : значений, полученных из безопасных хранилищ данных и доступных для выполнения рабочих нагрузок. Конфиденциальные данные, такие как ключи API или пароли, требуют другого обращения, чем переменные среды или файлы конфигурации, чтобы избежать непреднамеренного раскрытия.
Параметр LoadCredential=
systemd поддерживает загрузку конфиденциальных значений из файлов на диске и безопасный доступ к ним запущенным службам. Подобно размещенным платформам, которые удаленно управляют секретами, systemd будет относиться к учетным данным иначе, чем к таким значениям, как переменные среды, чтобы гарантировать их безопасность.
Чтобы внедрить секрет в службу systemd, начните с размещения файла, содержащего значение секрета, в пути в файловой системе. Например, чтобы предоставить ключ API .service
модулю, создайте файл в /etc/credstore/api-key
, чтобы файл сохранялся при перезагрузках, или в /run/credstore/api-key
, чтобы избежать постоянного сохранения файла (файл путь может быть произвольным, но systemd будет рассматривать эти пути credstore
как значения по умолчанию). В любом случае права доступа к файлу должны быть ограничены с помощью такой команды, как chmod 400 /etc/credstore/api-key
.
В разделе [Service]
файла .service
определите параметр LoadCredential=
и передайте ему два значения, разделенные двоеточием ( :
: имя учетных данных и путь к ним. Например, чтобы вызвать наш файл /etc/credstore/api-key
«токен», определите следующую опцию службы systemd:
LoadCredential=token:/etc/credstore/api-key
Когда systemd запускает вашу службу, секрет предоставляется работающей службе по пути в форме ${CREDENTIALS_DIRECTORY}/token
где ${CREDENTIALS_DIRECTORY}
— это переменная среды, заполненная systemd. Код вашего приложения должен читать каждый секрет, определенный таким образом, для использования в библиотеках или коде, требующем безопасных значений, таких как токены API или пароли. Например, в Python вы можете прочитать этот секрет с помощью следующего кода:
from os import environ from pathlib import Path credentials_dir = Path(environ["CREDENTIALS_DIRECTORY"]) with Path(credentials_dir / "token").open() as f: secret = f.read().strip()
Затем вы можете использовать secret
переменную с содержимым вашего секрета для любых библиотек, которым может потребоваться токен или пароль API.
Еще одна возможность оркестраторов, таких как Nomad , — это возможность автоматического перезапуска вышедшей из строя рабочей нагрузки. Перезапуск отказавших приложений, будь то из-за необработанной ошибки приложения или по какой-либо другой причине, является очень полезной возможностью, которая часто является первой линией защиты при проектировании отказоустойчивого приложения.
Параметр Restart=
systemd определяет, будет ли systemd автоматически перезапускать запущенный процесс. У этой опции есть несколько потенциальных значений, но для базовых служб настройка on-failure
хорошо подходит для большинства случаев использования.
Еще одним параметром, который следует учитывать при настройке автоматического перезапуска, является параметр RestartSec=
, который определяет, как долго systemd будет ждать перед повторным запуском службы. Как правило, это значение следует настроить, чтобы избежать перезапуска неисправных служб в узком цикле и потенциально отнимать слишком много времени ЦП, затрачиваемого на перезапуск процессов. Обычно достаточно короткого значения, которое не ждет слишком долго, например 5s
.
Такие параметры, как RestartSec=
, которые принимают периоды продолжительности или значения на основе времени, могут анализировать различные форматы, например 5min 10s
или 1hour
, в зависимости от ваших потребностей. Дополнительную информацию можно найти в руководстве по systemd.time .
Наконец, два других параметра определяют, насколько агрессивно systemd будет пытаться перезапустить вышедшие из строя модули, прежде чем в конечном итоге сдаться. StartLimitIntervalSec=
и StartLimitBurst=
будут контролировать, как часто устройству разрешено запускаться в течение заданного периода времени. Например, следующие настройки:
StartLimitBurst=5 StartLimitIntervalSec=10
Это позволит устройству попытаться запуститься не более 5 раз в течение 10 секунд. Если настроенная служба попытается запуститься в шестой раз в течение 10 секунд, systemd прекратит попытки перезапустить устройство и вместо этого пометит его как failed
.
Объединив все эти настройки, вы можете включить в свой модуль .service
следующие параметры для настройки автоматического перезапуска:
[Unit] StartLimitBurst=5 StartLimitIntervalSec=10 [Service] Restart=on-failure RestartSec=1
Эта конфигурация перезапустит службу в случае сбоя (то есть она неожиданно завершит работу, например, с ненулевым кодом выхода), после ожидания в течение одной секунды и прекратит попытки перезапустить службу, если она попытается запуститься более пяти раз в течение курса. 10 секунд.
Одним из главных преимуществ работы в контейнере является изолированная программная среда безопасности. Благодаря сегментированию процесса приложения от базовой операционной системы любые уязвимости, которые могут присутствовать в службе, гораздо сложнее перерасти в полноценную компрометацию. Среды выполнения, такие как Docker, достигают этого за счет комбинации контрольных групп и других примитивов безопасности.
Вы можете включить несколько параметров systemd, чтобы применить аналогичные ограничения, которые могут помочь защитить базовый хост от непредсказуемого поведения рабочей нагрузки:
ProtectSystem=
может ограничить доступ на запись к конфиденциальным системным путям, таким как /boot
и /usr
. В документации по этому параметру перечислены все доступные параметры, но, вообще говоря, установка full
значения этого параметра является разумным вариантом по умолчанию для защиты этих путей к файловой системе.ProtectHome=
может установить каталоги /home
, /root
и /run/user
в режим «только для чтения» с настройкой read-only
» или, если установлено значение true
, смонтировать их в файловую систему службы как пустые каталоги. Если у вашего приложения нет особой необходимости в доступе к этим каталогам, установка этого параметра в значение true
может безопасно защитить систему от несанкционированного доступа к этим каталогам.PrivateTmp=
поддерживает отдельные /tmp
и /var/tmp
для настроенной службы, чтобы временные файлы для этой службы и других процессов оставались конфиденциальными. Если у процессов нет веской причины обмениваться информацией через временные файлы, эту опцию полезно включить.NoNewPrivileges=
— это еще один безопасный и простой способ усилить безопасность службы, гарантируя, что исполняемый процесс не сможет повысить свои привилегии. Если вы не уверены в возможности использования других вариантов усиления защиты, это, как правило, один из наименее проблемных вариантов включения.
Страница руководства по systemd.exec — это полезный ресурс для изучения различных параметров, применимых к исполняемым рабочим нагрузкам, таким как службы.
Страницы руководства по проекту systemd обширны и полезны для изучения всех возможностей, доступных для запуска ваших собственных приложений. Независимо от того, используете ли вы постоянную службу, например веб-сервер, или периодический модуль .timer
для замены задания cron, документация systemd может предложить полезные рекомендации.