Skip to main content

10 habits of great Ansible users

Ansible makes it easier to create, share, and manage automation, but like any tool, some ways of using it are better than others.
Image
Colorful gears

Image by Pexels

Ansible is designed to be minimal, consistent, secure, and highly reliable, with an extremely low learning curve for administrators, developers, and IT managers. In other words, Ansible should be easy to work with, but there are still some ways of using it that are better than others.

[ Download now: A system administrator's guide to IT automation. ]

Whether you're writing playbooks, maintaining inventory, or executing tasks, here are 10 things to keep in mind as you implement enterprise-wide automation:

  1. Use version control
  2. Use whitespace and comments
  3. Give variables unique and meaningful names
  4. Use roles to keep playbooks well-organized
  5. Troubleshoot on execution
  6. Use block syntax
  7. Use a separate inventory file for staging and production
  8. Understand the serial keyword for rolling updates
  9. Use native modules when possible
  10. Keep debugging messages clean

This article is a combination of advice pulled from official Ansible documentation and two presentations by Ansible experts: Ansible best practices: the essentials and Ansible best practices: How to write, how to execute, and how to use in real life). You don't need to treat them as gospel. Some of these practices may not fit your specific use case, and that's okay! If nothing else, you'll have a solid baseline of Ansible knowledge from which to build your skills.

1. Use version control

Using version control is a standard practice when coding, and Ansible is no different. Be sure to keep playbooks, roles, inventory, and variables files in Git or another version control system, and make commits often.

2. Use whitespace and comments

Ansible uses YAML for writing playbooks, and whitespace characters (literal space characters) are what YAML uses to define document structure and denote nesting. Tabs are not allowed.

For example:

foo: bar
     dah: dum
     lah:
       dee: dah
       dah: dee

is translated into Python (using the PyYAML library) as:

foo : bar
dah : dum
lah : {'dee': 'dah', 'dah': 'dee'}

Using comments is another best practice that can help you meaningfully describe lines of code. Don't overuse them—the more clear the comment, the better! In YAML, comments begin with a pound (or hash) sign:

# This is a comment

[ Want to learn more? Start the Ansible Basics: Automation technical overview course. ]

3. Give variables unique and meaningful names

Add the role name to a variable as a prefix to avoid name conflicts and confusion.

For example:

apache_max_keepalive: 25
apache_port: 80
tomcat_port: 8080

Instead of:

max_keepalive: 25
port: 80
port: 8080

[ Check out a personalized skill path for becoming a Red Hat Certified Specialist in Ansible Network Automation. ]

4. Use roles to keep playbooks well-organized

While there are many possible ways to organize playbook content, one crucial way is with Ansible’s roles organization feature. Here is an example role directory structure:

site.yml
webservers.yml
fooservers.yml
roles/
    common/
        tasks/
        handlers/
        files/
        templates/
        vars/
        defaults/
        meta/
    webservers/
        tasks/
        defaults/
        meta/

5. Troubleshoot on execution

If you're looking to test new plays or do some debugging, there are a few alternative ways to run playbooks in Ansible. Using these switches can help you catch problems in your code more quickly. Here is a breakdown of a few:

  • -vvvv enables connection debugging.
  • --step causes Ansible to stop on each task and ask if it should execute that task.
  • --check enables check mode, where Ansible runs without making any changes on remote systems.
  • --diff enables diff mode, where Ansible provides before-and-after comparisons.
  • --start-at-task starts executing your playbook at a particular task.

6. Use block syntax

You can use Ansible blocks to group tasks logically. Blocks make it much easier to set data or directives common to a bunch of tasks, organize code, and enable rollbacks for critical changes.

Tasks:
   - name: Install, configure, and start Apache
     block:
       - name: install httpd and memcached
         yum:
           name:
           - httpd
           - memcached
           state: present

       - name: apply the foo config template
         template:
           src: templates/src.j2
           dest: /etc/foo.conf
       - name: start service bar and enable it
         service:
           name: bar
           state: started
           enabled: True
     when: ansible_facts['distribution'] == 'CentOS'
     become: true
     become_user: root
     ignore_errors: yes

     ignore_errors: yes

7. Use a separate inventory file for staging and production

You don't want to run a play on a group of servers only to realize a day later that you've just pushed experimental changes into production. To avoid these sorts of surprises, use separate inventory files for staging and production instead of maintaining everything in a single inventory file. For example:

|----inventories/   
|    |--dev/
|    |  |--group_vars/...
|    |  |--host_vars/...
|    |--prod/
|       |--group_vars/...
|       |--host_vars/
|            |--my_playbook_hostname_vars.yml
|----roles/...     
|----hosts.yml    
|----my_playbook.yml  
|

8. Understand the serial keyword for rolling updates

You can control how many machines you update at once in the batch with the serial keyword. By default, Ansible tries to manage all the devices referenced in a play in parallel. For a rolling update use case, you can define how many hosts Ansible should manage at a single time by using the serial keyword:

---
- name: test play
  hosts: webservers
  serial: 2
  gather_facts: False

  tasks:
    - name: task one
      command: hostname
    - name: task two
      command: hostname

9. Use native modules when possible

Ansible's goal is to make things as easy and convenient as possible. So while you can use commands such as command , shell , raw , and script to do command-line operations, using them excessively could lead to problems down the line. It's best to use run commands sparingly since there are hundreds of native Ansible modules that can do what you need.

[ Explore Red Hat Enterprise Linux Automation with the Ansible training course. ]

10. Keep debugging messages clean

While useful for debugging variables or expressions, the debug module can clutter the output. It's best practice to remove these lines of code before your playbook goes into production. You can also control when the debug is run with a verbosity parameter. For example, if you set it to 3, it will only run debug when you run -vvv.

- debug:
   msg: "I always display!"

- debug:
   msg: "I only display with ansible-playbook -vvv+"
   verbosity: 3

Learn more

Ansible enables users across an organization to create, share, and manage automation, but like any tool, some ways of using it are better than others.

If you're looking for further Ansible expertise, check out the resources below.

Topics:   Ansible   Automation   Troubleshooting  
Author’s photo

Bill Cozens

Bill Cozens is a recent UNC-Chapel Hill grad interning as an Associate Blog Editor for the Red Hat Blog. More about me

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.