Playbook tips
These tips help make playbooks and roles easier to read, maintain, and debug.
Generous use of whitespace, for example, a blank line before each block or task, makes a playbook easy to scan.
Task names are optional, but extremely useful. In its output, Ansible shows you the name of each task it runs. Choose names that describe what each task does and why.
For many modules, the ‘state’ parameter is optional. Different modules have different default settings for ‘state’, and some modules support several ‘state’ settings. Explicitly setting ‘state=present’ or ‘state=absent’ makes playbooks and roles clearer.
Role directory structure
An Ansible role has a defined directory structure with eight main standard directories. You must include at least one of these directories in each role. You can omit any directories the role does not use. For example:
# playbooks site.yml webservers.yml fooservers.yml roles/ common/ tasks/ handlers/ library/ files/ templates/ vars/ defaults/ meta/ webservers/ tasks/ defaults/ meta/
By default Ansible will look in each directory within a role for a file for relevant content (also and ):
-
— the main list of tasks that the role executes.
-
— handlers, which may be used within or outside this role.
-
— modules, which may be used within this role (see for more information).
-
— default variables for the role (see for more information). These variables have the lowest priority of any variables available, and can be easily overridden by any other variable, including inventory variables.
-
— other variables for the role (see for more information).
-
— files that the role deploys.
-
— templates that the role deploys.
-
— metadata for the role, including role dependencies.
You can add other YAML files in some directories. For example, you can place platform-specific tasks in separate files and refer to them in the file:
# roles/example/tasks/main.yml - name Install the correct web server for RHEL import_tasks redhat.yml when ansible_facts|lower == 'redhat' - name Install the correct web server for Debian import_tasks debian.yml when ansible_facts|lower == 'debian' # roles/example/tasks/redhat.yml - name Install web server ansible.builtin.yum name "httpd" state present # roles/example/tasks/debian.yml - name Install web server ansible.builtin.apt name "apache2" state present
Концепция обработчиков
Вы можете понимать обработчики как другой вид задач. Обработчики — это еще один вид «списка задач». Задачи в обработчиках будут «вызываться» задачами в задачах, но их «вызов» не означает, что они будут выполнены. Только когда задачи в задачах «действительно выполняются» (фактические операции фактически выполняются, что приводит к фактическим изменениям), задачи, вызываемые в обработчиках, будут выполняться. Если задачи в задачах не выполняют никаких реальных операций, то Задачи в обработчиках не будут выполняться, даже если они вызываются. Кажется, это непросто понять, напишем небольшой пример, пример такой.
Как показано в приведенном выше примере, мы используем ключевое слово handlers, чтобы указать, какие задачи могут быть выполнены.Как я уже сказал, обработчики — это еще один список задач. Вы можете понимать обработчики как другую задачу, а можете понимать их кактот же уровеньИтак,Выровнены обработчики и задачи (одинаковый отступ), В приведенном выше примере в обработчиках есть только одна задача. Имя этой задачи — «перезапуск httpd». Как объяснялось ранее, задачи в обработчиках должны вызываться задачами в задачах. Затем, в приведенном выше примере, какой задачей является «перезапуск httpd» Вызывается? Очевидно, что «перезапуск httpd» вызывается командой «Изменить конфигурацию», да, как вы можете видеть, == Мы используем ключевое слово notify для «вызова» задач в обработчиках, или, другими словами, используем ключевое слово notify для «уведомления» обработчиков В задаче == Итак, подытоживая, игра в приведенном выше примере означает, что еслиДействительно измените файл конфигурации (фактическая операция), затем выполнитеЗадача, еслиЕсли фактических изменений не было сделано, они не будут реализованы. ,ЭтоРоль.
Playbook execution
A playbook runs in order from top to bottom. Within each play, tasks also run in order from top to bottom. Playbooks with multiple ‘plays’ can orchestrate multi-machine deployments, running one play on your webservers, then another play on your database servers, then a third play on your network infrastructure, and so on. At a minimum, each play defines two things:
-
the managed nodes to target, using a
-
at least one task to execute
Note
In Ansible 2.10 and later, we recommend you use the fully-qualified collection name in your playbooks to ensure the correct module is selected, because multiple collections can contain modules with the same name (for example, ). See .
In this example, the first play targets the web servers; the second play targets the database servers.
--- - name Update web servers hosts webservers remote_user root tasks - name Ensure apache is at the latest version ansible.builtin.yum name httpd state latest - name Write the apache config file ansible.builtin.template src /srv/httpd.j2 dest /etc/httpd.conf - name Update db servers hosts databases remote_user root tasks - name Ensure postgresql is at the latest version ansible.builtin.yum name postgresql state latest - name Ensure that postgresql is started ansible.builtin.service name postgresql state started
Your playbook can include more than just a hosts line and tasks. For example, the playbook above sets a for each play. This is the user account for the SSH connection. You can add other at the playbook, play, or task level to influence how Ansible behaves. Playbook keywords can control the , whether to use , how to handle errors, and more. To support a variety of environments, Ansible lets you set many of these parameters as command-line flags, in your Ansible configuration, or in your inventory. Learning the for these sources of data will help you as you expand your Ansible ecosystem.
By default, Ansible executes each task in order, one at a time, against all machines matched by the host pattern. Each task executes a module with specific arguments. When a task has executed on all target machines, Ansible moves on to the next task. You can use to change this default behavior. Within each play, Ansible applies the same task directives to all hosts. If a task fails on a host, Ansible takes that host out of the rotation for the rest of the playbook.
When you run a playbook, Ansible returns information about connections, the lines of all your plays and tasks, whether each task has succeeded or failed on each machine, and whether each task has made a change on each machine. At the bottom of the playbook execution, Ansible provides a summary of the nodes that were targeted and how they performed. General failures and fatal “unreachable” communication attempts are kept separate in the counts.
Most Ansible modules check whether the desired final state has already been achieved, and exit without performing any actions if that state has been achieved, so that repeating the task does not change the final state. Modules that behave this way are often called ‘idempotent.’ Whether you run a playbook once, or multiple times, the outcome should be the same. However, not all playbooks and not all modules behave this way. If you are unsure, test your playbooks in a sandbox environment before running them multiple times in production.
Verifying playbooks
You may want to verify your playbooks to catch syntax errors and other problems before you run them. The command offers several options for verification, including , , , , and . The describes other tools for validating and testing playbooks.
You can use ansible-lint for detailed, Ansible-specific feedback on your playbooks before you execute them. For example, if you run on the playbook called near the top of this page, you should get the following results:
$ ansible-lint verify-apache.yml 403 Package installs should not use latest verify-apache.yml:8 Task/Handler: ensure apache is at the latest version
The ansible-lint default rules page describes each error. For , the recommended fix is to change to in the playbook.
See also
- ansible-lint
-
Learn how to test Ansible Playbooks syntax
-
Learn about YAML syntax
-
Tips for managing playbooks in the real world
-
Browse existing collections, modules, and plugins
-
Learn to extend Ansible by writing your own modules
-
Learn about how to select hosts
- GitHub examples directory
-
Complete end-to-end playbook examples
- Mailing List
-
Questions? Help? Ideas? Stop by the list on Google Groups
Execution tricks
These tips apply to using Ansible, rather than to Ansible artifacts.
Testing changes in a staging environment before rolling them out in production is always a great idea. Your environments need not be the same size and you can use group variables to control the differences between those environments.
Use the ‘serial’ keyword to control how many machines you update at once in the batch. See .
Group variables files and the module work together to help Ansible execute across a range of operating systems and distributions that require different settings, packages, and tools. The module creates a dynamic group of hosts matching certain criteria. This group does not need to be defined in the inventory file. This approach lets you execute different tasks on different operating systems or distributions. For example:
--- - name talk to all hosts just so we can learn about them hosts all tasks - name Classify hosts depending on their OS distribution group_by key os_{{ ansible_facts'distribution' }} # now just on the CentOS hosts... - hosts os_CentOS gather_facts False tasks - # tasks that only happen on CentOS go in this play
The first play categorizes all systems into dynamic groups based on the operating system name. Later plays can use these groups as patterns on the line. You can also add group-specific settings in group vars files. All three names must match: the name created by the task, the name of the pattern in subsequent plays, and the name of the group vars file. For example:
--- # file: group_vars/all asdf 10 --- # file: group_vars/os_CentOS.yml asdf 42
In this example, CentOS machines get the value of ‘42’ for asdf, but other machines get ‘10’.
This can be used not only to set variables, but also to apply certain roles to only certain systems.
You can use the same setup with when you only need OS-specific variables, not tasks:
- hosts all tasks - name Set OS distribution dependent variables include_vars "os_{{ ansible_facts'distribution' }}.yml" - debug var asdf
This pulls in variables from the group_vars/os_CentOS.yml file.
See also
-
Learn about YAML syntax
-
Review the basic playbook features
-
Browse existing collections, modules, and plugins
-
Learn how to extend Ansible by writing your own modules
-
Learn about how to select hosts
- GitHub examples directory
-
Complete playbook files from the github project source
- Mailing List
-
Questions? Help? Ideas? Stop by the list on Google Groups
Прерывание игры на всех хозяевах
Иногда требуется, чтобы сбой на одном хосте или сбой на определенном проценте хостов прервали всю игру на всех хостах. Вы можете остановить выполнение воспроизведения после первого сбоя с помощью . Для более управления вы можете использовать max_fail_percentage, чтобы прервать выполнение после сбоя определенного процента хостов.
Прерывание первой ошибки:any_errors_fatal
Если вы устанавливаете и задача возвращает ошибку, Ansible завершает фатальную задачу на всех хостах в текущем пакете, а затем прекращает воспроизведение на всех хостах. Последующие задания и спектакли не выполняются. Вы можете избавиться от фатальных ошибок, добавив в блок восстановления. Вы можете установить на уровне игры или блока:
- hosts: somehosts any_errors_fatal: true roles: - myrole - hosts: somehosts tasks: - block: - include_tasks: mytasks.yml any_errors_fatal: true
Вы можете использовать эту функцию,когда все задачи должны быть на 100% успешными,чтобы продолжить выполнение Playbook.Например,если вы запускаете сервис на машинах в нескольких центрах обработки данных с балансировщиками нагрузки для передачи трафика от пользователей к сервису,вы хотите,чтобы все балансировщики нагрузки были отключены до того,как вы остановите сервис на техническое обслуживание.Чтобы гарантировать,что любой сбой в задаче,отключающей работу балансировщиков нагрузки,остановит все остальные задачи:
--- - hosts: load_balancers_dc_a any_errors_fatal: true tasks: - name: Shut down datacenter 'A' ansible.builtin.command: /usr/bin/disable-dc - hosts: frontends_dc_a tasks: - name: Stop service ansible.builtin.command: /usr/bin/stop-software - name: Update software ansible.builtin.command: /usr/bin/upgrade-software - hosts: load_balancers_dc_a tasks: - name: Start datacenter 'A' ansible.builtin.command: /usr/bin/enable-dc
В данном примере Ansible запускает обновление программного обеспечения на передних концах только в том случае,если все балансировщики нагрузки успешно отключены.
Установка максимального процента отказа
По умолчанию,Ansible продолжает выполнять задачи до тех пор,пока есть хосты,которые еще не вышли из строя.В некоторых ситуациях,например,при выполнении скользящего обновления,вы можете прервать воспроизведение,когда достигнут определенный порог неудач.Для этого вы можете установить максимальный процент сбоев при воспроизведении:
--- - hosts: webservers max_fail_percentage: 30 serial: 10
Параметр применяется к каждому пакету, когда вы используете его с интерфейсом . В приведенном выше примере, если более 3 из 10 серверов в первой (или любой) группе серверов вышли из строя, остальная часть игры будет прервана.
Note
Установленный процент должен быть превышен,а не равен.Например,если серийный набор установлен на 4 и вы хотите,чтобы задача прерывала воспроизведение при сбое 2-х систем,установите max_fail_percentage на 49,а не на 50.
Using variables with handlers
You may want your Ansible handlers to use variables. For example, if the name of a service varies slightly by distribution, you want your output to show the exact name of the restarted service for each target machine. Avoid placing variables in the name of the handler. Since handler names are templated early on, Ansible may not have a value available for a handler name like this:
handlers # This handler name may cause your play to fail! - name Restart "{{ web_service_name }}"
If the variable used in the handler name is not available, the entire play fails. Changing that variable mid-play will not result in newly created handler.
Instead, place variables in the task parameters of your handler. You can load the values using like this:
Handlers can also “listen” to generic topics, and tasks can notify those topics as follows:
handlers - name Restart memcached ansible.builtin.service name memcached state restarted listen "restartwebservices" - name Restart apache ansible.builtin.service name apache state restarted listen "restartwebservices" tasks - name Restart everything ansible.builtin.command echo "this task will restart the web services" notify "restartwebservices"
This use makes it much easier to trigger multiple handlers. It also decouples handlers from their names,
making it easier to share handlers among playbooks and roles (especially when using 3rd party roles from
a shared source like Galaxy).
Note
-
Handlers always run in the order they are defined, not in the order listed in the notify-statement. This is also the case for handlers using listen.
-
Handler names and listen topics live in a global namespace.
-
Handler names are templatable and listen topics are not.
-
Use unique handler names. If you trigger more than one handler with the same name, the first one(s) get overwritten. Only the last one defined will run.
-
You can notify a handler defined inside a static include.
-
You cannot notify a handler defined inside a dynamic include.
-
A handler can not run import_role or include_role.
When using handlers within roles, note that:
-
handlers notified within , , and sections are automatically flushed at the end of section where they were notified.
-
handlers notified within section are automatically flushed at the end of section, but before any handlers.
-
handlers are play scoped and as such can be used outside of the role they are defined in.
Ошибки управления блоками
Вы также можете использовать блоки для определения ответов на ошибки задачи. Этот подход похож на обработку исключений во многих языках программирования. См. Подробности и примеры в разделе .
См.также
-
Введение в плейбуки
-
Советы и трюки для плейбуков
-
Условные заявления в пьесах
-
Все о переменных
- Список рассылки
-
У тебя есть вопрос? Заходите в Google-группу!
- irc.libera.chat
-
#ansible IRC чат-канал
2012–2018 Майкл ДеХан 2018–2021 Red Hat, Inc.Лицензируется по версии 3 Стандартной общественной лицензии GNU.https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html