run_once и serial
Тема дорожной карты · Ansible
Директива run_once в Ansible заставляет задачу выполниться ровно на одном хосте из текущего пакета — на первом хосте в сериализованном play, — независимо от того, сколько хостов задействовано. Это широко применяется для разовых операций в кластерной среде, например для выполнения миграции базы данных или начального заполнения данными, — ситуаций, когда выполнение одной и той же операции на каждом узле привело бы к ошибкам или дублированию. Директиву часто сочетают с delegate_to: db_primary, чтобы единственное выполнение происходило на конкретном назначенном хосте, а не на том, который оказался первым. Обратите внимание: run_once не означает, что задача уникальна на протяжении всего playbook; если play сериализован с serial: 5, задача выполнится по одному разу на каждый пакет из пяти хостов.
Как это работает
run_once и serial покрывает условия (when:), циклы (loop:/with_items:), error handling (block/rescue/always, failed_when, changed_when), делегирование (delegate_to: localhost для запуска задачи на контроллере), async-задачи (async: 60 poll: 5 для долгих операций), кеширование facts (fact_caching = redis), разработку filter/lookup/callback-плагинов. Ansible — настоящий DSL с серьёзной программируемостью.
Когда применять
block/rescue/always вместо ignore_errors для нормального error handling. async — для задач дольше SSH-таймаута (миграции БД, сборка образов). delegate_to — для "сделать на load balancer" посреди play. Кеширование facts в Redis — при большом inventory + медленных gather_facts.
Типичные ошибки
Ловушки run_once и serial: сложный Jinja2 + Ansible-специфика (when: var is defined and var | length > 0 — порядок важен, is defined первым для short-circuit); чрезмерный delegate_to ("магия на расстоянии"); loop с очень большими списками = медленный запуск + рост памяти (используйте batch: или chunked-плейбуки); сбор facts на каждом play в долгом запуске (поставьте gather_facts: false после первого play).