Как управлять серверами с Rex — лучшие практики
О чем эта статья
Эта инструкция шаг за шагом показывает, как структурировать код задач Rex, хранить общие модули в репозиториях и применять их к разным проектам (в примере — «website» и «database»). Примеры используют Subversion, Ubuntu и стандартные конфигурации Apache/MySQL/NTP. Кодовые фрагменты и пути к файлам сохранены без изменений.
Важно: примеры команд показаны без sudo — выполняйте их с правами, соответствующими вашей среде.
Ключевые варианты поиска (SEO):
- Управление серверами Rex
- Rex оркестрация и конфигурация
- Rex best practices
- Rex задачи и модули
- Хранение задач Rex в SCM
Введение в Rex
Rex — это инструмент оркестрации и управления конфигурацией. С Rex вы управляете всеми серверами централизованно: описываете задачи (tasks) в Perl и исполняете их по SSH на удалённых хостах. По сути, Rex похож на Make для инфраструктуры: есть центральный Rexfile и набор задач, сгруппированных по модулям и неймспейсам.
Сайт проекта: http://rexify.org/.
Префейс — используемые роли и серверы
В примерах используются следующие серверы:
- Subversion server: svn01
- Database Server: db01
- Web Server: web01
- Workstation: wks01
Я использую Subversion для управления задачами и шаблонами, но вы можете применять любую систему контроля версий, поддерживающую аналогичный механизм внешних ссылок (externals).
Установка репозиториев кода (Subversion)
Выполните на Subversion-сервере установку необходимых пакетов:
svn01# apt-get install libapache2-svn subversion apache2-mpm-preforkОтредактируйте /etc/apache2/mods-enabled/dav_svn.conf, заменив содержимое следующим блоком:
DAV svn
SVNParentPath /var/lib/svn
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
Создайте директории и репозитории:
svn01# mkdir /var/lib/svn
svn01# cd /var/lib/svn
svn01 /var/lib/svn# svnadmin create common
svn01 /var/lib/svn# svnadmin create service
svn01 /var/lib/svn# svnadmin create database
svn01 /var/lib/svn# svnadmin create website
svn01 /var/lib/svn# chown -R www-data: .Настройте аутентификацию Apache и перезапустите сервис:
svn01# htpasswd -c /etc/apache2/dav_svn.passwd your-user-name
svn01# service apache2 restartТеперь сервер Subversion готов. Переходим на рабочую станцию для чекаута репозиториев.
Чекаут репозиториев и написание задач
На рабочей станции выполните:
wks01# svn co http://svn01/svn/common Common
wks01# svn co http://svn01/svn/service Service
wks01# svn co http://svn01/svn/database
wks01# svn co http://svn01/svn/websiteОбщая задача: NTP
Создадим общий модуль для настройки NTP. Перейдите в Common и создайте файл NTP.pm:
wks01# cd Common# Common/NTP.pm
package Common::NTP;
use Rex -base;
task prepare => sub {
install "ntp";
file "/etc/ntp.conf",
source => "files/ntp.conf",
on_change => sub {
service ntp => "restart";
};
};
1;
Этот task «prepare» в неймспейсе NTP устанавливает пакет ntp и загружает конфигурационный файл. При изменении файла сервис перезапускается.
Создайте папку для файлов и добавьте ntp.conf:
bash Common# mkdir filesСодержимое files/ntp.conf (простой дефолтный файл):
# /etc/ntp.conf, managed with rex
driftfile /var/lib/ntp/ntp.drift
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
server 0.ubuntu.pool.ntp.org
server 1.ubuntu.pool.ntp.org
server 2.ubuntu.pool.ntp.org
server 3.ubuntu.pool.ntp.org
# Use Ubuntu's ntp server as a fallback.
server ntp.ubuntu.com
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1
Добавьте и зафиксируйте изменения в репозитории:
wks01 Common# svn add NTP.pm files
wks01 Common# svn ci -m "added NTP task"Сервисные модули: Apache и MySQL
Перейдем в репозиторий Service и создадим модули Apache и MySQL:
wks01 Common# cd ../Service
wks01 Service# touch Apache.pm MySQL.pmСодержимое Apache.pm:
package Service::Apache;
use Rex -base;
task prepare => sub {
install "apache2";
};
task configure => sub {
my $param = shift;
file "/etc/apache2/apache2.conf",
owner => "root",
mode => 644,
content => template("templates/apache2/apache2.conf.tpl", %{ $param });
file "/etc/apache2/conf.d/security",
owner => "root",
mode => 644,
content => template("templates/apache2/conf.d/security.tpl", %{ $param });
};
1;
Создаём каталоги для шаблонов:
wks01 Service# mkdir -p templates/apache2/conf.dШаблон templates/apache2/apache2.conf.tpl:
LockFile /var/run/apache2/accept.lock
PidFile /var/run/apache2.pid
Timeout <%= is_defined($::timeout, "300") %>
KeepAlive <%= is_defined($::keepalive, "On") %>
MaxKeepAliveRequests <%= is_defined($::max_keepalive_requests, "100") %>
KeepAliveTimeout <%= is_defined($::keepalive_timeout, "5") %>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 150
MaxRequestsPerChild 0
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 150
MaxRequestsPerChild 0
User <%= is_defined($::user, "www-data") %>
Group <%= is_defined($::group, "www-data") %>
AccessFileName .htaccess
Order allow,deny
Deny from all
Satisfy all
DefaultType None
HostnameLookups <%= is_defined($::hostname_lookups, "Off") %>
ErrorLog <%= is_defined($::error_log, "/var/log/apache2/error.log") %>
LogLevel <%= is_defined($::log_level, "warn") %>
Include mods-enabled/*.load
Include mods-enabled/*.conf
Include httpd.conf
Include ports.conf
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
Include conf.d/
Include sites-enabled/
Шаблон templates/apache2/conf.d/security.tpl:
ServerTokens <%= is_defined($::server_tokens, "Prod") %>
ServerSignature <%= is_defined($::server_signature, "Off") %>
TraceEnable <%= is_defined($::trace_enable, "Off") %>
Модуль Service::MySQL в MySQL.pm:
package Service::MySQL;
use Rex -base;
task prepare => sub {
install "mysql-server";
};
task configure => sub {
my $param = shift;
file "/etc/mysql/my.cnf",
owner => "root",
mode => 644,
content => template("templates/mysql/my.cnf.tpl", %{ $param });
};
1;
Шаблон templates/mysql/my.cnf.tpl:
[mysqld]
user = <%= is_defined($::user, "mysql") %>
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = <%= is_defined($::port, "3306") %>
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address = <%= $::eth0_ip %>
key_buffer = <%= is_defined($::key_buffer, "16M") %>
max_allowed_packet = <%= is_defined($::max_allowed_packet, "16M") %>
thread_stack = <%= is_defined($::thread_stack, "192K") %>
thread_cache_size = <%= is_defined($::thread_cache_size, "8") %>
myisam-recover = BACKUP
query_cache_limit = <%= is_defined($::query_cache_limit, "1M") %>
query_cache_size = <%= is_defined($::query_cache_size, "16M") %>
expire_logs_days = <%= is_defined($::expire_logs_days, "10") %>
max_binlog_size = <%= is_defined($::max_binlog_size, "100M") %>
[mysqldump]
quick
quote-names
max_allowed_packet = <%= is_defined($::max_allowed_packet, "16M") %>
[mysql]
[isamchk]
key_buffer = <%= is_defined($::key_buffer, "16M") %>
!includedir /etc/mysql/conf.d/
Добавьте и зафиксируйте файлы Service:
wks01 Service# svn add *
wks01 Service# svn ci -m "inital commit of apache and mysql service"Теперь у вас есть общие модули. Дальше вы можете создавать проектные задачи для database и website, используя общие модули.
Методология: как структурировать репозитории и модули
- common — переиспользуемые модули (NTP, users, monitoring). Должны быть стабильными и версионируемыми.
- service — сервисные модули (apache, mysql, redis). Содержат шаблоны и параметры.
- project (website/database) — проекты, которые объявляют зависимости на common и service и содержат специфичные задачи и конфигурации.
- Используйте шаблоны для конфигураций и передавайте параметры через hash/параметры задач.
Совет: разделяйте обязательные (install/configure) и описательные (deploy) задачи. Делайте задачи идемпотентными.
Чек-листы по ролям
Администратор инфраструктуры (Ops):
- Проверить доступность SSH ключей и прав доступа.
- Настроить и протестировать репозитории SCM.
- Подключить common-модули к проектам через externals или submodules.
- Проверить idempotency задач на тестовом хосте.
DBA:
- Протестировать шаблон my.cnf с ожидаемыми параметрами.
- Запустить configure task на стенде и проверить логи.
- Описать требования к бэкапу и рестору в отдельном task.
Разработчик/Deploy инженер:
- Убедиться, что deploy-task не перезаписывает runtime-конфиг без флага.
- Подготовить параметризованный Rexfile для разных окружений.
Критерии приёмки
- Задачи idempotent: повторный запуск не вносит изменений без необходимости.
- Конфигурации генерируются из шаблонов и параметров проекта.
- После выполнения prepare/configure сервисы корректно запускаются и в логах нет ошибок.
- Процедуры отката документированы и протестированы (см. playbook ниже).
Playbook (SOP) — быстрый сценарий деплоя изменений конфигурации
- Локально: написать/обновить модуль и шаблон.
- Закоммитить в ветку/репозиторий и создать merge request.
- На тестовом сервере выполнить rex task и проверить результат.
- При успешном тестировании запустить на стенде pre-prod, провести smoke tests.
- Планировать окно для prod и уведомить заинтересованные стороны.
- Выполнить в prod, параллельно мониторить сервисы и логи.
- При проблемах — выполнить rollback (описано ниже).
Критическая рекомендация: тестируйте откат для любых изменения в конфиге БД или сети.
Откат/инцидентный план (Runbook)
- Если конфигурация привела к недоступности сервиса:
- Применить предыдущий рабочий шаблон (хранится в SCM) через rex task.
- Перезапустить сервис и проверить логи.
- Если сервис не поднимается — восстановить из бэкапа конфигов и данных.
Когда Rex не подходит (контрпримеры)
- Если требуется управление инфраструктурой без SSH (например, agent-based only), Rex может быть неудобен.
- Для огромной инфраструктуры с централизованным inventory и привязкой к облачным API удобнее использовать инструменты, оптимизированные под облако (иногда Terraform + провайдеры конфигурации).
- Если ваша команда преимущественно не знакома с Perl и не готова его поддерживать, рассмотрите YAML/DSL-ориентированные инструменты.
Альтернативные подходы
- Ansible — похож по принципу agentless SSH, но использует YAML и имеет широкую экосистему ролей.
- Puppet/Chef — agent-based и декларативные конфигурации, подходят для больших инфраструктур.
- Salt — гибридный подход с REST и агентами.
Выбор зависит от навыков команды, требований к idempotency, интеграции с CMDB и облачными провайдерами.
Краткий глоссарий (1 строка)
- task: единица работы в Rex, выполняемая на хосте через SSH.
- namespace: пространство имён модуля (например, Common::NTP).
- template: ERB-подобный шаблон для генерации конфигов.
Вывод
Rex — удобный инструмент для команд, которым нужен лёгкий, SSH-ориентированный менеджер задач с возможностью писать модули на Perl. Приведённая структура репозиториев и шаблонов помогает разделять обязанности и переиспользовать код. Тестируйте idempotency, документируйте playbook и имейте план отката.
Важно: адаптируйте примеры под вашу систему управления версиями (Git тоже хорошая альтернатива) и корпоративные процессы.
Полезные ссылки
- Официальный сайт Rex: http://rexify.org/
Похожие материалы
Троян Herodotus: как он действует и как защититься
Включить новое меню «Пуск» в Windows 11
Панель полей PivotTable в Excel — руководство
Включить новый Пуск в Windows 11 — инструкция
Дубликаты Диспетчера задач в Windows 11 — как исправить