Lesson 7 of 11 ↓
- 1.Ansible Basic Setup Guide
- 2.Ansible Inventory Guide (hosts)
- 3.Ansible Configuration Guide (ansible.cfg)
- 4.Ansible Ad-hoc Commands Guide
- 5.Ansible Playbook Guide (playbook.yml)
- 6.Ansible Variables & Precedence Guide
- 7.Ansible Loops Guide
- 8.Ansible Conditionals Guide (when)
- 9.Ansible Vault Guide
- 10.Ansible Handlers Guide
- 11.Ansible Custom Roles Guide
6 min read
Ansible Loops Guide
A comprehensive guide to understanding and using Loops in Ansible. This document covers everything from basic iteration to complex dictionary loops, designed for beginners and professionals.
What are Loops in Ansible?
Loops allow you to repeat a task multiple times without writing the same code over and over.
-
Instead of writing 5 tasks to install 5 packages, you write one task and loop over a list of 5 items.
-
The Magic Variable:
{{ item }}. Inside a loop, Ansible uses this variable to represent the current value being processed.
Part 1: Basic List Loops
Install Multiple Packages
Instead of running yum five times, we pass a list to the module.
- name: Install essential packages
hosts: all
become: true # Root access required for installation
tasks:
- name: Install packages
yum:
name: "{{ item }}" # Takes the current value from the loop
state: present # Ensures package is installed
loop: # The list of items to iterate over
- git
- vim
- curlExplanation of Arguments:
-
name: "{{ item }}": This is dynamic. In the first run, it becomesgit, thenvim, thencurl. -
state: present: Standard argument to ensure software is installed. -
loop: The modern keyword for looping (replaceswith_items).
Create Multiple Users
Creating users one by one is tedious. Loops make it instant.
- name: Create user accounts
hosts: all
become: true
tasks:
- name: Add users
user:
name: "{{ item }}"
state: present
loop:
- alice
- bob
- charlieWhy is this important?
- Scaling: If you need to add 50 users, you just add their names to the list. You don't change the logic code.
Create Multiple Directories
You can use loops to create standard folder structures on servers.
- name: Create directories
hosts: all
become: true
tasks:
- name: Make folders
file:
path: "/opt/{{ item }}" # Concatenates string with item
state: directory # Tells 'file' module to create a folder
mode: '0755' # Sets permissions (rwxr-xr-x)
loop:
- app
- logs
- backupResult:
-
Creates
/opt/app -
Creates
/opt/logs -
Creates
/opt/backup
Create Files with Content
You can loop over strings to create simple files or data.
- name: Create files with predefined content
hosts: all
become: true
tasks:
- name: Create files
copy:
dest: "/tmp/{{ item }}.txt"
content: "This is file {{ item }}" # Dynamic content inside the file
loop:
- file1
- file2
- file3Result:
-
/tmp/file1.txtcontains "This is file file1" -
/tmp/file2.txtcontains "This is file file2"
Part 2: Complex Loops (dictionaries)
Sometimes a simple list isn't enough. You might need to pair data (e.g., Username + UserID). We use Dictionaries (Key-Value pairs) for this.
Loop Over Dictionaries
- name: Add users with specific UIDs
hosts: all
become: true
tasks:
- name: Create users with custom UID
user:
name: "{{ item.name }}" # Access the 'name' key
uid: "{{ item.uid }}" # Access the 'uid' key
state: present
loop:
- { name: devops, uid: 1101 }
- { name: qa, uid: 1102 }Detailed Explanation:
-
The List: The
loopcontains items that are objects{...}, not just strings. -
Accessing Data:
-
{{ item }}is the whole object:{ name: devops, uid: 1101 }. -
{{ item.name }}gives youdevops. -
{{ item.uid }}gives you1101.
-
Part 3: Legacy vs Modern
Use with_items (legacy Loop)
Before Ansible 2.5, with_items was the standard. You will see this in older tutorials and existing codebases.
- name: Create users using with_items
hosts: all
become: true
tasks:
- name: Add users
user:
name: "{{ item }}"
state: present
with_items: # Old syntax
- user1
- user2Difference:
-
Functionality: Identical for simple lists.
-
Recommendation: Use
loopfor new playbooks. Usewith_itemsonly when maintaining old code.
Part 4: Advanced Loop Features (must Know!)
Here are some advanced tricks that make your output cleaner and your playbooks smarter.
Loop Control (clean Output)
When looping over complex dictionaries, the output on the screen can get messy/huge. Use label to show only what matters.
- name: Create users with clean output
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
loop:
- { name: devops, uid: 1101, group: admin, shell: /bin/bash }
- { name: qa, uid: 1102, group: testers, shell: /bin/sh }
loop_control:
label: "{{ item.name }}" # Only shows the name in the terminal output
Retry Loops (do-until)
Very useful for checking if a service is up (e.g., waiting for a Database to start).
- name: Check if web server is up
uri:
url: "http://localhost"
status_code: 200
register: result
until: result.status == 200 # Keep looping UNTIL this is true
retries: 5 # Try 5 times
delay: 10 # Wait 10 seconds between tries
Part 5: Looping Over External Variables
Hardcoding lists in your playbook (as seen in Part 1) is fine for small tests, but for production, you should keep data separate from logic.
The Variable File (vars.yml)
Create a file solely for your data:
# vars.yml
my_packages_list:
- git
- vim
- curl
- htop
The Playbook (main.yml)
Load the file using vars_files and pass the variable name to loop.
- name: Install packages from external file
hosts: all
become: true
vars_files:
- vars.yml # Import the variables file
tasks:
- name: Install packages
yum:
name: "{{ item }}"
state: present
loop: "{{ my_packages_list }}" # Loop over the list defined in vars.yml
Why do this?
-
Clean Code: Your playbook logic remains simple and doesn't get cluttered with long lists.
-
Security: You can encrypt
vars.ymlwith Ansible Vault if it contains sensitive data (like passwords), while keepingmain.ymlreadable.
Complex Dictionaries in Variables (with Loop Control)
You can also move complex lists (dictionaries) to the variable file and use loop_control to keep the output clean.
The Variable File (vars.yml):
users_list:
- name: devops
uid: 1101
group: admin
shell: /bin/bash
- name: qa
uid: 1102
group: testers
shell: /bin/shThe Playbook (main.yml):
- name: Create users from external variable
hosts: all
become: true
vars_files:
- vars.yml
tasks:
- name: Create users
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
loop: "{{ users_list }}"
loop_control:
label: "{{ item.name }}" # Still works perfectly with variables!Summary Checklist
| Keyword | Use Case |
|---|---|
loop |
Standard iteration. The default for everything. |
{{ item }} |
The variable that holds the current value. |
{{ item.key }} |
Used when looping over dictionaries/hashes. |
with_items |
Old syntax. Still works, but loop is preferred. |
loop_control |
Used to limit/clean up the text output in the terminal. |
until / retries |
Used to repeat a task until it succeeds (Retry logic). |
vars_files |
Used to import lists from external files for cleaner playbooks. |
Comments
Loading the discussion…