Ansible Best Practices

Ansible is a tool that automates configuration management through code written in YAML. It is extremely popular, partly thanks to the fact that it works without clients and daemons: all it needs is Python and an SSH connection!

Since the YAML syntax is quite user-friendly, it is fairly easy to get started with Ansible. However, without a thorough introduction to the formats and structures of Ansible, the initial result is usually “bad” code: it might work, but it is prone to yield errors in the future, be inefficient or simply unreadable.

In this article, we want to present a few of the Ansible best practices that we deem especially important. This is a taste of what we discuss during our Ansible trainings at ATIX. If you are interested in learning Ansible from the ground up with a hands-on approach, do not hesitate to contact us for more information about our trainings.


  • Nutzen Sie true anstelle von yes und false anstatt no

  • Setzen Sie pro eingerückter Ebene zwei Leerzeichen (nicht vier und NIEMALS Tabs!)

  • Vermeiden Sie Listen und Dictionaries innerhalb einer Zeile

  • Brechen Sie Zeilen um, wenn sie länger als 80 Zeichen sind:

    1 a_string: > # transforms linebreaks to spaces
    4  ar3xxbJ9p0qa7R3fasdAS0YxwzaFME
    5  1IAADs=
    7 # this string doesn't have spaces
    8 a_folded_string_without: "R0lGO2313DdhDQAIAIAAAAAAANn
    9                                                   Z2SwAAAAAsdasfDQAIAAACF4SDGQ
    10                                                   ar3xxbJ9p0qa7R3fasdAS0YxwzaFME
    11                                                   1IAADs="


  • Task names:

    • Always give a name to each task

    • Start the name with a capital letter

    • Ensure the name describes the task appropriately; for example “Install Apache” instead of “Install stuff”

  • Use dictionary style in playbooks, for example:

    1 # avoid this
    2 - name: Install Apache packages
    3   yum: name="{{ packages }}" state=present
    4   vars:
    5     packages:
    6       - httpd
    7       - httpd-devel
    9 # use this instead
    10 - name: Install Apache packages
    11   yum:
    12     name: "{{ packages }}"
    13     state: present
    14   vars:
    15     packages:
    16       - httpd
    17       - httpd-devel
  • Use the fully qualified collection name (FQCN), e.g., ansible.builtin.debug instead of debug

  • Apply privilege escalation at task level, not at play level

  • Try to avoid the modules ansible.builtin.command, and these modules are not idempotent! If you have no other option, try to work with changed_when, failed_when and (if applicable) creates and removes to make your tasl as idempotent as possible


  • Verschlüsseln Sie alle vertraulichen Variablen/Dateien mit ansible-vault

  • Speichern Sie das Vault-Passwort an einem sicheren Ort, z.B. als Jenkins Secret oder mit Hilfe eines externen Secret Manager, wie z.B. der Vault von HashiCorp

  • Wenn Sie eine ganze Datei verschlüsseln, kann es sein, dass Sie die Namen Ihrer Variablen vergessen => führen Sie eine Vermittlungsvariable zur besseren Lesbarkeit ein, z.B.:

    1 ---
    2 # vault.yaml
    3 vaulted_password: this_will_be_encrypted
    1 ---
    2 # vars.yaml
    3 password: "{{ vaulted_password }}"

Reusing Ansible Code

  • Separate your tasks into files and then import/include them in your playbook

  • As there are some important differences between import_tasks and include_tasks (see this table), try to use import_tasks when possible

  • In general, go for import_*, especially because

    • --list-tasks also shows the imported tasks (and --start-at-task works as intended)

    • --list-tags also shows the tags of the imported tasks

    • notify of imported tasks works (careful: you should notify one of the imported tasks, not the import_tasks task itself!)

    • the options of the import_* are passed to ALL child tasks

  • You should use include_* when

    • you want to loop over tasks

    • the name of the file to be included depends on a variable, for example {{ ansible_os_family }}.yaml

    • you want to apply an option ONLY to the include_* task


  • Collect Ansible content meant for reuse in future projects into roles

  • Use one of the two options to define variables within a role—defaults and vars:

    • vars refers to variables that are not supposed to be changed by the user

    • defaults refers to variables that can be easily overridden by the user

  • Add a prefix to the variables in a role to indicate to which role they belong, for example postgresql_version for a variable defined in a postgresql role (this is especially useful when you are working with multiple roles at once)

  • If you use ansible-galaxy init my-role to initialize a role, don’t forget to remove all unused directories in the end


Include a line at the beginning of your templates to show which role generated these files. For this purpose, the variable ansible_role is very useful; for example, your template could start like this:

1 # this file was created from the role: {{ansible_role}}
2 ***here comes your actual template***
  • Use the ansible_managedfeature if you want to make it clear to other users that a specific file is generated by Ansible: you can define a variable named ansible_managed in the Ansible configuration (ansible.cfg)—see this minimal example of such an ansible.cfg:

    1 [defaults]
    2 ansible_managed: Ansible managed: {file} modified
    3 on %Y-%m-%d %H:%M:%S by {uid} on {host}
  • o make sure your template includes information about who generated it at what time, write this variable at the beginning of your templates:

    1 # {{ansible_managed}}
    2 # this file was created from the role: {{ansible_role}}
    3 ***your actual template***


As you can see, Ansible covers a wide range of topics. There are many places where you have to be careful in order to write elegant code and save yourself more work down the road.

We hope that this serves as a good reference and can help you in your future Ansible endeavours.

If you have any questions or would like more guidance on any of these specific topics, do not hesitate to contact us.

Ansible Training

The Ansible Training – “Fast Track” teaches participants how to manage infrastructures with Ansible as well as the basic concepts and best practices of Ansible. The “Ansible Extended Training” also offers an additional day where the trainer can specifically address individual questions and needs of the participants.

The following two tabs change content below.

Ottavia Balducci

Latest posts by Ottavia Balducci (see all)