Привет, Хабр! В этой статье хочу рассказать об основных модулях нашего приложения для развертывания больших инфраструктур и киберполигонов на основе Ansible. Эти модули мы называем A-services (сокращенно от Ansible services). Они содержат все сценарии подготовки, развертывания и настройки ИТ-инфраструктуры.

Общая архитектура приложения на основе Ansible, описана в предыдущей статье. Здесь хочу поделиться особенностями архитектуры модулей А-services.

Предыдущие статьи из серии:

  1. Конфигуратор. Как подготовиться к развертыванию инфраструктур компаний по одной кнопке (Ansible)

  2. Конфигуратор. Связываем хосты в единую инфраструктуру, используя функциональность Ansible inventory

  3. Архитектура приложения. Разбиваем приложение Ansible на модули (Inventory, Deployer)

Техническое задание

  • Сценарии могут быть любого объема и качества и должны включать все — от развертывания виртуальных машин до тонкой настройки.

  • Скорость разработки должна быть максимальной (простой и переиспользуемый код, параллельная разработка).

  • Необходима быстрая адаптация под любые платформы (OpenStack, Proxmox, VMware).

  • Нужно обеспечить возможность установки любых версий ОС и приложений.

  • Запуск развертывания должен быть быстрым и контролируемым с возможностью управлять параллельной установкой. 

Архитектурное решение

Как отмечалось ранее, A-service — это отдельный контейнер. Он содержит все необходимое для запуска:

  • внешние ссылки для скачивания дистрибутивов;

  • свою версия Ansible и свои библиотеки;

  • свою версию ОС и инструментария;

  • сценарий развертывания и настройки.

Команды для запуска контейнера A-service, команды управления и контракты для работы с Inventory – стандартизированы. Модули Deployer и Inventory могут работать с любыми модулями A-services.

Взаимодействие с внешними ресурсами

Для понимания «внешней» архитектуры опишу сценарий работы A-service:

  • Скачивание A-service с Git, модулем Deployer.

  • Запуск контейнера модулем Deployer с передачей ссылки на Inventory.

  • Подключение Inventory. По полученной от Deployer ссылке подключается Inventory, который сконфигурирован заранее. В нем — все нужные переменные и ссылки на внешние ресурсы.

  • Развертывание. Скачиваем дистрибутив для установки из интернета или с локального зеркала. Ссылки на локальные зеркала могут быть заданы в Inventory. Далее — установка. После установки остаются артефакты: ключи, учетные данные, файлы подключения и т. п. Они сохраняются в артефактории и в Inventory для оперативного использования. 

A-service могут развертывать виртуальную машину, настраивать ее и делать интеграцию с другими виртуальными машинами. Важно, что может быть несколько A-service на одни и те же виртуальные машины — это добавляет гибкости в разработке и использовании.

Внутренняя архитектура

Так как модулей А-services большое количество, а постоянно писать один и тот же код, а тем более это все исправлять — очень трудозатратно, было принято решение использовать своего рода библиотеку. Эта библиотека представляет собой первичный контейнер (default A-service), который содержит общие сценарии для A-services.

Почему не использовали механизм коллекций и ролей? Было три основных ограничения, которые смогли обойти:

  • Нам бы все равно пришлось делать отдельные A-service с плейбуками. А это добавляет еще один уровень в архитектуру и усложняет ее.

  • Каждый A-service должен был хранить свои скрипты сборки(Dockerfile) и запуска(start.sh). Для улучшения и исправления который нужно было вносить изменения во все модули A-services.

  • Можно просто запутаться: коллекции и роли используются в A-service как основные прикладные сценарии.

Состав default A-service:

  • Конфигурация сборки контейнера. Все скрипты сборки и запуска контейнера правятся в одном месте.

  • Все зависимости и приложения ОС.

  • Ansible библиотеки и коллекции определенных версий.

  • Общие сценарии развертывания, которые можно расширять через A-service:

    • Установка ОС (Windows, Ubuntu, Debian, «РЕД ОС» и т. п.).

    • Установка виртуальных маршрутизаторов (CheckPoint, MikroTik, PT NGFW).

    • Работа с пользователями в стандартных приложениях (Active Directory, Microsoft Exchange, RoundCube, OpenLDAP и т. п.).

    • Работа с внешними сервисами (HashiCorp Vault, Passwork, ownCloud и другими).

    • Валидация входных данных из Inventory.

Особенности:

  • Default A-service версионируется так же, как и все остальное.

  • Default A-service с заранее скачанными основными зависимостями Ansible запускается гораздо быстрее.

  • Default A-service может быть несколько, можно делать их для разных платформ. 

Дерево проекта выглядит так:

  • Dockerfile — сценарий сборки контейнера с зависимостями

  • requirements.txt — зависимости Python

  • ./scripts/* — скрипты запуска A-service. Нужно, чтобы они были унифицированы для всех A-services, наследуемых этим default A-service.

  • ./service/* — сценарии установки. В папках находятся playbook.yml и файл зависимостей для конкретного сценария.

  • ./service/*_collection_requirements.yml — требуемые Ansible-коллекции.

Пример ./service/*/playbook.yml из default A-service (логика работы будет описана ниже):

- name: Basic Configuration | Ubuntu | Run
  hosts: "{{ playbook_hostname }}"
  gather_facts: false
  become: true
  tasks:

	# ...

    # Установка Default-роли создания виртуальной машины
    - name: Role | vsphere_ubuntu
      when:
        - polygon_platform is match("vsphere")
        - service_ubuntu_role_vsphere_ubuntu_down is not defined or
          not service_ubuntu_role_vsphere_ubuntu_down
      include_role:
        name: vsphere_ubuntu

    # Запуск ролей в зависящем A-service
    - name: Role | Ubuntu | Run GameService Roles
      when:
        - service_ubuntu_gameservice_role is defined
        - service_ubuntu_gameservice_role != ''
      include_tasks: "{{ playbook_dir }}/../{{ service_ubuntu_gameservice_role }}"

	# ...

Состав A-service:

  • Сценарий запуска контейнера (docker-compose.yml) на основе default A-service с подключением своих сценариев.

  • Зависимости Ansible, которые обогащают дефолтные библиотеки.

  • Файл playbook.yml — с полным сценарием установки, который хуками расширяет сценарии из default A-service.

На примере A-service развертывания seafile, дерево проекта выглядит так:

  • docker-compose.yml — сценарий запуска контейнера на основе default A-service.

  • requirements.yml — Ansible-зависимости для текущего A-service. Будут обогащать зависимости от сценария default A-service.

  • playbook.yml — книга, которая в определенной последовательности запускает индивидуальные сценарии из папки ./config, обогащающие сценарии default A-service. Далее запускает нужный playbook.yml из default A-service.

Пример playbook.yml из A-service (логика работы будет описана ниже):

- name: Include default ansible-service | Deploy GameService
  vars:

	# ...

    # Файл для генерации служебного пользователя
    service_ubuntu_custom_user: “config/custom_user.yml”

    # Файл для настройки ролей основного сценария
    service_ubuntu_gameservice_role: "config/gameservice_role.yml"

  import_playbook: ubuntu/playbook.yml

Логика работы внутренней архитектуры

  • После старта контейнера A-service, основанного на default A-service (то есть каталоги и файлы A-service дополнили каталоги и файлы default A-service), запускается playbook.yml из A-service.

  • playbook.yml из A-service формирует ссылки на конфигурационные файлы (пример выше), которые будут встраиваться в сценарий из default A-service.

  • playbook.yml из A-service подключает playbook.yml из default A-service выбранного сценария (пример выше). Начинается основное развертывание.

  • Начинается процесс валидации:

    • Основной файл для валидации в default A-service может быть расширен хуком до и хуком после. То есть присутствует дефолтная проверка, но мы ее можем обогатить через сценарии A-service.

  • Настраиваем переменные для ролей default A-service. Их мы тоже можем расширить хуками до и после.

  • Настраиваем роли A-service.

  • Выполняем роли default A-service, которые настроены в п. 2.

  • Выполняем роли A-service с настройками из п. 3.

  • Сохраняем артефакты в Inventory. Это нужно для того, чтобы другие A-service могли получить информацию о ранее установленных сервисах. На этой основе и проходит интеграция внутри инфраструктуры.

Минус

  • Контроль версий. Нужно не забывать, что чем больше связей между компонентами, тем более внимательно необходимо следить за тем, что используешь и подключаешь в A-service. А здесь нужно следить за версиями default A-service, Ansible ролей, Ansible коллекций, Inventory и Deployer.

Итог

Налажена быстрая и независимая разработка сценариев развертывания и настройки.

Изменение платформы, обновление версии любого из компонентов не приносит много боли.

Есть возможность гибкого запуска сценариев — как в нужной последовательности, так и параллельно на основе блоков (A-services).

Комментарии (1)


  1. DmitriyEssensci
    07.10.2025 10:06

    На мой взгляд очень сильно ломать базою структуру и арху FHS - кощунство.

    Правильно понял, что под каждую роль есть свой a-s контейнер? Мне кажется подобная история это создание дополнительных прослоек, которые нужно как-то регулировать и версионировать. При 40+ ролей уже начинается зоопарк в репе, а это для каждого объекта ещё нужно сделать связи в VCS (inventory, playbooks, roles, templates)))). Так же не ясно как тут вообще будет работать молекула.

    Но всё равно респект, материал интересный, в очередной раз говорит про гибкость всеми нами любимого ansible.