Debug School

Cover image for Ansible Execution Strategies
Suyash Sambhare
Suyash Sambhare

Posted on

Ansible Execution Strategies

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:
  # ...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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%"
Enter fullscreen mode Exit fullscreen mode

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.

Ansible

You can also specify batch sizes as a list:

- name: test play
  hosts: weblogic
  serial:
    - 1
    - 5
    - 10
Enter fullscreen mode Exit fullscreen mode

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%"
Enter fullscreen mode Exit fullscreen mode

You can also mix and match the values:

- name: test play
  hosts: weblogic
  serial:
    - 1
    - 5
    - "20%"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

    # ...
Enter fullscreen mode Exit fullscreen mode

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)