Как изменить последовательное выполнение задач Ansible playbook на параллельное?

Ответ

Параллельное выполнение в Ansible значительно ускоряет развертывание на множестве хостов. Я использую несколько механизмов в зависимости от сценария.

1. Стратегия выполнения free (наиболее агрессивная)

---
- name: Deploy application cluster
  hosts: web_servers  # Группа из 10+ хостов
  strategy: free
  tasks:
    - name: Update packages
      apt:
        update_cache: yes
        cache_valid_time: 3600
      async: 300  # Асинхронное выполнение с таймаутом
      poll: 0     # Не ждем завершения, продолжаем

    - name: Deploy application code
      synchronize:
        src: ./app/
        dest: /opt/app/
      delegate_to: "{{ inventory_hostname }}"

    - name: Restart service
      systemd:
        name: app-service
        state: restarted
      async: 60
      poll: 10    # Проверяем статус каждые 10 секунд

2. Настройка количества форков (параллельных соединений)

# В командной строке
ansible-playbook deploy.yml --forks 20

# Или в ansible.cfg
[defaults]
forks = 20
host_key_checking = False
# Увеличиваем таймауты для параллельного выполнения
timeout = 30
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

3. Параллельное выполнение с ограничениями

- name: Rolling update with batch
  hosts: web_servers
  serial: 3  # Обрабатываем по 3 хоста одновременно
  tasks:
    - name: Take host out of load balancer
      uri:
        url: "http://lb-api/disable/{{ inventory_hostname }}"
        method: POST

    - name: Apply updates
      include_tasks: update_tasks.yml

    - name: Return host to load balancer
      uri:
        url: "http://lb-api/enable/{{ inventory_hostname }}"
        method: POST

4. Асинхронные задачи с проверкой статуса

- name: Run long operation
  command: /opt/scripts/long-running-process.sh
  async: 1800  # 30 минут максимум
  poll: 30     # Проверяем каждые 30 секунд
  register: long_task

- name: Check async task status
  async_status:
    jid: "{{ long_task.ansible_job_id }}"
  register: job_result
  until: job_result.finished
  retries: 30
  delay: 30

5. Параллельное выполнение разных задач на разных хостах

- name: Database migration (только на master)
  hosts: db_master
  tasks:
    - name: Run migrations
      command: /opt/app/migrate.sh

- name: Application deployment (параллельно на всех app servers)
  hosts: app_servers
  strategy: free
  tasks:
    - name: Deploy code
      synchronize:
        src: ./app/
        dest: /opt/app/

6. Использование throttle для ограничения нагрузки

- name: CPU-intensive operation
  hosts: all
  tasks:
    - name: Compile software
      make:
        chdir: /src/
      throttle: 2  # Не более 2 хостов одновременно

Ключевые практики:

  • Тестирую параллельное выполнение в staging перед production
  • Мониторю нагрузку на управляющей машине (CPU, память, сеть)
  • Использую serial для rolling updates критических сервисов
  • Настраиваю правильные таймауты в ansible.cfg
  • Логирую выполнение с тегами хостов для отладки
  • Для очень больших инфраструктур (>1000 хостов) использую Ansible Tower/AWX с разбивкой на job templates

Ответ 18+ 🔞

Ёпта, ну смотри, тут про параллельное выполнение в Ansible. Всё просто, как три копейки, но если не знать этих фокусов — можно ждать, пока хуй с горы свалится, пока плейбук на сотне серверов отработает.

Вот, например, самая агрессивная стратегия — free. Это когда ты говоришь: "Похуй, чувак, делай всё что хочешь и как хочешь". Сервера начинают работать асинхронно, без оглядки друг на друга. Главное — правильно таймауты выставить, а то получишь овердохуища ошибок.

---
- name: Deploy application cluster
  hosts: web_servers  # Группа из 10+ хостов
  strategy: free
  tasks:
    - name: Update packages
      apt:
        update_cache: yes
        cache_valid_time: 3600
      async: 300  # Асинхронное выполнение с таймаутом
      poll: 0     # Не ждем завершения, продолжаем

А ещё можно просто в командной строке форков накрутить. Типа --forks 20. Это как сказать: "Э, сабака сука, у меня двадцать рук, я всеми сразу могу работать". Но тут главное — не переборщить, а то управляющая машина взвоет, как мартышлюшка, и накроется медным тазом.

Самый адекватный подход для прода — это rolling update. Ставишь serial: 3 и обрабатываешь по три хоста за раз. Сначала выводишь из балансировщика, потом обновляешь, потом обратно загоняешь. Так и волнение ебать поменьше, и если что-то пойдёт не так — только три сервера в ауте, а не все сразу.

- name: Rolling update with batch
  hosts: web_servers
  serial: 3  # Обрабатываем по 3 хоста одновременно

А бывают задачи, которые выполняются хуй знает сколько. Для них есть асинхронный режим с проверкой статуса. Запустил, зарегистрировал job id, и потом периодически дёргаешь: "Ну что, готово, пидарас шерстяной, или ещё нет?" Пока не скажет finished.

Ну и, конечно, для особо прожорливых операций есть throttle. Скажем, компиляция софта. Если на всех серверах одновременно запустить make — они друг другу все ресурсы сожрут. Ставишь throttle: 2 и спокойно смотришь, как они по очереди, не спеша, всё делают.

Главное, чувак, — тестировать это всё на staging-окружении. Потому что если сразу на прод запустишь с неправильными настройками, будет тебе хиросима и нигерсраки. Сервера попадают, задачи зависают, а ты сидишь и думаешь: "Э, бошка думай, что же пошло не так?". А всё пошло не так с самого начала, потому что доверия ебать ноль к непроверенным конфигам.

Для совсем больших фертин, где серверов больше, чем мозгов у менеджера, уже нужен Ansible Tower или AWX. Там уже встроенные механизмы для работы с овердохуищем хостов, с очередями и распределением нагрузки. Но это уже совсем другая история, с кот сука собака сложностью.