Skip to content
All posts

How to Optimize Ansible Performance with Execution Strategies: Best Practices for IT Automation

A futuristic network diagram showcasing interconne

When it comes to Ansible, choosing the right Ansible strategies can drastically optimize Ansible performance, improve resource usage, and ensure efficient task completion across multiple hosts. In this blog, we’ll explore Ansible linear strategy, serial execution, and the free strategy, and see how these different approaches can impact automation.

We will also discuss how these strategies contribute to task concurrency and performance optimization through the use of forks, pipelining, and other Ansible techniques.

What are Ansible Execution Strategies? Understanding Ansible Playbook Strategies for Automation Efficiency

Ansible execution strategies control how tasks are processed across multiple hosts in your inventory. Choosing the right Ansible playbook strategies ensures that automation is executed efficiently and predictably. These strategies help you manage automation workflows more effectively by dictating how tasks are executed—either sequentially, concurrently, or in batches.

Ansible offers three core strategies: linear (default), free, and serial (not a strategy but a keyword).

Each of these modes has a specific purpose for different types of workloads.

What is the Ansible Linear Strategy?

The Ansible Linear Strategy is the default execution strategy used in Ansible playbooks, designed to ensure that tasks are executed in a sequential and predictable order across all hosts.  This means that Ansible will complete each task on every host before moving on to the next task.

How Ansible Linear Strategy Works

In the linear strategy, if you define 100 hosts in your inventory, Ansible will perform task 1 on all 100 hosts before moving to task 2. This ensures that all hosts are at the same step in the process at any given time.

Use Case

As discussed previously, this strategy is ideal for scenarios where tasks have dependencies on one another. For instance, if a web server must be configured before a database server, the linear strategy ensures that the web server setup is completed first, preventing potential errors due to unmet dependencies.

Example Configuration

- hosts: all
  tasks:
    - name: Install Apache
      yum: name=httpd state=present
    - name: Start Apache
      service: name=httpd state=started

 

Pros of the Linear Strategy

  • Consistency: Ensures every task is completed across all hosts before moving to the next. Ideal for roles with dependent tasks.
  • Order of Execution: Useful when task order matters, such as configuring servers or updating plugins in sequence.
  • Simpler Debugging: Issues are easier to track since failures occur in a predictable order.

Cons of the Linear Strategy

  • Slower Execution: Tasks on faster nodes must wait for slower hosts, introducing delays.
  • Less Parallelism: No task concurrency; hosts wait for each other to complete each task.

What is the Ansible Free Strategy?

The free strategy enables tasks to run independently on each host without waiting for other hosts to complete the same task. This means that as soon as a task finishes on one host, the next task will begin, regardless of whether the other hosts have completed the previous task. This significantly optimizes Ansible performance by maximizing concurrency and reducing execution time.

How Ansible Free Strategy Works:

The free strategy is particularly useful for optimizing execution times in large-scale environments with a diverse range of hosts or servers.

Use Case

As we saw earlier, this strategy is beneficial when tasks are independent of one another and can be executed in parallel without concern for completion order. For instance, collecting logs from multiple servers can be done simultaneously without waiting for each host to finish its logging task.

Configuration Example

In this scenario, each host will execute the logging command independently and as fast as possible.

- hosts: all
  strategy: free
  tasks:
    - name: Collect logs
      command: cat /var/log/syslog

 

Pros of the Free Strategy

  • Speed: Significantly reduces execution time by maximizing task concurrency.
  • Performance: Hosts do not need to wait for each other, making it ideal for large-scale deployments where hosts perform at different speeds.
  • Efficiency: Ideal for nodes that don’t rely on one another to complete tasks.

Cons of the Free Strategy

  • Unpredictability: Since tasks are not executed in the same order on each host, debugging can be more complex.
  • Not Suitable for Dependent Tasks: If your tasks require that one host waits for another, the free strategy is not the right choice.

What is the Ansible Serial Execution (Keyword)

The serial keyword isn’t an execution strategy itself but a way to control how many hosts are processed at once. It allows you to throttle the execution by defining the batch size of hosts to work on at any given time.

How Ansible Serial Execution Works:

When you use serial: 10, Ansible processes 10 hosts at a time for each task. After the first batch of hosts finishes, the next 10 will start, continuing until all hosts are complete.

Use Case

As pointed out above, this strategy is particularly useful in environments where changes could impact service availability or stability. For example, when updating software on redundant devices, you might want to update only a subset of devices at a time to maintain overall system functionality.

Configuration Example

This configuration ensures that only three hosts are updated simultaneously, allowing for monitoring and rollback if issues arise.

- hosts: all
  serial: 3 # Process three hosts at a time
  tasks:
    - name: Update software
      yum: name=myapp state=latest

 

Pros of Serial Execution

  • Resource Management: Avoids overwhelming resources by processing a limited number of hosts at a time.
  • Controlled Parallelism: Combines the benefits of both parallelism and order.
  • Fault Isolation: Easier to identify and address issues in smaller groups of hosts.

Cons of Serial Execution

  • Longer Execution Time: When using small batch sizes, serial execution can take longer than free strategy or default linear strategy.
  • Requires Tuning: Needs adjustment based on infrastructure and task concurrency capabilities.

Additional Keywords Affecting Execution

In addition to these strategies, Ansible provides several keywords that can further refine execution behavior:

  • throttle: Limits the number of concurrent tasks at the task level.
  • forks: Controls how many tasks can run in parallel across all hosts (default is 5). This can be increased in the ansible.cfg file or via command line options.
  • run_once: Executes a task only once regardless of the number of hosts targeted.
  • ignore_errors and ignore_unreachable: These options allow playbooks to continue executing even if some tasks fail or if some hosts are unreachable.

Learn more about these keywords and others in the comprehensive Ansible playbook keywords section.

How to make Ansible run faster?

To get the most out of Ansible's execution strategies, consider these optimizations:

  • Forks: Forks determine how many simultaneous processes Ansible creates. Adjust forks to optimize resource usage and concurrency.
  • ControlPersist: Enables SSH connections to remain persistent, reducing the time spent reconnecting for each task. Enable controlPersist to reduce SSH overhead by keeping connections open between tasks.
  • Pipelining: Enable pipelining to reduce the number of SSH connections, thereby accelerating task execution.
  • Task Blocks: Use block strategies for tasks that must run together or rollback on failure.
  • Throttling and Batch Size: Control concurrency by using the throttle keyword to limit the number of tasks running at a given time, preventing overwhelming your system resources.

Ansible Strategy Performance: Linear vs Serial vs Free

Linear Strategy

The linear strategy can lead to longer execution times, especially when dealing with a large number of hosts. For instance, a playbook that takes about 11 seconds to run on a single machine may take significantly longer when scaled up to 100 hosts due to the sequential nature of task execution. Reports indicate that such playbooks can take over 4 minutes for 97 machines, even with fast networking conditions.

Serial Execution

With Serial Execution you can improve overall performance by reducing the load on the control node and allowing for staggered updates across hosts. By updating only a subset of devices at a time, organizations can maintain service availability while still pushing updates efficiently.

Free Strategy

The free strategy maximizes parallelism and can significantly reduce execution time when tasks are independent of one another. This is particularly useful for operations like log collection or configuration checks where tasks do not depend on the completion of others.

How to Use Ansible Execution Strategies in Ansible Playbooks

Here’s a sample playbook demonstrating how to use both linear and serial execution for better task concurrency and resource management.

This example uses both linear strategy and serial execution to ensure tasks run sequentially but with a limited batch of hosts at a time. This combination optimizes orchestration while controlling system resources.

- name: Optimize Performance
  hosts: all
  strategy: linear
  serial: 5
  tasks:
    - name: Install Packages
      apt:
        update: True
        cache_valid_time: 3600
    - name: Upgrade Packages
      package:
        upgrade: yes
    - name: Restart Services
      service:
        name: my_service
        state: restarted
  forks: 10
  control_persist: True

Explanation of the Playbook

Execution Strategy: The playbook uses the linear strategy, which is the default in Ansible. This means tasks will be executed sequentially across all targeted hosts, ensuring that each task completes on all hosts before moving on to the next.

Serial Execution: By setting serial: 5, this playbook processes hosts in batches of five. This approach is beneficial for reducing the risk of downtime during updates, as it allows for staggered changes across the environment. For example, if you are upgrading packages on a large number of servers, processing them in smaller batches can help maintain service availability.

Task Definitions: The tasks defined include installing packages, upgrading them, and restarting services. Each task is executed in order, ensuring that dependencies are respected.

Performance Optimizations:

  • Forks: The forks parameter is set to 10, which allows Ansible to run up to ten tasks concurrently across the specified hosts. This can significantly speed up execution time when dealing with multiple hosts.
  • Control Persist: Setting control_persist to True keeps SSH connections open for a specified duration, reducing the overhead of establishing new connections for each task.

Additional Considerations

Throttling Execution: When using serial, it’s important to consider how many hosts are being processed simultaneously. If you have a large number of hosts and want to avoid overwhelming your network or control node, you may want to adjust the serial value accordingly.

Using Other Strategies: Depending on your use case, you might also explore other strategies such as:

  • Free Strategy: Allows tasks to run independently across all hosts, which can maximize parallelism when tasks are not dependent on one another.
  • Host Pinned Strategy: Similar to free but allows you to run tasks as fast as possible on a specified number of hosts before moving on.

Debugging and Error Handling: Incorporating error handling and debugging strategies can help identify issues during execution. For example, using ignore_errors can allow playbooks to continue running even if some tasks fail, which is useful in production environments .

Best Practices for Optimizing Ansible Playbook Performance: Ansible Block Strategy & Execution Strategies

To further optimize your playbooks and enhance performance:

Choose the Right Ansible Execution Strategy

Use linear for tasks requiring order, free for independent tasks, and serial for controlled batches.

Enable ControlPersist

Reduce SSH overhead by enabling persistent connections. This can significantly speed up playbook execution by keeping SSH connections open, which reduces the time spent establishing new connections for each task. Configure this in your ansible.cfg:

[ssh_connection] 
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

Utilize Forks

Adjust the forks parameter to balance resource usage and concurrency. The default value is 5, but increasing it allows Ansible to execute tasks on more hosts simultaneously, which can lead to faster completion times. Be mindful of your control node’s capacity when increasing this value:

[defaults] 
forks = 20

Pipelining

Enable pipelining to reduce the number of SSH operations required during playbook execution. This can significantly decrease execution time, especially in environments with many tasks:

[ssh_connection] 
pipelining = True

Task Blocks

Group related tasks together using task blocks. This not only improves readability but also enhances reliability by ensuring that all related tasks are executed as a single unit. If one task fails, you can handle errors more gracefully.

Disable Fact Gathering When Not Needed

By default, Ansible gathers facts about managed nodes before executing tasks, which can add unnecessary overhead if those facts are not used in the playbook. Disable this feature by setting gather_facts: False in your playbook:

hosts: all 
gather_facts: False 
tasks:name: Example Task 
command: echo "Hello World"

Identify Slow Tasks with Callback Plugins

Use callback plugins like timerprofile_tasks, and profile_roles to identify which tasks consume the most time during execution. This information can help you focus your optimization efforts where they will have the most impact.

Use Async Tasks for Long-Running Operations

For tasks that take a long time to complete (e.g., backups or installations), consider using asynchronous execution with a polling interval. This allows subsequent tasks to run without waiting for the long-running task to finish:

- name: Long Running Task 
command: /path/to/long_running_script.sh 
async: 300 # Maximum allowed time in seconds 
poll: 0 # Do not wait for completion

What's Next

Understanding and leveraging Ansible's execution strategieslinear, serial, and free—allows you to optimize playbook performance based on your infrastructure needs. By selecting the right strategy, you can optimize execution times, manage system resources effectively, and ensure that your automation tasks are completed efficiently.

🚀 Want to test and refine your Ansible automation in a real-world environment? Try CloudMyLab’s hands-on Ansible labs to validate your automation workflows before deploying them at scale. Start your free trial today!

More Resources