Ansible
Configuration management and automation tool for provisioning, configuration, and application deployment.
Ansible
Configuration management and automation tool for provisioning, configuration, and application deployment.
Overview
Ansible is an agentless automation platform that uses SSH to connect to managed nodes and push configurations. It uses YAML-based playbooks to define automation tasks, making infrastructure as code readable and maintainable. Ansible follows a declarative approach, ensuring systems reach a desired state through idempotent operations.
flowchart LR
A[Control Node] -->|SSH| B[Managed Node 1]
A -->|SSH| C[Managed Node 2]
A -->|SSH| D[Managed Node 3]
subgraph Control Node
E[Playbooks]
F[Inventory]
G[Modules]
H[Plugins]
end
E --> A
F --> A
G --> A
H --> A
Inventory Management
Inventory files define the hosts and groups that Ansible manages. They can be static (INI or YAML files) or dynamic (scripts that query external sources).
Key Concepts
- Inventory file: Lists managed nodes organised into groups
- Host groups: Logical groupings of servers (e.g., webservers, databases)
- Host variables: Variables specific to individual hosts
- Group variables: Variables applied to all hosts in a group
- Dynamic inventory: Scripts that generate inventory from external sources (AWS, GCP, etc.)
Static Inventory
# /etc/ansible/hosts or inventory.ini
# Ungrouped hosts
server1.example.com
# Group definition
[webservers]
web1.example.com
web2.example.com ansible_port=2222
[databases]
db1.example.com
db2.example.com
# Group of groups
[production:children]
webservers
databases
# Group variables
[webservers:vars]
http_port=80
proxy_env=production
# Host with connection variables
[loadbalancers]
lb1.example.com ansible_host=192.168.1.50 ansible_user=admin ansible_ssh_private_key_file=/path/to/key
YAML Inventory Format
# inventory.yml
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_port: 2222
vars:
http_port: 80
databases:
hosts:
db1.example.com:
db2.example.com:
vars:
db_port: 5432
production:
children:
webservers:
databases:
Dynamic Inventory
# List hosts from AWS EC2
ansible-inventory -i aws_ec2.yml --list
# Example aws_ec2.yml plugin configuration
# aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- eu-west-1
keyed_groups:
- key: tags.Environment
prefix: env
filters:
instance-state-name: running
Common Commands
# List all hosts in inventory
ansible-inventory --list -i inventory.yml
# List hosts in a specific group
ansible webservers --list-hosts -i inventory.ini
# Graph inventory structure
ansible-inventory --graph -i inventory.yml
# Test connectivity to all hosts
ansible all -m ping -i inventory.ini
# Test connectivity to specific group
ansible webservers -m ping -i inventory.ini
Playbook Structure
Playbooks are YAML files that define the desired state of managed systems through plays, tasks, and handlers.
Key Concepts
- Play: Maps a group of hosts to tasks
- Task: A single action to be performed (calls a module)
- Handler: Task triggered by notifications from other tasks
- Role: Reusable collection of tasks, handlers, variables, and files
flowchart TD
A[Playbook] --> B[Play 1]
A --> C[Play 2]
B --> D[Tasks]
B --> E[Handlers]
B --> F[Variables]
C --> G[Roles]
G --> H[tasks/main.yml]
G --> I[handlers/main.yml]
G --> J[defaults/main.yml]
G --> K[templates/]
G --> L[files/]
Basic Playbook Structure
---
# site.yml
- name: Configure webservers
hosts: webservers
become: yes
vars:
http_port: 80
doc_root: /var/www/html
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Copy nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Ensure nginx is running
service:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
- name: Configure databases
hosts: databases
become: yes
roles:
- postgresql
- backup
Role Structure
# Create a new role
ansible-galaxy init myrole
# Standard role directory structure
myrole/
├── defaults/
│ └── main.yml # Default variables (lowest priority)
├── files/
│ └── myfile.txt # Static files to copy
├── handlers/
│ └── main.yml # Handler definitions
├── meta/
│ └── main.yml # Role metadata and dependencies
├── tasks/
│ └── main.yml # Main task list
├── templates/
│ └── config.j2 # Jinja2 templates
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/
└── main.yml # Role variables (higher priority)
Example Role Tasks
# roles/webserver/tasks/main.yml
---
- name: Install web server packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- php-fpm
tags:
- packages
- name: Deploy configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Reload nginx
tags:
- configuration
- name: Create document root
file:
path: "{{ doc_root }}"
state: directory
owner: www-data
group: www-data
mode: '0755'
Running Playbooks
# Run a playbook
ansible-playbook site.yml -i inventory.ini
# Run with specific inventory
ansible-playbook -i production.ini deploy.yml
# Limit to specific hosts or groups
ansible-playbook site.yml --limit webservers
# Run specific tags only
ansible-playbook site.yml --tags "configuration,packages"
# Skip specific tags
ansible-playbook site.yml --skip-tags "packages"
# Start at a specific task
ansible-playbook site.yml --start-at-task "Deploy configuration"
Modules
Modules are the units of work in Ansible. They perform specific tasks on managed nodes.
Key Concepts
- Idempotent: Modules can be run multiple times without changing the result
- Return values: Modules return JSON data about the operation
- Check mode: Most modules support dry-run mode
Command and Shell Modules
---
- name: Execute commands
hosts: all
tasks:
# command module - simple commands (no shell features)
- name: Check disk space
command: df -h
register: disk_space
changed_when: false
# shell module - supports pipes, redirects, environment variables
- name: Find large files
shell: find /var/log -type f -size +100M | head -10
register: large_files
changed_when: false
# raw module - bypasses the module subsystem
- name: Install Python on minimal systems
raw: apt-get install -y python3
when: ansible_python_interpreter is not defined
File Management Modules
---
- name: File operations
hosts: all
tasks:
# copy module - copy files from control node
- name: Copy configuration file
copy:
src: files/app.conf
dest: /etc/app/app.conf
owner: root
group: root
mode: '0644'
backup: yes
# template module - process Jinja2 templates
- name: Deploy templated configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
validate: nginx -t -c %s
notify: Reload nginx
# file module - manage file properties
- name: Create directory
file:
path: /opt/myapp
state: directory
owner: appuser
group: appgroup
mode: '0755'
- name: Create symbolic link
file:
src: /opt/myapp/current
dest: /var/www/app
state: link
# lineinfile module - manage lines in files
- name: Ensure line in file
lineinfile:
path: /etc/hosts
line: "192.168.1.100 app.local"
state: present
# blockinfile module - manage blocks of text
- name: Add configuration block
blockinfile:
path: /etc/ssh/sshd_config
block: |
Match User deploy
PasswordAuthentication no
PubkeyAuthentication yes
marker: "# {mark} ANSIBLE MANAGED BLOCK - deploy user"
Package Management Modules
---
- name: Package management
hosts: all
tasks:
# apt module - Debian/Ubuntu
- name: Install packages (apt)
apt:
name:
- nginx
- postgresql
- redis-server
state: present
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Remove package
apt:
name: apache2
state: absent
purge: yes
when: ansible_os_family == "Debian"
# yum module - RHEL/CentOS 7
- name: Install packages (yum)
yum:
name:
- nginx
- postgresql-server
state: present
when: ansible_os_family == "RedHat" and ansible_distribution_major_version == "7"
# dnf module - RHEL/CentOS 8+
- name: Install packages (dnf)
dnf:
name:
- nginx
- postgresql-server
state: present
when: ansible_os_family == "RedHat" and ansible_distribution_major_version | int >= 8
# package module - generic (auto-detects package manager)
- name: Install package (generic)
package:
name: git
state: present
Service Module
---
- name: Service management
hosts: all
tasks:
- name: Ensure service is running and enabled
service:
name: nginx
state: started
enabled: yes
- name: Restart service
service:
name: nginx
state: restarted
- name: Reload service configuration
service:
name: nginx
state: reloaded
# systemd module - additional systemd features
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Enable and start service
systemd:
name: myapp
state: started
enabled: yes
masked: no
User and Group Modules
---
- name: User management
hosts: all
tasks:
- name: Create group
group:
name: appgroup
state: present
gid: 1500
- name: Create user
user:
name: appuser
group: appgroup
groups: sudo,docker
shell: /bin/bash
home: /home/appuser
create_home: yes
state: present
- name: Add SSH key for user
authorized_key:
user: appuser
key: "{{ lookup('file', 'files/id_rsa.pub') }}"
state: present
Variables and Facts
Variables provide flexibility in playbooks, while facts are system information gathered from managed nodes.
Key Concepts
- Variable precedence: Variables have a defined order of precedence (22 levels)
- Facts: System information automatically gathered by Ansible
- Magic variables: Special variables like
hostvars,groups,inventory_hostname - Registered variables: Capture output from tasks
Variable Definition
---
# Playbook variables
- name: Deploy application
hosts: webservers
vars:
app_name: myapp
app_port: 8080
features:
- logging
- monitoring
vars_files:
- vars/common.yml
- vars/{{ env }}.yml
tasks:
- name: Use variables
debug:
msg: "Deploying {{ app_name }} on port {{ app_port }}"
# group_vars/webservers.yml
---
http_port: 80
https_port: 443
document_root: /var/www/html
# host_vars/web1.example.com.yml
---
http_port: 8080
custom_config: true
Variable Precedence (Simplified)
# From lowest to highest precedence:
# 1. Role defaults (roles/x/defaults/main.yml)
# 2. Inventory file or script group vars
# 3. Inventory group_vars/all
# 4. Playbook group_vars/all
# 5. Inventory group_vars/*
# 6. Playbook group_vars/*
# 7. Inventory file or script host vars
# 8. Inventory host_vars/*
# 9. Playbook host_vars/*
# 10. Host facts
# 11. Play vars
# 12. Play vars_prompt
# 13. Play vars_files
# 14. Role vars (roles/x/vars/main.yml)
# 15. Block vars
# 16. Task vars
# 17. Extra vars (-e) - HIGHEST PRIORITY
Gathering and Using Facts
---
- name: Work with facts
hosts: all
gather_facts: yes
tasks:
- name: Display OS information
debug:
msg: "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: Display memory
debug:
msg: "Total memory: {{ ansible_memtotal_mb }} MB"
- name: Display IP addresses
debug:
msg: "IPv4: {{ ansible_default_ipv4.address }}"
- name: Conditional based on facts
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
# Custom facts from /etc/ansible/facts.d/*.fact
- name: Display custom facts
debug:
var: ansible_local.custom.section.key
Registered Variables
---
- name: Register and use output
hosts: all
tasks:
- name: Get service status
command: systemctl status nginx
register: nginx_status
ignore_errors: yes
changed_when: false
- name: Display return code
debug:
msg: "Return code: {{ nginx_status.rc }}"
- name: Display stdout
debug:
msg: "{{ nginx_status.stdout_lines }}"
- name: Act on result
service:
name: nginx
state: started
when: nginx_status.rc != 0
Special Variables
---
- name: Use special variables
hosts: all
tasks:
- name: Current host info
debug:
msg: |
Hostname: {{ inventory_hostname }}
Short name: {{ inventory_hostname_short }}
Groups: {{ group_names }}
- name: Access other host variables
debug:
msg: "DB host IP: {{ hostvars['db1.example.com']['ansible_host'] }}"
- name: List all hosts in group
debug:
msg: "Webservers: {{ groups['webservers'] }}"
- name: Playbook directory
debug:
msg: "Playbook dir: {{ playbook_dir }}"
Conditionals and Loops
Conditionals control task execution, while loops iterate over lists of items.
Key Concepts
- when: Execute task only if condition is true
- loop: Iterate over a list of items
- until: Retry task until condition is met
- Jinja2 tests: Check variable types and values
Conditionals
---
- name: Conditional examples
hosts: all
vars:
install_nginx: true
deploy_env: production
packages:
- nginx
- php
tasks:
- name: Simple boolean condition
apt:
name: nginx
state: present
when: install_nginx
- name: String comparison
debug:
msg: "Production deployment"
when: deploy_env == "production"
- name: Multiple conditions (AND)
service:
name: nginx
state: started
when:
- install_nginx
- deploy_env == "production"
- name: Multiple conditions (OR)
debug:
msg: "Non-standard environment"
when: deploy_env == "development" or deploy_env == "staging"
- name: Check if variable is defined
debug:
msg: "Variable exists"
when: my_variable is defined
- name: Check list membership
debug:
msg: "nginx will be installed"
when: "'nginx' in packages"
- name: Numeric comparison
debug:
msg: "Plenty of memory"
when: ansible_memtotal_mb >= 4096
- name: Check task result
command: which nginx
register: nginx_check
ignore_errors: yes
changed_when: false
- name: Install if not present
apt:
name: nginx
state: present
when: nginx_check.rc != 0
Loops
---
- name: Loop examples
hosts: all
vars:
packages:
- nginx
- postgresql
- redis-server
users:
- name: alice
groups: admin
- name: bob
groups: developers
tasks:
# Simple loop
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop: "{{ packages }}"
# Loop with index
- name: Create numbered files
file:
path: "/tmp/file{{ index }}.txt"
state: touch
loop: "{{ packages }}"
loop_control:
index_var: index
# Loop over dictionaries
- name: Create users
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
state: present
loop: "{{ users }}"
# Loop with conditional
- name: Start specific services
service:
name: "{{ item }}"
state: started
loop:
- nginx
- postgresql
- redis-server
when: item != "redis-server"
# Nested loops with subelements
- name: Add SSH keys for users
authorized_key:
user: "{{ item.0.name }}"
key: "{{ item.1 }}"
loop: "{{ users | subelements('ssh_keys', skip_missing=True) }}"
# Loop until condition
- name: Wait for service to be ready
uri:
url: "http://localhost:8080/health"
status_code: 200
register: result
until: result.status == 200
retries: 10
delay: 5
# Loop with dict2items
- name: Set sysctl values
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
state: present
loop: "{{ sysctl_settings | dict2items }}"
vars:
sysctl_settings:
net.ipv4.ip_forward: 1
vm.swappiness: 10
Block Structure
---
- name: Block examples
hosts: all
tasks:
- name: Handle errors with blocks
block:
- name: Attempt risky operation
command: /opt/scripts/deploy.sh
- name: Verify deployment
uri:
url: http://localhost:8080/health
status_code: 200
rescue:
- name: Rollback on failure
command: /opt/scripts/rollback.sh
- name: Send alert
mail:
to: ops@example.com
subject: "Deployment failed"
body: "Deployment failed on {{ inventory_hostname }}"
always:
- name: Clean up temporary files
file:
path: /tmp/deploy
state: absent
Ansible Vault
Ansible Vault encrypts sensitive data such as passwords, keys, and certificates.
Key Concepts
- Encryption: AES256 encryption for files and variables
- Vault password: Can be provided via prompt, file, or script
- Multiple vaults: Different passwords for different environments
- Variable-level encryption: Encrypt individual variables within files
Common Commands
# Create encrypted file
ansible-vault create secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Encrypt existing file
ansible-vault encrypt vars.yml
# Decrypt file
ansible-vault decrypt vars.yml
# View encrypted file
ansible-vault view secrets.yml
# Rekey (change password)
ansible-vault rekey secrets.yml
# Encrypt string (for inline use)
ansible-vault encrypt_string 'mysecret' --name 'db_password'
# Run playbook with vault password prompt
ansible-playbook site.yml --ask-vault-pass
# Run playbook with vault password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
# Multiple vault IDs
ansible-vault encrypt --vault-id prod@prompt secrets-prod.yml
ansible-playbook site.yml --vault-id prod@~/.vault_pass_prod
Using Encrypted Variables
# group_vars/production/vault.yml (encrypted)
---
vault_db_password: supersecret
vault_api_key: abc123xyz
# group_vars/production/vars.yml (unencrypted, references vault)
---
db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"
Inline Encrypted Variables
# vars.yml with encrypted string
---
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
61626364656667686970616263646566676869706162636465666768697061626364656667686970
61626364656667686970616263646566676869706162636465666768697061626364656667686970
61626364656667686970616263646566676869706162636465666768697061626364656667686970
Vault Configuration
# ansible.cfg
[defaults]
vault_password_file = ~/.vault_pass
# Or use environment variable
# export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
Common Patterns
Best practices and patterns for writing effective Ansible automation.
Key Concepts
- Idempotency: Tasks produce the same result regardless of how many times they run
- Tags: Label tasks for selective execution
- Handlers: Run tasks only when notified of changes
- Check mode: Preview changes without applying them
Idempotency Patterns
---
- name: Idempotent operations
hosts: all
tasks:
# Good - idempotent
- name: Ensure package is installed
apt:
name: nginx
state: present
# Good - idempotent with creates
- name: Download file only if not present
get_url:
url: https://example.com/file.tar.gz
dest: /tmp/file.tar.gz
checksum: sha256:abc123...
# Good - idempotent command with creates
- name: Extract archive only if directory missing
command: tar xzf /tmp/file.tar.gz -C /opt
args:
creates: /opt/myapp
# Good - check before acting
- name: Check if config exists
stat:
path: /etc/myapp/config.yml
register: config_stat
- name: Create config if missing
template:
src: config.yml.j2
dest: /etc/myapp/config.yml
when: not config_stat.stat.exists
# Avoid - not idempotent without controls
- name: Run deployment script
command: /opt/scripts/deploy.sh
# Better with:
args:
creates: /opt/app/.deployed
Using Tags
---
- name: Tagged playbook
hosts: all
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- php-fpm
tags:
- packages
- install
- name: Configure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- configuration
- nginx
notify: Reload nginx
- name: Deploy application
git:
repo: https://github.com/example/app.git
dest: /var/www/app
version: main
tags:
- deploy
- application
# Special tags
- name: Always run this task
debug:
msg: "Always executed"
tags:
- always
- name: Never run unless explicitly called
debug:
msg: "Dangerous operation"
tags:
- never
- dangerous
handlers:
- name: Reload nginx
service:
name: nginx
state: reloaded
tags:
- configuration
# Run only specific tags
ansible-playbook site.yml --tags "configuration"
# Run multiple tags
ansible-playbook site.yml --tags "packages,configuration"
# Skip tags
ansible-playbook site.yml --skip-tags "deploy"
# List available tags
ansible-playbook site.yml --list-tags
Handler Patterns
---
- name: Handler examples
hosts: all
tasks:
- name: Update nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Validate nginx config
- Reload nginx
- name: Update nginx sites
template:
src: "{{ item }}.conf.j2"
dest: "/etc/nginx/sites-available/{{ item }}.conf"
loop:
- site1
- site2
notify: Reload nginx
# Force handler to run immediately
- name: Flush handlers now
meta: flush_handlers
- name: Check service status
uri:
url: http://localhost/health
status_code: 200
handlers:
- name: Validate nginx config
command: nginx -t
listen: "Validate nginx config"
- name: Reload nginx
service:
name: nginx
state: reloaded
listen: "Reload nginx"
Role Dependencies and Includes
# roles/webapp/meta/main.yml
---
dependencies:
- role: common
- role: nginx
vars:
nginx_port: 8080
- role: postgresql
when: database_type == "postgresql"
# Dynamic includes
---
- name: Include tasks dynamically
hosts: all
tasks:
- name: Include OS-specific tasks
include_tasks: "{{ ansible_os_family | lower }}.yml"
- name: Include role dynamically
include_role:
name: "{{ app_role }}"
vars:
app_port: 8080
Troubleshooting
Tools and techniques for debugging Ansible playbooks and resolving issues.
Key Concepts
- Verbose mode: Increase output detail with
-vflags - Check mode: Dry-run to preview changes
- Diff mode: Show file changes
- Debug module: Print variables and messages
Verbose and Check Modes
# Verbose levels
ansible-playbook site.yml -v # Show task results
ansible-playbook site.yml -vv # Show task input/output
ansible-playbook site.yml -vvv # Show connection details
ansible-playbook site.yml -vvvv # Show connection plugins, scripts
# Check mode (dry run)
ansible-playbook site.yml --check
# Check mode with diff
ansible-playbook site.yml --check --diff
# Diff mode (show changes)
ansible-playbook site.yml --diff
# Step through tasks
ansible-playbook site.yml --step
# Start at specific task
ansible-playbook site.yml --start-at-task "Deploy application"
# List tasks without executing
ansible-playbook site.yml --list-tasks
# List hosts that would be affected
ansible-playbook site.yml --list-hosts
Debug Module
---
- name: Debugging playbook
hosts: all
vars:
my_var: "test value"
tasks:
- name: Print variable
debug:
var: my_var
- name: Print message
debug:
msg: "The value is {{ my_var }}"
- name: Print with verbosity control
debug:
msg: "Detailed debug info"
verbosity: 2 # Only shows with -vv or higher
- name: Print all variables
debug:
var: vars
- name: Print hostvars
debug:
var: hostvars[inventory_hostname]
- name: Register and debug
command: cat /etc/os-release
register: os_info
changed_when: false
- name: Show registered variable
debug:
var: os_info
Common Issues and Solutions
| Issue | Solution |
|---|---|
| SSH connection refused | Check SSH service, firewall rules, and ansible_port |
| Permission denied | Verify ansible_user, SSH keys, or use --ask-pass |
| Module not found | Install required collection: ansible-galaxy collection install |
| Variable undefined | Check variable name spelling, scope, and precedence |
| Vault password error | Use --ask-vault-pass or set vault_password_file |
| Task timeout | Increase ansible_timeout or use async with poll |
| Jinja2 template error | Check syntax, quote strings: "{{ var }}" not {{ var }} |
| Idempotency issues | Use creates, removes, or when conditions |
| Handler not running | Ensure task reports changed, use meta: flush_handlers |
| Slow execution | Use strategy: free, serial, or async tasks |
Debugging Techniques
---
- name: Debugging techniques
hosts: all
tasks:
# Assert expected conditions
- name: Verify prerequisites
assert:
that:
- ansible_memtotal_mb >= 2048
- ansible_distribution == "Ubuntu"
fail_msg: "System does not meet requirements"
success_msg: "System requirements verified"
# Fail with custom message
- name: Check critical file
stat:
path: /etc/critical.conf
register: critical_file
- name: Fail if file missing
fail:
msg: "Critical configuration file is missing!"
when: not critical_file.stat.exists
# Pause for investigation
- name: Pause for manual check
pause:
prompt: "Check the server and press Enter to continue"
when: debug_mode | default(false)
Logging and Output
# ansible.cfg
[defaults]
# Log all output to file
log_path = /var/log/ansible.log
# Show timestamps
callbacks_enabled = timer, profile_tasks
# Display skipped hosts
display_skipped_hosts = True
# Show custom stats
show_custom_stats = True
# Save output to file
ansible-playbook site.yml | tee ansible_output.log
# JSON output for parsing
ansible-playbook site.yml --extra-vars "output_format=json"
# Use callback plugins
ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook site.yml
Quick Reference
| Command | Description |
|---|---|
ansible-playbook site.yml |
Run a playbook |
ansible-playbook site.yml -i inventory |
Specify inventory file |
ansible-playbook site.yml --limit host1 |
Limit to specific hosts |
ansible-playbook site.yml --tags deploy |
Run only tagged tasks |
ansible-playbook site.yml --check |
Dry run (check mode) |
ansible-playbook site.yml --diff |
Show file changes |
ansible-playbook site.yml -e "var=value" |
Pass extra variables |
ansible-playbook site.yml --ask-vault-pass |
Prompt for vault password |
ansible-playbook site.yml -vvv |
Verbose output |
ansible all -m ping |
Test connectivity |
ansible all -m setup |
Gather facts |
ansible-galaxy init role_name |
Create role skeleton |
ansible-galaxy install -r requirements.yml |
Install roles/collections |
ansible-vault create secrets.yml |
Create encrypted file |
ansible-vault edit secrets.yml |
Edit encrypted file |
ansible-vault encrypt_string 'text' |
Encrypt a string |
ansible-inventory --list |
List inventory as JSON |
ansible-doc module_name |
View module documentation |
Common Issues and Solutions
Connection Problems
# Test SSH connectivity
ansible all -m ping -vvv
# Check SSH configuration
ssh -v user@host
# Use password authentication
ansible-playbook site.yml --ask-pass --ask-become-pass
# Specify private key
ansible-playbook site.yml --private-key=/path/to/key
Variable Issues
# Debug a variable (lookup returns the resolved value, with a safe default if undefined)
- debug:
msg: |
Variable 'my_var' value: {{ my_var }}
Resolved value: {{ lookup('vars', 'my_var', default='undefined') }}
# Check if variable is defined
- fail:
msg: "Required variable 'db_host' is not defined"
when: db_host is not defined
Performance Optimisation
# ansible.cfg
[defaults]
forks = 20 # Parallel processes
pipelining = True # Reduce SSH operations
gathering = smart # Cache facts
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
Related Topics
The following topics would complement this Ansible cheatsheet:
- Terraform - Infrastructure provisioning that pairs well with Ansible configuration management
- Vault (HashiCorp) - Advanced secrets management integrated with Ansible
- Jenkins - CI/CD pipelines that orchestrate Ansible playbook execution
- SOPS - Alternative secrets management for GitOps workflows
- systemd - Service management understanding for effective Ansible service tasks
- AWX/Ansible Tower - Web-based interface and API for enterprise Ansible automation