Ansible playbook execution strategies
By default, Ansible uses five forks to run each task on all hosts impacted by a play before beginning the subsequent task on any host. You can use a different strategy plugin, adjust the number of forks, or apply one of various keywords, like serial, to modify this default behavior.
Selecting a strategy
The linear strategy is the default behavior that was previously mentioned. Ansible has other strategies, such as the debug strategy (see to Debugging tasks) and the free strategy, which permits every host to run as quickly as possible until the play's conclusion:
- hosts: all
strategy: free
tasks:
# ...
Here we see that you can choose a different play strategy for each, or you can define your preferred play strategy globally in ansible.cfg
, in the defaults stanza:
[defaults]
strategy = free
Forks
You can set the number in ansible.cfg
or pass it on the command line: ansible-playbook -f 25 run.yml
if you have the processing capability to use more forks.
[defaults]
forks = 25
Keywords
Some keywords also have an impact on play execution in addition to tactics. With serial
, you can specify a number, a percentage, or a list of hosts that you wish to handle at once. Before beginning the next group of hosts, Ansible finishes the play on the designated number or percentage of hosts. Using throttle
, you may limit how many workers are assigned to a block or job. Ansible gives you control over how it chooses which host in a group to execute against next when using order. The run_once
allows you to execute a job on a single host. While these terms don't represent strategies, they are instructions or choices that are applied to a task, block, or activity.
There are also other keywords that impact the way a play is executed, such as any_errors_fatal
, ignore_errors
, and ignore_unreachable
.
Setting the batch size
Ansible operates against all hosts in the pattern you specify in the hosts: field of each play by default, running in parallel. You can specify how many hosts Ansible should handle at once with the serial keyword if you only want to control a small number of machines at once, for instance during a rolling update:
- name: test play
hosts: weblogic
serial: 3
gather_facts: False
tasks:
- name: first task
command: hostname
- name: second task
command: hostname
Here, Ansible would finish the play (both jobs) on three of the six hosts in the group "weblogic" before going on to the remaining three hosts:
PLAY [weblogic] ***********************************************************************
TASK [first task] ***********************************************************************
changed: [web1]
changed: [web3]
changed: [web2]
TASK [second task] **********************************************************************
changed: [web1]
changed: [web2]
changed: [web3]
PLAY [weblogic] ***********************************************************************
TASK [first task] ***********************************************************************
changed: [web4]
changed: [web5]
changed: [web6]
TASK [second task] **********************************************************************
changed: [web4]
changed: [web5]
changed: [web6]
PLAY RECAP ******************************************************************************
web1 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web3 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web4 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web5 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web6 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Note
When the batch size is set to serial, Ansible failures only affect the batch size and not the full host list. To change this behavior, use max_fail_percentage
or ignore_unreachable
.
With the serial
keyword, a percentage can also be specified. To calculate the number of hosts each pass, Ansible multiplies the percentage by the total number of hosts in a play:
- name: test play
hosts: weblogic
serial: "30%"
If the number of hosts does not divide equally into the number of passes, the final pass contains the remainder. Here, if you had 20 hosts in the weblogic group, the first batch would contain 6 hosts, the second batch would contain 6 hosts, the third batch would contain 6 hosts, and the last batch would contain 2 hosts.
You can also specify batch sizes as a list:
- name: test play
hosts: weblogic
serial:
- 1
- 5
- 10
Here, there would be one host in the first batch, five hosts in the next, and (assuming any hosts were left) all of the hosts in each subsequent batch, if there were fewer than ten hosts left.
You can list multiple batch sizes as percentages:
- name: test play
hosts: weblogic
serial:
- "10%"
- "20%"
- "100%"
You can also mix and match the values:
- name: test play
hosts: weblogic
serial:
- 1
- 5
- "20%"
No matter how small the percentage, the number of hosts per pass will always be 1 or greater.
Restricting execution with throttle
The throttle
keyword sets a cap on how many workers can run on a given task. Both the task and block levels can have it configured. To limit CPU-intensive tasks or tasks that communicate with a rate-limiting API, use throttle:
tasks:
- command: /usr/bin/binary
throttle: 1
Ordering
The order
keyword controls the order in which hosts are run. Possible values for order are:
inventory:
#(default) The order provided by the inventory for the selection requested (see note below)
reverse_inventory:
#The same as above, but reversing the returned list
sorted:
#Sorted alphabetically sorted by name
reverse_sorted:
#Sorted by name in reverse alphabetical order
shuffle:
#Randomly ordered on each run
The "order in which a selection is returned from the compiled inventory" is what is meant to be understood as the "inventory" order, not the order in which hosts or groups are defined in the inventory source file. Although replicable, this option is not typically predictable and is backwards compatible. It is nearly impossible to return such an order because to the nature of inventory, host patterns, restrictions, inventory plugins, and the flexibility to enable numerous sources. This may coincide with the file definition order in straightforward circumstances, but it is not a given.
Running on a single machine
If you want a task to run only on the first host in your batch of hosts, set run_once
to true on that task:
# ...
tasks:
# ...
- command: /usr/bin/binary
run_once: true
# ...
Ansible executes this task on the first host in the current batch and applies all results and facts to all the hosts in the same batch. This approach is similar to applying a conditional to a task
Ref: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html
Top comments (0)