Ansible Playbook Guide
Inventory
# inventory/hosts.ini
[webservers]
web1.example.com
web2.example.com ansible_user=ubuntu
[dbservers]
db1.example.com ansible_host=10.0.1.10 ansible_port=2222
[production:children]
webservers
dbservers
[production:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/prod_key
# inventory/hosts.yml (YAML format)
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_user: ubuntu
dbservers:
hosts:
db1.example.com:
ansible_host: 10.0.1.10
# Run against inventory
ansible -i inventory/hosts.ini webservers -m ping
ansible-playbook -i inventory/hosts.ini deploy.yml
Playbook Structure
---
- name: Deploy web application
hosts: webservers
become: yes
gather_facts: yes
serial: 2 # rolling update: 2 at a time
vars:
app_version: "2.1.0"
app_dir: /opt/myapp
vars_files:
- vars/common.yml
- "vars/{{ansible_os_family}}.yml"
pre_tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
tasks:
- name: Create app directory
file:
path: "{{app_dir}}"
state: directory
mode: '0755'
owner: www-data
- name: Deploy app
copy:
src: dist/
dest: "{{app_dir}}/"
notify: Restart nginx
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
Tasks & Modules
tasks:
# Package management
- name: Install packages
package:
name: "{{item}}"
state: present
loop:
- nginx
- git
- python3-pip
# Template file
- name: Deploy nginx config
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: nginx -t -c %s
notify: Reload nginx
# Command with return value
- name: Get current version
command: /opt/myapp/bin/version
register: current_version
changed_when: false
- debug:
msg: "Running {{current_version.stdout}}"
# Block with error handling
- block:
- name: Dangerous task
command: /opt/upgrade.sh
rescue:
- name: Rollback on failure
command: /opt/rollback.sh
always:
- name: Send notification
debug:
msg: "Upgrade attempt completed"
Variables & Conditionals
# Variable precedence (highest to lowest):
# 1. extra vars (-e flag)
# 2. task vars
# 3. block vars
# 4. role vars
# 5. play vars_files
# 6. host_vars / group_vars
# 7. defaults
# Conditionals
- name: Install Apache on RHEL
yum:
name: httpd
state: present
when:
- ansible_os_family == "RedHat"
- ansible_distribution_major_version | int >= 8
- name: Deploy only if version changed
copy:
src: app.tar.gz
dest: /opt/
when: current_version.stdout != app_version
# Conditional import
- import_tasks: tasks/centos.yml
when: ansible_distribution == "CentOS"
# Loops
- name: Create users
user:
name: "{{item.name}}"
groups: "{{item.groups}}"
shell: /bin/bash
loop:
- { name: alice, groups: sudo }
- { name: bob, groups: developers }
Roles Structure
roles/
โโโ nginx/
โโโ tasks/
โ โโโ main.yml
โ โโโ install.yml
โ โโโ configure.yml
โโโ handlers/
โ โโโ main.yml
โโโ templates/
โ โโโ nginx.conf.j2
โโโ files/
โ โโโ mime.types
โโโ vars/
โ โโโ main.yml
โโโ defaults/
โ โโโ main.yml # lowest priority variables
โโโ meta/
โโโ main.yml # dependencies
# Use role in playbook
- hosts: webservers
roles:
- common
- { role: nginx, nginx_port: 8080 }
- role: app
vars:
app_version: "2.1.0"
# Install roles from Ansible Galaxy
ansible-galaxy install geerlingguy.nginx
ansible-galaxy collection install community.general
Ansible Vault
# Encrypt a file
ansible-vault encrypt vars/secrets.yml
ansible-vault encrypt_string 'mysecretpassword' --name 'db_password'
# Edit encrypted file
ansible-vault edit vars/secrets.yml
# Decrypt file
ansible-vault decrypt vars/secrets.yml
# Rekey (change password)
ansible-vault rekey vars/secrets.yml
# Run playbook with vault password
ansible-playbook deploy.yml --ask-vault-pass
ansible-playbook deploy.yml --vault-password-file ~/.vault_pass
# Vault in group_vars
# group_vars/production/secrets.yml (encrypted)
# db_password: !vault |
# $ANSIBLE_VAULT;1.1;AES256
# 6631356...
# Multiple vault IDs (Ansible 2.4+)
ansible-vault encrypt --vault-id dev@prompt vars/dev.yml
ansible-playbook deploy.yml --vault-id dev@~/.dev_pass