Всем привет! Я Владимир Елагин, технический руководитель проекта Arenadata Cluster Manager (ADCM). В этой статье я хочу рассказать, как с помощью open‑source продукта ADCM можно автоматизировать развертывание и управление практически любым программным обеспечением, даже если вы не используете другие продукты компании Arenadata. Для этого рассмотрим, как написать бандл для установки Bacula — open‑source системы резервного копирования.
Данная статья обзорная, она предназначена для того, чтобы познакомить с базовыми понятиями ADCM. Подробная инструкция по написанию своего бандла приведена в документации ADCM. Если у Вас возникнут вопросы, Вы можете обратиться в сообщество ADCM.

Что такое ADCM?
ADCM представляет собой веб‑приложение на Django в Docker‑контейнере с графическим интерфейсом для управления объектами инфраструктуры. Действия над объектами представляют собой Ansible‑playbook: вы можете запускать их с нужными параметрами на выбранных хостах в любой момент без обращения к командной строке. Для установки и развертывания программного обеспечения ADCM использует бандл — специальный архив, который содержит описание объектов ADCM.
К объектам ADCM относится кластер, который включает в себя набор сервисов, при этом сервис может представлять собой либо единичную сущность, либо логическую сущность, объединяющую в себе несколько компонентов.
Каждый объект ADCM может иметь собственную конфигурацию и набор действий.
Бандл: что это и из чего состоит
Бандл (bundle) — это инструкция для ADCM о том, как развернуть и управлять каким‑либо сервисом или кластером. Это архивный файл в формате .tgz, который вы загружаете в ADCM. После загрузки бандла в интерфейсе ADCM на его основе можно создать один или несколько кластеров.
Внутри бандла обязательно есть два основных компонента:
Конфигурационный файл
config.yaml— это описание структуры вашего кластера. Фактически он работает как шаблон для объектов: вы описываете структуру объектов, действия над ними, а ADCM генерирует соответствующие элементы управления в веб‑интерфейсе.-
Ansible‑playbook — набор действий, приводящих хост к некому конечному состоянию: установка пакетов, копирование файлов, запуск сервисов.
Важно: В рамках этой статьи мы не будем рассматривать написание Ansible playbook — это отдельная большая тема. Мы сосредоточимся на том, как устроен
config.yaml, как его параметры влияют на отображение в интерфейсе и как с его помощью решать задачи управления инфраструктурой.
Что такое прототип и зачем он нужен?
Все объекты, которыми можно управлять из ADCM, описываются в файле config.yaml в виде прототипов.
В продуктовом бандле такими объектами могут быть:
Прототип кластера — описывает кластер в целом.
Прототип сервиса — описывает отдельный сервис внутри кластера.
Прототип компонента — описывает компонент сервиса, который может быть размещен на хосте.
Самый простой прототип кластера выглядит следующим образом:
- name: Test_cluster type: cluster version: 1 adcm_min_version: 2.12.0 contract_version: "2.1" venv: "2.16"
Подробное описание всех свойств в файле config.yaml можно найти в документации ADCM, я остановлюсь только на обязательных:
name— уникальное наименование прототипа.type— тип прототипа (cluster,service,component).version— версия прототипа.adcm_min_version— минимальная версия ADCM, которая необходима для работы бандла. Указывается только для прототипаcluster.contract_version— версия контракта в бандле, в соответствии с которой составлен конфигурационный файлconfig.yaml. Указывается только для прототипаcluster.venv— версия Ansible для выполнения Ansible playbook. Указывается только для прототипаcluster.
Запускаем действия
Прототип описывает объект, но сам по себе не выполняет никаких действий. Чтобы пользователь мог взаимодействовать с объектом, в прототипе описываются actions — действия, которые ADCM может выполнить над ним.
actions: Install: display_name: "Install" scripts: - name: "Install" script_type: ansible script: ansible/install.yaml states: available: any
Install— уникальное наименование действия.display_name— наименование действия, отображаемое в интерфейсе.-
scripts— список скриптов, которые будут выполнены.name— наименование выполняемого скрипта, отображаемое в интерфейсе.script_type— тип скрипта (ansible/internal).script— путь до файла Ansible playbook внутри бандла.
-
states— состояния кластера, в которых доступно данное действие.Полный список свойств для описания действий можно найти в документации ADCM.
После запуска действия ADCM сформирует inventory‑файл на основе текущей топологии кластера. В этом файле будут указаны все объекты с параметрами, к которым можно обращаться из Ansible playbook.
Более подробно о том, как происходит запуск действия, можно почитать здесь.
После загрузки такого бандла в интерфейсе ADCM появится соответствующее действие:

Добавляем кастомные параметры
Очень часто при запуске действия возникает потребность использовать параметры, которые ввел пользователь. Для этого используется специальный блок config:
config: - name: postgresql_user display_name: Username description: "Database username for Bacula catalog connection" type: string default: "bacula" - name: postgresql_password display_name: Password description: "Password for the Bacula database user" type: password - name: postgresql_dbname display_name: Database name description: "Name of the PostgreSQL database for Bacula catalog" type: string default: "bacula"
где:
name— уникальное наименование параметра.display_name— наименование параметра, которое отображается в интерфейсе.description— описание параметра.type— тип параметра. От выбора типа зависит способ отображения в интерфейсе.default— значение по умолчанию.
Указанные параметры конфигурации будут доступны в inventory‑файле и к ним можно обращаться из Ansible playbook указав {{ vars.service.postgresql.config.postgresql_user }}, где:
vars— наименование блока переменных в inventory‑файле.service— тип прототипа, в котором располагается конфигурация.postgresql— наименование прототипа.config— наименование блока конфигурационных параметров.postgresql_user— наименование параметра конфигурации.
Полный список свойств параметров можно найти в документации ADCM.
В интерфейсе ADCM это будет выглядеть следующим образом:

Практика: создаём бандл для Bacula
Bacula — это система резервного копирования, которая состоит из четырёх компонентов: база данных (postgresql), управляющий сервис (director), хранилище (storage) и агенты (client) на клиентских машинах. Поэтому для развертывания кластера Bacula потребуется:
Описать прототип кластера.
Описать прототип каждого сервиса (postgresql, director, storage, client).
Описать конфигурацию сервисов.
Описать действия над кластером.
Описываем прототипа кластера
Для того чтобы в ADCM появился новый кластер, необходимо в файле config.yaml указать его прототип. Для прототипа кластера Bacula составим следующее описание:
- name: Bacula display_name: Bacula type: cluster version: 15.0.3_63 contract_version: "2.1" edition: community adcm_min_version: 2.12.0 venv: "2.16"

После загрузки бандла у нас появится возможность создать кластер.
Описываем прототипа сервиса
Сервис представляет собой набор компонентов, которые определены в бандле продукта и не способны функционировать изолированно.
Сервисный прототип может содержать компоненты. Так как компонент сам считается прототипом, его описание тоже может содержать такие секции, как config и actions.
Чтобы не перегружать статью однотипными YAML — файлами, подробно разберем только сервис client. Остальные сервисы Bacula описываются по тому же принципу.
# Описание прототипа сервиса - name: client display_name: Client type: service required: true description: "Bacula File Daemon service - agent installed on client hosts to provide file access for backup operations" version: 1 # Описание компонентов сервиса components: client: constraint: [1,+] display_name: Client # Описание конфигурационных параметров сервиса config: - name: Paths type: list description: "List of file system paths to include in backup for this client (e.g., /etc, /var/www, /home)" group_customization: true default: - "/home/adcm" # Описание действия над сервисом actions: Reconfig: display_name: "Reconfig" scripts: - name: "Reconfig client" script_type: ansible script: ansible/reconfig_client.yaml states: available: any on_success: installed

Все описанные в config.yaml сервисы можно добавить в кластер.
Здесь стоит обратить внимание на две важные особенности:
Блок
config— в нём определена переменная для хранения путей к директориям, которые необходимо включать в резервную копию.Блок
actions— в нём добавлено действие, которое синхронизирует значение этой переменной с сервисомdirector.

В результате сервис Client успешно добавлен в кластер: в его конфигурации присутствует параметр Paths, а также доступно действие Reconfig.
Описываем действие Install
Для того чтобы запустить установку, необходимо в прототип кластера добавить описание соответствующего действия. Для нашего примера это будет выглядеть следующим образом:
# Описание прототипа кластера - name: Bacula display_name: Bacula type: cluster version: 15.0.3_1 contract_version: "2.1" edition: community adcm_min_version: 2.12.0 venv: "2.16" # Описание действия, которое можно выполнить над кластером actions: Install: display_name: "Install" scripts: - name: Install Postgresql script_type: ansible script: ansible/install_postgresql.yaml - name: Install Client script_type: ansible script: ansible/install_client.yaml - name: Install Storage script_type: ansible script: ansible/install_storage.yaml - name: Install Director script_type: ansible script: ansible/install_director.yaml # Указание, в каких состояниях действие доступно пользователю states: available: - created on_success: installed
В интерфейсе данное действие будет выглядеть следующим образом:

После запуска установки можно перейти на страницу Jobs и увидеть, что были выполнены именно те скрипты, которые мы указали в config.yaml:

Управляем кластером Bacula
После установки Bacula необходимо предоставить пользователю инструменты для управления компонентами системы. Для этого следует описать соответствующие действия (actions).
Например, для получения списка активных заданий резервного копирования создадим action в файле config.yaml
List_jobs: display_name: "List Jobs" description: "Display all job categories: running, scheduled, terminated, disabled, and full history." states: available: - installed scripts: - name: List Jobs script_type: ansible script: ansible/list_jobs.yaml config: - name: job_name display_name: "Job Name" description: "Filter results by job name. Leave empty to show all jobs." type: string required: false pattern: "^[a-zA-Z0-9_-]+$"
После добавления action в config.yaml он отобразится в интерфейсе ADCM и станет доступен для выполнения.

Обратите внимание, данный список действий стал доступен только после установки кластера, за это отвечает свойство
statesв описании действия
После выполнения действия в логах можно увидеть список заданий, которые присутствуют в кластере Bacula.

Из логов видно, что на расписании стоит одно задание backup_client_1_bacula-client-1. Реализуем Action, для его отключения:
Disable_Job: display_name: "Disable Job" states: available: - installed on_success: installed scripts: - name: Disable Job script_type: ansible script: ansible/disable_job.yaml config: - name: job_name display_name: "Job Name" description: "Name of the backup job to disable" type: string required: true pattern: "^[a-zA-Z0-9_-]+$"
В интерфейсе ADCM появится форма с полем для ввода имени задания:

Успешное выполнение задания отобразится в логах:

Заключение
Мы создали собственный бандл, описали кластер Bacula, добавили сервисы с конфигурационными параметрами и связали действия ADCM с Ansible playbook. Это крошечная часть возможностей по кастомизации бандла. Полную информацию вы можете найти в документации ADCM.
Также у нас есть сообщество разработчиков бандлов! Полный бандл Bacula можно найти в репозитории нашего сообщества на GitHub.