Ansible Playbook Examples
This page showcases practical, real-world Ansible playbook examples organized by use case. Each example includes the full YAML code and brief explanations to help you understand and adapt them for your infrastructure automation needs.
1. Web Server Setup
Nginx Configuration and Deployment
This playbook installs nginx, configures virtual hosts, manages symbolic links, and deploys static website content.
---
- hosts:
become: true
tasks:
- name: Checking nginx is at the latest version
apt: name=nginx state=latest
- name: starting nginx service
service:
name: nginx
state: started
- name: nginx config file copy and service restart
copy:
src: /home/foo/static_site.cfg
dest: /etc/nginx/sites-available/static_site.cfg
- name: creating symbolic-link
file:
src: /etc/nginx/sites-available/static_site.cfg
dest: /etc/nginx/sites-enabled/default
state: link
- name: Copying the content of the web site of just copy index.html
copy:
src: /home/foo/static-site-src/
dest: /home/foo/static-site
- name: restarting the nginx service
service:
name: nginx
state: restarted
Key Concepts:
- Uses
become: truefor elevated privileges - Manages package updates with
aptmodule - Handles service lifecycle with
servicemodule - Creates symbolic links for site configuration
- Copies static content to web root
2. Container Management
Docker and Docker Compose Installation
This playbook automates Docker and Docker Compose installation on CentOS, with checks to skip reinstallation if already present.
---
- name: Install Docker and Docker Compose on CentOS
hosts: '{{ host }}'
become: true
tasks:
- name: Upgrade all packages
yum: name=* state=latest
- name: Check if Docker is installed
command: systemctl status docker
register: docker_check
ignore_errors: yes
- name: Download the Docker installer
get_url:
url: https://get.docker.com/
dest: /root/install_docker.sh
mode: 0700
when: docker_check.stderr.find('service could not be found') != -1
- name: Install Docker
shell: /root/install_docker.sh
when: docker_check.stderr.find('service could not be found') != -1
- name: Remove the Docker installer file.
file:
state: absent
path: /root/install_docker.sh
- name: Enable the Docker daemon in systemd
systemd:
name: docker
enabled: yes
masked: no
- name: Start the Docker daemon
systemd:
name: docker
state: started
masked: no
- name: Check if Docker Compose is installed
command: docker-compose --version
register: docker_compose_check
ignore_errors: yes
- name: Download and install Docker Compose
get_url:
url: https://github.com/docker/compose/releases/download/1.24.0/docker-compose-Linux-x86_64
dest: /usr/bin/docker-compose
mode: 0755
when:
- docker_compose_check.msg is defined
- docker_compose_check.msg.find('No such file or directory') != -1
- name: Clone repo
git:
repo: https://github.com/syedsaadahmed/DevOps-Homework.git
dest: /home
Key Concepts:
- Uses
registerto capture command output for conditional logic - Leverages
ignore_errors: yesto handle expected failures - Downloads and executes installation scripts
- Manages systemd services with proper enablement
- Clones git repositories for application deployment
3. System Administration
Server Reboot with Wait
Demonstrates asynchronous task execution, server reboot, and waiting for the server to come back online.
---
- hosts:
become: true
tasks:
- name: restart server
shell: sleep 2 && shutdown -r now "Ansible updates triggered"
async: 1
poll: 0
ignore_errors: true
- name: waiting for the server to come back
local_action: wait_for host=testcentos state=started delay=30 timeout=300
Key Concepts:
async: 1runs the command asynchronouslypoll: 0means fire-and-forget (don't wait for result)local_actionexecutes on the control machine (where Ansible runs)wait_forpauses execution until the server responds
Create Multiple Directories
Uses the with_items loop to create multiple directories in a single task.
---
- hosts:
become: true
tasks:
- name: Creating multiple directories
file: path={{item}} state=directory
with_items:
- '/home/ansible/dir1'
- '/home/ansible/dir2'
- '/home/ansible/dir3'
Key Concepts:
with_itemsiterates over a list- Single task definition applies to all items
- More efficient than multiple similar tasks
User Management: Create and Delete
Creates a user, then demonstrates user removal in subsequent tasks.
---
- hosts:
become: true
tasks:
- name: Creating the User
user: name=testuser password=testuser123 groups=ansible shell=/bin/bash
- name: Removing the User
user: name=testuser state=absent remove=yes force=yes
Key Concepts:
usermodule handles account creation and deletionstate: absentremoves the userremove: yesdeletes the home directoryforce: yesforces removal even if user is logged in
Date and Timestamp Operations
Captures system date/time facts and creates timestamped files.
---
- hosts:
become: true
tasks:
- name: Date and Time Display
debug:
var=ansible_date_time.date
- name: Date and Time Example in Ansible
debug:
var=ansible_date_time.time
- name: Timestamp example with file
command: touch helloworld{{ansible_date_time.date}}.log
Key Concepts:
ansible_date_timeis a built-in fact- Access specific components like
.dateand.time - Use Jinja2 templating to embed variables in commands
File Archiving
Creates ZIP archives of single files, multiple files, and entire directories.
---
- hosts: all
become: true
tasks:
- name: Ansible zip file example
archive:
path: /home/ansible/helloworld.txt
dest: /home/ansible/helloworld.zip
format: zip
- name: Ansible zip multiple files example
archive:
path:
- /home/ansible/helloworld1.txt
- /home/ansible/helloworld.txt
dest: /home/ansible/helloworld.zip
format: zip
- name: Ansible zip directory example
archive:
path:
- /home/ansible
dest: /home/ansible/helloworld.zip
format: zip
Key Concepts:
archivemodule supports various formats (zip, tar, gz, bz2, xz)- Can archive single files or lists of files
destspecifies the output archive path
4. Variables and Tags
Variable Registration and Declaration
Demonstrates variable declaration, arrays, and capturing command output with register.
---
# Basic variable declaration
- hosts: all
vars:
name: hellowolrd
tasks:
- name: Variable Example Basic
debug:
msg: "{{ name }}"
# Array variable example
- hosts: all
vars:
name:
- helloworld
- pythonworld
tasks:
- name: Ansible Array Example
debug:
msg: "{{ name[1] }}"
# Register variable to capture command output
- hosts: all
tasks:
- name: Ansible register variable basic example
shell: "find *.txt"
args:
chdir: "/home/Ansible"
register: reg_output
- debug:
var: reg_output
Key Concepts:
varsblock defines playbook variables- Variables are accessed with
{{ variable_name }} - Arrays are indexed starting from 0
registercaptures task output for later use- Registered variables can be used in subsequent tasks
Pre/Post Tasks and Tags
Executes setup tasks before and cleanup tasks after main tasks; demonstrates selective execution with tags.
---
# Pre-tasks and post-tasks with tags
- hosts:
become: true
name: Post, Pre tasks and Tags
tags:
- helloworld
pre_tasks:
- debug: msg="task with tag - helloworld"
tasks:
- name: Execute of main task
debug: msg="now in our node"
post_tasks:
- debug: msg="task with tag - helloworld"
# Separate play without tags
- name: Go without tags
hosts: localhost
become: true
tasks:
- name: Command for files list
shell: ls -lrt > helloworld.txt
Usage Examples:
# List all available tags
ansible-playbook preposttagseg.yml --list-tags
# Run only tasks with specific tag
ansible-playbook preposttagseg.yml --tags helloworld
# Skip tasks with specific tag
ansible-playbook preposttagseg.yml --skip-tags helloworld
Key Concepts:
pre_tasksrun beforetaskspost_tasksrun after all taskstagsallow selective task execution- Tags can be applied at play or task level
5. Network Configuration
SSH Port Configuration
Modifies SSH configuration, restarts the service on a new port, and updates Ansible's connection port.
---
- name: Setup alternate SSH port
lineinfile:
dest: "/etc/ssh/sshd_config"
regexp: "^Port"
line: "Port 10786"
- name: restart server
shell: sleep 2 && shutdown -r now "Ansible updates triggered"
async: 1
poll: 0
become: true
ignore_errors: true
- name: waiting for the server to come back
local_action: wait_for host={{ KvmIP }} port=10786 state=started delay=30 timeout=300
sudo: false
- name: Changed SSH Port
set_fact:
ansible_port: 10786
Key Concepts:
lineinfilemodifies configuration files line-by-lineregexpmatches the line to replaceset_factupdates Ansible variables for subsequent connections- Critical to update
ansible_portafter changing SSH configuration
Telnet Automation with Expect
Demonstrates interactive telnet login and command execution using the expect module.
---
- name: Telnet {{ hostname }}
ignore_errors: yes
expect:
timeout: 10
command: telnet 127.0.0.1 10896
responses:
"Escape character is": "\n"
"login:": "root"
"password: ": "admin123"
"# ":
- conf
- hostname {{ hostname }}
- exit
- save all
Key Concepts:
expectmodule automates interactive commandsresponsesmaps prompts to expected input- Useful for legacy systems without API access
- Multiple commands can be chained in sequence
6. Advanced Patterns
KVM Setup with Roles
A role-based infrastructure setup that installs KVM, configures networking, and provisions virtual machines.
Main Playbook (infra-setup.yml):
---
- hosts: "{{ host }}"
roles:
- { role: initial-server-setup }
- { role: vm-setup }
Initial Server Setup Role (initial-server-setup/tasks/main.yml):
- name: Installing the required software & other Dependencies
become: yes
yum:
name: "{{ item }}"
state: latest
with_items:
- libguestfs-tools
- libvirt
- qemu-kvm
- virt-manager
- virt-install
- xorg-x11-apps
- xauth
- virt-viewer
- libguestfs-xfs
notify: enable_service
- name: Starting and enabling libvirtd service
systemd:
state: started
daemon_reload: yes
enabled: yes
name: libvirtd
- name: Destroying Default Virtual Network
virt_net:
command: destroy
name: default
- name: Undefining Default Virtual Network
virt_net:
command: undefine
name: default
- name: Restarting Libvirtd service
systemd:
state: restarted
daemon_reload: yes
name: libvirtd
- name: Disabling unwanted services on server
service:
name: "{{ item }}"
enabled: no
state: stopped
with_items:
- firewalld
- firewalld
- NetworkManager
- NetworkManager
- ntpd
- ntpd
- postfix
- postfix
- chronyd
- chronyd
- avahi-daemon
- avahi-daemon
- dhclient
- name: Disable SELinux on server
selinux: state=disabled
- name: Setup alternate SSH port
lineinfile:
dest: "/etc/ssh/sshd_config"
regexp: "^Port"
line: "Port 10896"
- name: restart server
shell: sleep 2 && shutdown -r now "Ansible updates triggered"
async: 1
poll: 0
become: true
ignore_errors: true
- name: waiting for the server to come back
local_action: wait_for host={{ baseServerIP }} port=10896 state=started delay=30 timeout=300
sudo: false
- name: Changed SSH Port
set_fact:
ansible_port: 10896
- name: Initializing performance parameters
raw: sysctl -p
VM Setup Role (vm-setup/tasks/main.yml):
- name: Getting server Template
command: mv /root/DevOps-Homework/VM_IMAGE/centos7-minimal.qcow2 /home/kvm/images/
- name: System preparation is running on Template
command: virt-sysprep -a /home/kvm/images/centos7-minimal.qcow2
- name: provisioning Server
command: virt-install -n {{ KVMHostname }}
--ram 2048 \
--vcpus 2 \
--os-type linux \
--os-variant rhel7 \
--import \
--disk path=/home/kvm/images/centos7-minimal.qcow2,device=disk,bus=virtio,format=qcow2 \
--network bridge=br0 \
--graphics none \
--serial tcp,host=127.0.0.1:7001,mode=bind,protocol=telnet
- name: "Starting {{ KVMHostname }} Server"
pause:
seconds: 40
- name: Configuring {{ KVMHostname }}
ignore_errors: yes
expect:
command: telnet 127.0.0.1 7001
timeout: 30
responses:
"Escape character is": "root"
"Password: ": "abc123+"
"# ":
- cd /root/DevOps-Homework/
- docker-compose up -d --build
Key Concepts:
- Roles organize tasks into reusable components
virt_netandvirt_installmanage KVM resourcespauseadds delays for system initializationexpectautomates interactive guest configuration
Vagrant Integration with Ansible
Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64" # Specifies the base Ubuntu Vagrant image
config.vm.hostname = "web" # Sets the target name for the Ansible playbook
# Port forwarding configuration
config.vm.network "forwarded_port", guest: 80, host: 8080 # Forwards port 80 from the VM to port 8080 on your local machine
# Ansible provisioning
config.vm.provision "ansible_local" do |a|
a.playbook = "apache.yaml" # Specifies the Ansible playbook to run (replace with your playbook filename)
end
#Add more provisioning blocks for additional playbooks
# config.vm.provision "ansible_local" do |a|
# a.playbook = "playbook2.yaml" # Specifies the second Ansible playbook to run
# end
end
Ansible Playbook (apache.yaml):
---
- hosts: all
become: true
gather_facts: false
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install Apache
apt:
name: apache2
state: present
- name: Start Apache service
service:
name: apache2
state: started
enabled: yes # Auto-start Apache on system boot
Key Concepts:
- Vagrant automates VM provisioning with
vagrant up ansible_localruns Ansible inside the guest VM- Port forwarding maps guest ports to host
- Ansible playbooks can be chained for complex setups
7. Windows Automation
Windows Ping Test
Basic connectivity test for Windows hosts using the Windows-specific win_ping module.
---
- name: Ping windows host
hosts: win_host
tasks:
- name: ping win_host
win_ping:
Key Concepts:
win_pingis the Windows equivalent ofping- Requires WinRM configured on Windows hosts
- No arguments needed for basic connectivity check
Windows User Creation
Creates a local user on Windows systems with specified password and state.
---
- name: Add a user
hosts: win_host
tasks:
- name: Add User
win_user:
name: testuser
password: "test123"
state: present
Key Concepts:
win_usermodule manages Windows local accountsstate: presentcreates the userstate: absentremoves the user- Passwords must meet Windows complexity requirements
Windows IP Configuration
Executes ipconfig command and displays network configuration.
---
- name: ipconfig module
hosts: win_hosts
tasks:
- name: run ipconfig
raw: ipconfig
register: ipconfig
- debug: var=ipconfig
Key Concepts:
rawmodule executes arbitrary commands without parsing- Windows-specific commands work with
rawmodule - Output is captured and displayed with
debug
8. Ansible Vault (Secrets Management)
Vault encrypts sensitive files like passwords, API keys, and inventory files containing credentials.
Create Encrypted Files
# Create a new encrypted file
ansible-vault create secrets.yml
# Encrypt an existing YAML file
ansible-vault encrypt inventory.yml
View and Edit Encrypted Files
# View encrypted file (prompts for password)
ansible-vault view secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Change vault password
ansible-vault rekey secrets.yml
Execute Playbooks with Vault
# Prompt for vault password at runtime
ansible-playbook playbook.yml --ask-vault-pass
# Use password from file (file contains only the password)
ansible-playbook playbook.yml --vault-password-file ./vault-pass.txt
# Use password from script (script outputs password to stdout)
ansible-playbook playbook.yml --vault-password-file ./vault-pass.py
Decrypting Files
# Decrypt vault file permanently
ansible-vault decrypt secrets.yml
Best Practices:
- Store vault passwords in secure password managers
- Use
.gitignoreto exclude vault password files from version control - Rotate vault passwords regularly
- Use separate vault passwords for different environments
Common Patterns and Tips
Conditional Task Execution
- name: Install package only if not already installed
apt:
name: nginx
state: present
when: "'nginx' not in ansible_packages"
Loop Examples
# Loop with list
- name: Create users
user:
name: "{{ item }}"
state: present
loop:
- user1
- user2
- user3
# Loop with dictionary
- name: Configure services
service:
name: "{{ item.name }}"
state: "{{ item.state }}"
loop:
- { name: 'nginx', state: 'started' }
- { name: 'mysql', state: 'started' }
Error Handling
# Ignore errors for non-critical tasks
- name: Remove old packages
apt:
name: deprecated-package
state: absent
ignore_errors: yes
# Fail on specific conditions
- name: Check disk space
shell: df -h / | awk 'NR==2 {print $5}'
register: disk_usage
failed_when: disk_usage.stdout | int > 90
Handlers for Service Restarts
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
tasks:
- name: Update nginx config
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: restart nginx
Running Playbooks
# Basic execution
ansible-playbook playbook.yml
# With inventory file
ansible-playbook -i inventory.ini playbook.yml
# Target specific hosts
ansible-playbook playbook.yml --limit webservers
# Run specific tags
ansible-playbook playbook.yml --tags "deploy"
# Verbose output
ansible-playbook playbook.yml -vvv
# Dry run (check mode)
ansible-playbook playbook.yml --check