Автоматизация развертывания кластеров на Ansible: готовые playbook для Pacemaker, балансировки и хранилищ (2026) | AdminWiki
Timeweb Cloud — сервера, Kubernetes, S3, Terraform. Лучшие цены IaaS.
Попробовать

Автоматизация развертывания кластеров на Ansible: готовые playbook для Pacemaker, балансировки и хранилищ (2026)

22 мая 2026 10 мин. чтения

Автоматизация развертывания кластеров с помощью Ansible превращает сложный и рискованный процесс в воспроизводимую и безопасную операцию. Это руководство предоставляет готовые, проверенные на практике playbook, роли и шаблоны для типовых сценариев 2026 года. Вы получите полный набор инструментов для быстрого создания кластеров Corosync/Pacemaker, отказоустойчивых балансировщиков на Keepalived и базовых конфигураций распределенного хранилища. Акцент сделан на идемпотентность, безопасное управление секретами через Ansible Vault и организацию проекта, которая упрощает поддержку и масштабирование.

Материал основан на реальном опыте развертывания в production-средах и учитывает особенности современных дистрибутивов Linux. Все примеры кода адаптированы под актуальные версии Ansible и его модулей, включая переход на рекомендованные collections. Вы сможете не только скопировать готовые решения, но и понять архитектурные принципы для адаптации под свои задачи.

Подготовка проекта Ansible: структура и безопасность для кластерных сред

Правильная организация проекта Ansible определяет его долгосрочную поддерживаемость и безопасность. Для кластерных сред, где конфигурации сложны, а секреты критичны, структура и управление доступом становятся первостепенными.

Оптимальная структура каталогов: разделение ролей и конфигураций

Логичное разделение кода упрощает переиспользование компонентов для разных типов кластеров. Для проекта по управлению кластерами рекомендуем следующую структуру каталогов:

automated_clusters/
├── ansible.cfg
├── inventories/
│   ├── production/
│   │   ├── hosts.yaml        # Инвентарь в формате YAML
│   │   └── group_vars/
│   │       ├── all.yml       # Общие переменные
│   │       ├── ha_nodes.yml  # Переменные для узлов кластера HA
│   │       └── lb_nodes.yml  # Переменные для балансировщиков
│   └── staging/              # Аналогичная структура для staging
├── roles/
│   ├── cluster_ha/           # Роль для Corosync/Pacemaker
│   ├── lb_keepalived/        # Роль для Keepalived
│   └── common/               # Общие задачи (firewall, users, packages)
├── playbooks/
│   ├── deploy_ha_cluster.yaml
│   ├── deploy_loadbalancer.yaml
│   └── site.yaml             # Главный playbook, импортирующий другие
├── templates/                # Шаблоны Jinja2 для конфигураций
├── files/                    # Статические файлы для копирования
├── vault/                    # Зашифрованные файлы с секретами
│   └── secrets_prod.yml
└── requirements.yml          # Зависимости (collections, роли)

Инвентарь в формате YAML (hosts.yaml) наглядно определяет группы и переменные на уровне хоста. Пример для двухузлового кластера Pacemaker и балансировщика:

all:
  children:
    ha_cluster:
      hosts:
        node1.cluster.local:
          node_id: 1
          corosync_ip: 192.168.10.11
        node2.cluster.local:
          node_id: 2
          corosync_ip: 192.168.10.12
    loadbalancers:
      hosts:
        lb1.cluster.local:
          keepalived_priority: 150
          vip: 10.0.0.100
        lb2.cluster.local:
          keepalived_priority: 100
          vip: 10.0.0.100

Такое разделение позволяет независимо управлять разными компонентами инфраструктуры и масштабировать проект, добавляя новые роли без переписывания существующей логики.

Безопасное управление секретами с Ansible Vault: ключи, пароли, токены

Хранение паролей, ключей аутентификации Corosync и SSL-сертификатов в открытом виде создает критическую уязвимость. Ansible Vault решает эту проблему шифрованием чувствительных данных.

Создайте зашифрованный файл для секретов:

ansible-vault create vault/secrets_prod.yml

Определите в нем переменные:

# vault/secrets_prod.yml
hacluster_password: "{{ vault_hacluster_password }}"
corosync_authkey: "{{ vault_corosync_authkey }}"
ssl_certificate_private_key: "{{ vault_ssl_key }}"

Фактические значения задаются при запуске playbook через команду ansible-vault encrypt_string или хранятся в защищенном CI/CD пайплайне. Интегрируйте зашифрованные переменные в playbook, используя vars_files с тегом vault:

# playbooks/deploy_ha_cluster.yaml
- hosts: ha_cluster
  vars_files:
    - "{{ playbook_dir }}/vault/secrets_prod.yml"
  tasks:
    - name: Set hacluster password
      ansible.builtin.user:
        name: hacluster
        password: "{{ hacluster_password | password_hash('sha512') }}"
        update_password: always
      tags: vault

Для генерации и безопасной передачи ключа аутентификации Corosync между узлами кластера используйте задачу, которая создает ключ на control node и распределяет его:

- name: Generate Corosync authkey if not present
  ansible.builtin.command:
    cmd: corosync-keygen
    chdir: /tmp
  delegate_to: localhost
  run_once: true
  register: keygen_result
  changed_when: keygen_result.rc == 0

- name: Distribute Corosync authkey
  ansible.builtin.copy:
    src: /tmp/authkey
    dest: /etc/corosync/authkey
    owner: root
    group: root
    mode: '0400'
  when: inventory_hostname in groups['ha_cluster']

Практика ротации секретов предполагает обновление зашифрованного файла через ansible-vault rekey и повторный запуск соответствующих playbook. Для автоматизации этого процесса в CI/CD используйте переменные окружения ANSIBLE_VAULT_PASSWORD_FILE.

Готовые playbook и роли для развертывания кластера Corosync/Pacemaker

Развертывание отказоустойчивого кластера на базе Corosync и Pacemaker включает несколько этапов: установка пакетов, настройка коммуникации, конфигурация кворума и создание ресурсов. Представленная роль cluster_ha объединяет эти шаги в идемпотентный playbook.

Базовая роль `cluster_ha`: установка пакетов и настройка Corosync

Роль содержит задачи для семейств RedHat (RHEL, CentOS, AlmaLinux) и Debian (Ubuntu). Основные задачи находятся в roles/cluster_ha/tasks/main.yml:

# roles/cluster_ha/tasks/main.yml
- name: Install HA packages (RedHat)
  ansible.builtin.package:
    name:
      - corosync
      - pacemaker
      - pcs
      - fence-agents-all
    state: present
  when: ansible_os_family == "RedHat"

- name: Install HA packages (Debian)
  ansible.builtin.package:
    name:
      - corosync
      - pacemaker
      - pcs
      - fence-agents
    state: present
  when: ansible_os_family == "Debian"

- name: Start and enable pcsd service
  ansible.builtin.service:
    name: pcsd
    state: started
    enabled: true

- name: Set hacluster password
  ansible.builtin.user:
    name: hacluster
    password: "{{ hacluster_password | password_hash('sha512') }}"
    update_password: always
  tags: vault

- name: Configure Corosync
  ansible.builtin.template:
    src: corosync.conf.j2
    dest: /etc/corosync/corosync.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart corosync

Шаблон corosync.conf.j2 динамически формирует конфигурацию на основе переменных инвентаря:

# roles/cluster_ha/templates/corosync.conf.j2
totem {
  version: 2
  cluster_name: {{ cluster_name | default('my_ha_cluster') }}
  transport: udpu
  crypto_cipher: aes256
  crypto_hash: sha256
}

nodelist {
{% for host in groups['ha_cluster'] %}
  node {
    ring0_addr: {{ hostvars[host].corosync_ip | default(hostvars[host].ansible_default_ipv4.address) }}
    nodeid: {{ hostvars[host].node_id }}
    name: {{ host }}
  }
{% endfor %}
}

quorum {
  provider: corosync_votequorum
  two_node: {{ (groups['ha_cluster'] | length == 2) | ternary('1', '0') }}
}

logging {
  to_logfile: yes
  logfile: /var/log/corosync/corosync.log
  to_syslog: yes
  timestamp: on
}

После применения конфигурации задачи инициализируют кластер и настраивают fencing с помощью модуля community.general.pcs_cluster из коллекции community.general, актуальной для 2026 года:

- name: Authenticate nodes in cluster
  community.general.pcs_cluster:
    state: present
    nodes: "{{ groups['ha_cluster'] | join(',') }}"
    cluster_auth: "{{ hacluster_password }}"
  run_once: true
  delegate_to: "{{ groups['ha_cluster'][0] }}"

- name: Configure STONITH fencing (example for virsh)
  community.general.pcs_stonith:
    stonith_id: fence_virsh
    stonith_type: fence_virsh
    stonith_options:
      - "pcmk_host_list={{ groups['ha_cluster'] | join(' ') }}"
      - "uri=hypervisor.local"
      - "key_file=/root/.ssh/id_rsa"
    state: present
  run_once: true

Управление ресурсами в Pacemaker: виртуальные IP и службы

Автоматизация создания ресурсов кластера завершает развертывание. Playbook для управления ресурсами использует модуль community.general.pcs_resource:

# playbooks/manage_ha_resources.yaml
- hosts: ha_cluster[0]  # Запускаем на первом узле
  tasks:
    - name: Create virtual IP resource
      community.general.pcs_resource:
        resource_id: vip_web
        resource_type: IPaddr2
        resource_options:
          - "ip={{ web_vip }}"
          - "cidr_netmask=24"
        state: present
        cluster_auth: "{{ hacluster_password }}"

    - name: Create Apache service resource
      community.general.pcs_resource:
        resource_id: httpd_svc
        resource_type: systemd:httpd
        resource_options:
          - "enable=true"
        state: present
        cluster_auth: "{{ hacluster_password }}"

    - name: Constrain resources to run together
      community.general.pcs_resource:
        command: constraint
        constraint_type: colocation
        resource_id: httpd_svc
        dependent_resource_id: vip_web
        score: INFINITY
        state: present
        cluster_auth: "{{ hacluster_password }}"

    - name: Set start order (VIP first, then Apache)
      community.general.pcs_resource:
        command: constraint
        constraint_type: order
        first_resource_id: vip_web
        then_resource_id: httpd_svc
        options: "kind=Mandatory"
        state: present
        cluster_auth: "{{ hacluster_password }}"

Best practice для именования ресурсов - использовать префиксы, указывающие на тип (vip_, svc_, fs_). Это упрощает их идентификацию в выводе команд pcs status. Для управления конфигурациями разных окружений (dev, stage, prod) определите переменные web_vip, cluster_name в соответствующих файлах group_vars.

Автоматизация развертывания балансировщика нагрузки и распределенного хранилища

Принципы автоматизации кластеров применимы к другим сценариям, таким как отказоустойчивые балансировщики и распределенные хранилища. Использование общих подходов и структуры проекта ускоряет внедрение новых типов кластеров.

Кластер балансировщиков на Keepalived: отказоустойчивый виртуальный IP

Роль lb_keepalived настраивает простой, но эффективный кластер для отказоустойчивого виртуального IP (VIP), направляющего трафик на бэкенд-серверы. Основная задача - управление конфигурацией Keepalived через шаблон Jinja2.

# roles/lb_keepalived/tasks/main.yml
- name: Install Keepalived
  ansible.builtin.package:
    name: keepalived
    state: present

- name: Configure Keepalived
  ansible.builtin.template:
    src: keepalived.conf.j2
    dest: /etc/keepalived/keepalived.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart keepalived

- name: Enable and start Keepalived service
  ansible.builtin.service:
    name: keepalived
    state: started
    enabled: true

Шаблон keepalived.conf.j2 динамически назначает роли (MASTER/BACKUP) на основе приоритета, заданного в инвентаре:

# roles/lb_keepalived/templates/keepalived.conf.j2
global_defs {
    router_id LVS_{{ inventory_hostname_short | upper }}
}

vrrp_instance VI_1 {
    state {{ (keepalived_priority == 150) | ternary('MASTER', 'BACKUP') }}
    interface {{ ansible_default_ipv4.alias | default(ansible_default_ipv4.device) }}
    virtual_router_id 51
    priority {{ keepalived_priority }}
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass {{ keepalived_auth_pass | default('secret_password') }}
    }
    virtual_ipaddress {
        {{ vip }}
    }
    notify_master "/usr/local/bin/notify_master.sh"
    notify_backup "/usr/local/bin/notify_backup.sh"
}

Механизм уведомлений (notify scripts) интегрирует кластер Keepalived с системами мониторинга (например, Prometheus) или отправляет оповещения в Slack/Telegram при смене состояния. Для проверки здоровья реальных сервисов можно добавить секцию virtual_server с health check для бэкендов.

Адаптация playbook под разные сценарии: использование переменных и тегов

Главный playbook site.yaml импортирует другие сценарии и позволяет гибко управлять развертыванием через теги и переменные.

# playbooks/site.yaml
- name: Deploy High Availability infrastructure
  hosts: all
  vars:
    deploy_ha_cluster: true
    deploy_loadbalancer: false
    deploy_storage: false
  tasks:
    - name: Include HA cluster deployment
      ansible.builtin.include_tasks: "{{ playbook_dir }}/deploy_ha_cluster.yaml"
      when: deploy_ha_cluster
      tags: ha

    - name: Include loadbalancer deployment
      ansible.builtin.include_tasks: "{{ playbook_dir }}/deploy_loadbalancer.yaml"
      when: deploy_loadbalancer
      tags: lb

    - name: Include distributed storage deployment
      ansible.builtin.include_tasks: "{{ playbook_dir }}/deploy_drbd_storage.yaml"
      when: deploy_storage
      tags: storage

Запустите развертывание только балансировщиков: ansible-playbook -i inventories/production/ playbooks/site.yaml --tags lb. Для кастомизации параметров под конкретное окружение переопределите переменные в инвентаре. Например, чтобы изменить виртуальный IP для staging:

# inventories/staging/group_vars/lb_nodes.yml
vip: 10.0.1.100
keepalived_priority:
  lb1.staging.local: 150
  lb2.staging.local: 100

Такой подход позволяет использовать один набор ролей для разных сред и требований, минимизируя дублирование кода.

Best practices и отладка: обеспечение идемпотентности и обработка ошибок

Надежная автоматизация требует не только рабочих playbook, но и стратегий тестирования, обработки сбоев и поддержания идемпотентности. Эти практики снижают риски при развертывании в production.

Тестирование playbook: от Vagrant до staging-окружения

Поэтапное тестирование минимизирует вероятность ошибок в боевой среде. Придерживайтесь следующего плана:

  1. Локальная проверка синтаксиса и предпросмотр изменений:
    ansible-playbook playbooks/site.yaml --check --diff --limit localhost
    Режим --check (dry run) показывает, какие изменения произойдут, не применяя их. Режим --diff отображает различия в изменяемых файлах.
  2. Развертывание на изолированных виртуальных машинах с идентичной ОС: Используйте Vagrant с тем же образом, что и в production. После выполнения playbook проверьте состояние кластера с помощью модуля ansible.builtin.shell:
- name: Verify Pacemaker cluster status
  ansible.builtin.shell:
    cmd: pcs status
  register: pcs_status
  changed_when: false
  failed_when: "'OFFLINE' in pcs_status.stdout or 'Stopped' in pcs_status.stdout"

- name: Debug output on failure
  ansible.builtin.debug:
    var: pcs_status.stdout
  when: pcs_status.failed
  1. Скрипт пост-деплой проверки: Автоматизируйте проверку ключевых метрик после развертывания. Пример скрипта, который проверяет доступность виртуального IP и службы:
#!/bin/bash
# scripts/post_deploy_verify.sh
VIP="10.0.0.100"
if ping -c 2 $VIP &> /dev/null; then
    echo "VIP $VIP is reachable."
    if curl -s --connect-timeout 5 http://$VIP/health | grep -q "OK"; then
        echo "Service on $VIP is responding correctly."
        exit 0
    else
        echo "Service health check failed."
        exit 1
    fi
else
    echo "VIP $VIP is not reachable."
    exit 1
fi

Интегрируйте этот скрипт в playbook как финальную задачу или запускайте его отдельно из CI/CD пайплайна.

Типовые проблемы при автоматизации кластеров и их решение

Автоматизация кластеров сталкивается со специфичными проблемами. Вот список частых ошибок и способы их решения в рамках Ansible:

  • Отказ в аутентификации Corosync между узлами:
    1. Причина: Несовпадение ключа authkey или блокировка firewall.
    2. Диагностика: Проверьте наличие идентичного файла /etc/corosync/authkey на всех узлах. Убедитесь, что порты UDP 5404-5405 открыты.
    3. Решение в Ansible: Добавьте задачу для проверки и открытия портов в роли common:
      - name: Ensure firewall allows Corosync ports
        ansible.posix.firewalld:
          port: "5404-5405/udp"
          permanent: true
          immediate: true
          state: enabled
        when: ansible_os_family == "RedHat"
  • Отсутствие кворума в двухузловом кластере:
    1. Причина: По умолчанию двухузловый кластер требует специальной настройки two_node: 1 или использования qdevice.
    2. Решение: Убедитесь, что в шаблоне corosync.conf.j2 параметр two_node установлен в 1. Добавьте задачу для настройки ожидания кворума в Pacemaker:
      - name: Configure two-node cluster quorum
        community.general.pcs_quorum:
          options:
            - "wait_for_all=0"
            - "auto_tie_breaker=1"
          state: present
        run_once: true
  • Сбои fencing (STONITH):
    1. Причина: Неправильная конфигурация агента fencing или отсутствие доступа к гипервизору.
    2. Диагностика: Выполните тестовую команду fencing вручную: fence_virsh --list.
    3. Решение: Используйте блок rescue в playbook для временного отключения fencing при критическом сбое, но с обязательным предупреждением:
      - name: Configure STONITH
        community.general.pcs_stonith:
          # ... конфигурация
        ignore_errors: yes
        register: stonith_result
      
      - name: Warn if STONITH configuration failed
        ansible.builtin.debug:
          msg: "STONITH configuration failed. Cluster will proceed without fencing (NOT RECOMMENDED FOR PRODUCTION)."
        when: stonith_result.failed

Обеспечьте идемпотентность, используя модули, которые сами проверяют состояние (например, ansible.builtin.template), и избегайте команд shell или command там, где есть специализированные альтернативы. Для обработки некритичных ошибок применяйте failed_when: с точными условиями и ignore_errors: yes с последующим уведомлением.

Актуальность модулей критична. В 2026 году многие устаревшие модули из ansible.builtin заменены на более функциональные в коллекциях. Например, для управления Pacemaker используйте community.general.pcs_* модули. Укажите зависимости в requirements.yml:

# requirements.yml
collections:
  - name: community.general
    version: ">=7.0.0"
  - name: ansible.posix
    version: ">=1.5.0"

Установите их командой ansible-galaxy collection install -r requirements.yml перед запуском playbook.

Для дальнейшего изучения принципов IaC и комбинирования инструментов рекомендуем наше руководство «Ansible или Terraform: выбор инструмента для управления инфраструктурой в 2026», где подробно разбирается совместное использование этих технологий.

Если вам нужно автоматизировать не только кластеры, но и другие рутинные задачи администрирования, ознакомьтесь с практическими скриптами в статье «Автоматизация инфраструктуры на практике».

Поделиться:
Сохранить гайд? В закладки браузера