Subscribe to the feed

Ansible is a powerful open source tool that helps you automate many of your IT infrastructure operations, from the smallest of tasks to the largest. Ansible has hundreds of modules to help you accomplish your configuration needs, both official and community-developed. When it comes to complex and lengthy workflows, though, you need to consider how to optimize the way you use these modules so you can speed up your playbooks.

Previously, I wrote about making your Ansible playbooks run faster. Here are five ways I make my Ansible modules work faster for me.

[ New to automation or looking to boost your skills? Sign up for the free online Ansible Basics course. ]

1. Use multiple tasks in a single module and avoid module loops

It's easy to fall into linear thinking. For instance, you might want to install several packages, so you might think to do this in a terminal:

# Multiple `dnf` commands
$ sudo dnf install httpd
$ sudo dnf install firewalld
$ sudo dnf install git

But you can do the same thing more efficiently:

$ sudo dnf install -y httpd firewalld git

The same strategy applies to Ansible playbooks. Instead of installing packages using multiple yum or dnf modules, you can pass multiple packages to a single yum task.

This might be your old method:

- name: Install httpd
  ansible.builtin.yum:
    name: httpd
 
- name: Install firewalld
  ansible.builtin.yum:
    name: firewalld
 
- name: Install git
  ansible.builtin.yum:
    name: git

Or maybe you did this:

- name: Install Pacakages
  ansible.builtin.yum:
    name: "{{ item }}"
    state: latest
  loop:
    - httpd
    - firewalld
    - git

But the better and more efficient method is this:

- name: Install httpd and firewalld
  ansible.builtin.yum:
    name: 
      - httpd
      - firewalld
      - git
    state: latest

2. Avoid copy loops and use the synchronize module

When you have multiple files to copy into the same directory, synchronize modules rather than using multiple copy modules or loops:

- name: Copy application data
  synchronize:
    src: app_data/
    dest: /opt/web_app/data

3. Use the latest version of Ansible and its modules

Most of the time, new versions of Ansible include performance and optimization improvements. If possible, use the latest compatible version of Ansible for your environments to ensure you're getting the most recent features. Also, update your modules and roles or Ansible collections to get the current features and bug fixes.

Make sure you've tested the latest version of the module and Ansible before pushing to production and critical environments to avoid breaking any existing functionalities.

[ Get the latest on Red Hat Ansible Automation Platform 2 in this interactive guide. ]

4. Make configuration templates

You might use multiple lineinfile and blockinfile tasks to manage and configure a single file. This approach creates a very long playbook. And when there's configuration drift, you must edit this lineinfile task with a different regex. However, you can use a Jinja2 template to create any level of complex files and use the template module (or filter) to configure managed nodes.

For instance, you can copy a complex Nginx web server configuration using the template module with a Jinja2 template.

Your Jinja2 template: nginxd.conf.j2

# nginx configuration for wp-test
server {
    root /var/www/{{ website_root_dir }};
    index index.php index.html index.htm;
    server_name {{ website_name }}.com www.{{ website_name }}.com;
    access_log /var/log/nginx/access_{{ website_name }}-com.log;
    error_log /var/log/nginx/error_{{ website_name }}-com.log;
...<output removed>...
    ssl_certificate /etc/letsencrypt/live/{{ website_name }}.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/{{ website_name }}.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = www.{{ website_name }}.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
...<output removed>...
    server_name {{ website_name }}.com www.{{ website_name }}.com;
    return 404; # managed by Certbot
}

The template module replaces the variable (the code {{ website_root_dir }}) with values provided in your playbook:

---
- name: Configure the nginx Web Server
  hosts: web_servers
  become: True 
  vars:
    website_name: myawesomeblog
    website_root_dir: /var/www/myawesomeblogdata
  tasks:
    - name: Copy nginx configuration
      template:
        src: nginxd.conf.j2
        dest: /etc/nginx/sites-enabled/{{ website_name }}.conf

5. Use appropriate modules and avoid using shell or command modules

You can use Ansible shell or command modules to run basic Linux commands. It is highly recommended that you use appropriate modules and use these shell/command modules in the worst-case scenarios. The shell (or command) modules will simply execute the command without any validations, and most of the time, you need to take care of idempotency and error checks.

For example, the first task below (with shell) simply overwrites the file's content without checking or validating, but the second task (with the copy module) changes the file only if required, and it also updates the permissions and ownership of the destination file.

    - name: Create file using shell module
      shell: 'echo "Hello" > /tmp/foo.conf'
      
    - name: Create file with permission using file module
      ansible.builtin.copy:
        content: "Hello"
        dest: /tmp/foo.conf
        owner: root
        group: root
        mode: '0644'

Bonus: Optimize your syntax

Using appropriate modules and module arguments in your playbook saves a lot of time and avoids complications. Refer to the latest module documentation, whether it's in the official Ansible docs or elsewhere, to ensure that the keys and values you remember from the last time you used the module are still valid.

Optimization is a journey

The modules you select and how you use them can affect the global execution time of your Ansible playbooks. But that means each module is an opportunity to optimize your playbook, refine the process, and maximize automation speed.

This isn't a complete list, of course. You can use many other parameters to control and optimize your Ansible playbook execution, such as serial, throttle, run_once, and more. Refer to the documentation to learn more and apply optimization techniques based on your Ansible environment.


About the author

Gineesh Madapparambath is a Platform & DevOps Consultant at Red Hat Singapore, specializing in automation and containerization with Ansible and OpenShift. 

He has worked as a Systems Engineer, Automation Specialist, and content author. His primary focus is on Ansible Automation, Containerization (OpenShift and Kubernetes), and Infrastructure as Code (Terraform). He is the author of the book "Ansible for Real-Life Automation".

 

Read full bio
UI_Icon-Red_Hat-Close-A-Black-RGB

Browse by channel

automation icon

Automation

The latest on IT automation for tech, teams, and environments

AI icon

Artificial intelligence

Updates on the platforms that free customers to run AI workloads anywhere

open hybrid cloud icon

Open hybrid cloud

Explore how we build a more flexible future with hybrid cloud

security icon

Security

The latest on how we reduce risks across environments and technologies

edge icon

Edge computing

Updates on the platforms that simplify operations at the edge

Infrastructure icon

Infrastructure

The latest on the world’s leading enterprise Linux platform

application development icon

Applications

Inside our solutions to the toughest application challenges

Virtualization icon

Virtualization

The future of enterprise virtualization for your workloads on-premise or across clouds