Ответ
В инфраструктурных проектах я постоянно работаю с целевым выполнением плейбуков. Вот основные практики, которые использую.
1. Определение целей в инвентари (inventory) — основной метод.
Группирую хосты в inventory/production.ini:
[webservers]
web01.example.com ansible_user=deploy
web02.example.com
[databases]
db01.example.com
[all:vars]
ansible_python_interpreter=/usr/bin/python3
Затем в плейбуке указываю группу:
- name: Configure Nginx on web servers
hosts: webservers # Выполнится ТОЛЬКО на этой группе
tasks: ...
2. Динамическое ограничение с помощью --limit:
Запускаю плейбук для подмножества хостов из группы, например, для одного сервера из webservers:
ansible-playbook site.yml --limit "web01.example.com"
# Или по шаблону:
ansible-playbook site.yml --limit "*.example.com"
3. Использование тегов (tags):
Позволяет выполнять не весь плейбук, а только задачи с определенными тегами на любой группе хостов.
- name: Deploy application
hosts: all
tasks:
- name: Copy configs
copy: src=app.conf dest=/etc/
tags: config
- name: Restart service
systemd: name=app state=restarted
tags: deploy
Запуск: ansible-playbook deploy.yml --tags "deploy" --limit "webservers"
4. Динамические группы и переменные извне:
Часто в CI/CD нужно передать целевые хосты динамически. Использую переменную hosts:
- name: Run ad-hoc update
hosts: "{{ target_hosts | default('all') }}"
tasks: ...
Запуск с передачей хостов через переменную окружения или аргумент:
export TARGET_HOSTS="web01,db01"
ansible-playbook update.yml -e "target_hosts=$TARGET_HOSTS"
Для сложной логики (например, выполнить задачу только если сервер в определенном дата-центре) использую условие when с фактами Ansible: when: ansible_facts['datacenter'] == 'ams1'.
Ответ 18+ 🔞
Ну, слушай, вот работаешь ты с этой инфраструктурой, а потом понимаешь — овердохуища серверов, и на всех сразу плейбук гонять как-то не очень. Ну, ёпта, представь: ты обновляешь конфиг, а он на базе данных тоже запустится и всё к ебеням сломает. Поэтому надо уметь целиться, как снайпер, а не палить из пушки по воробьям.
1. Группировка в инвентаре — это святое, основа основ.
Вот смотри, в файлике inventory/production.ini ты просто раскидываешь хосты по полочкам, как в армии: пехота — к пехоте, артиллерия — к артиллерии.
[webservers]
web01.example.com ansible_user=deploy
web02.example.com
[databases]
db01.example.com
[all:vars]
ansible_python_interpreter=/usr/bin/python3
А потом в плейбуке просто говоришь: «Эй, Ansible, работай только с пехотой!». И он послушно выполнит всё только на webservers. Просто, как три копейки, но доверия ебать ноль, что новички это сразу поймут.
2. Динамический лимит через --limit — для точечных ударов.
Бывает, обосраться можно от волнения: надо не на всю группу, а на один конкретный хост что-то применить. Например, web01 забаговался. Зачем всех трогать? Берёшь и ограничиваешь:
ansible-playbook site.yml --limit "web01.example.com"
# Или, если хочешь по маске, типа на всех в домене:
ansible-playbook site.yml --limit "*.example.com"
Вот это уже похоже на работу, а не на мартышлюшку с гранатой.
3. Теги (tags) — твои лучшие друзья в бардаке.
Представь плейбук, где задач — как говна за баней. А тебе надо только конфиги скопировать и всё. Зачем весь цирк запускать? Вешаешь на задачи бирки.
- name: Deploy application
hosts: all
tasks:
- name: Copy configs
copy: src=app.conf dest=/etc/
tags: config # Бирочка "конфиг"
- name: Restart service
systemd: name=app state=restarted
tags: deploy # Бирочка "деплой"
И потом запускаешь с точностью хирурга: ansible-playbook deploy.yml --tags "deploy" --limit "webservers". Выполнится только перезапуск сервиса и только на веб-серверах. Красота, ёпта! Удивление пиздец, как же раньше без этого жили.
4. Динамические группы извне — когда всё летит из CI/CD. А вот это, чувак, высший пилотаж. Когда твой CI-пайpline сам решает, на какие хосты деплоить. Ты в плейбуке делаешь хостс переменной:
- name: Run ad-hoc update
hosts: "{{ target_hosts | default('all') }}" # Если переменной нет — работаем везде
tasks: ...
А запускаешь так, передавая хосты хоть из переменной окружения, хоть с Луны:
export TARGET_HOSTS="web01,db01"
ansible-playbook update.yml -e "target_hosts=$TARGET_HOSTS"
Вот тут уже терпения ноль ебать, если переменную не передали и плейбук пошёл на «all» — будет вам хиросима и нигерсраки.
А для совсем хитрожопой логики (типа «обновляй только если сервер в Амстердаме») используешь условие when. Смотришь факты Ansible и фильтруешь:
when: ansible_facts['datacenter'] == 'ams1'
Вот тогда ты уже не просто кнопкодав, а настоящий инженер, который умом работает, а не тыкается, как слепой кот в жопу.