Summary
Ansible is an agentless, push-based configuration management and automation tool that uses SSH for communication and YAML for playbooks. It excels in infrastructure provisioning, configuration management, application deployment, and orchestration. Key strengths include idempotent operations, human-readable YAML syntax, extensive module library, and no agent requirements. Essential for DevOps professionals working on infrastructure automation, CI/CD pipelines, and multi-environment deployments where consistency and reliability are critical.
1. Core Concepts
What is Ansible?
- Agentless automation tool (uses SSH/WinRM)
- Push-based configuration management
- Written in Python, uses YAML for playbooks
- Idempotent - running multiple times produces same result
Key Components
- Control Node: Machine where Ansible is installed
- Managed Nodes: Target machines being configured
- Inventory: List of managed nodes
- Modules: Units of code Ansible executes
- Tasks: Units of action in Ansible
- Playbooks: YAML files containing plays
- Roles: Reusable collection of tasks, vars, handlers
2. Installation & Setup
# Install Ansible
pip install ansible
# or
sudo apt-get install ansible
# Test connection
ansible all -m ping -i inventory.ini
# Ad-hoc command syntax
ansible [pattern] -m [module] -a "[arguments]" -i [inventory]
3. Inventory
Static Inventory (inventory.ini)
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.example.com ansible_host=192.168.1.100
[all:vars]
ansible_user=admin
ansible_ssh_private_key_file=/path/to/key
Dynamic Inventory
# Can use scripts that return JSON
# AWS EC2, Azure, GCP plugins available
plugin: amazon.aws.ec2
regions:
- us-east-1
4. Playbook Structure
Basic Playbook
---
- name: Configure webservers
hosts: webservers
become: yes
vars:
http_port: 80
tasks:
- name: Install Apache
apt:
name: apache2
state: present
when: ansible_os_family == "Debian"
- name: Start Apache
service:
name: apache2
state: started
enabled: yes
5. Variables
Variable Precedence (Low to High)
- Role defaults
- Inventory vars
- Playbook vars
- Host facts
- Play vars
- Task vars
- Extra vars (-e)
Variable Definition
# In playbook
vars:
app_name: myapp
# In group_vars/all.yml
db_port: 5432
# Using variables
- debug:
msg: "App {{ app_name }} uses port {{ db_port }}"
6. Facts & Magic Variables
# Gathering facts
- name: Display facts
debug:
var: ansible_facts
# Common facts
ansible_hostname
ansible_os_family
ansible_distribution
ansible_memtotal_mb
# Magic variables
hostvars['hostname']
group_names
groups['webservers']
inventory_hostname
7. Conditionals & Loops
Conditionals
- name: Install on RedHat
yum:
name: httpd
when: ansible_os_family == "RedHat"
- name: Multiple conditions
service:
name: nginx
when:
- ansible_os_family == "Debian"
- ansible_distribution_major_version == "20"
Loops
# Simple loop
- name: Install packages
apt:
name: "{{ item }}"
loop:
- nginx
- mysql
- php
# Loop with dict
- name: Create users
user:
name: "{{ item.key }}"
groups: "{{ item.value }}"
loop: "{{ users | dict2items }}"
8. Handlers
tasks:
- name: Copy nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
9. Templates (Jinja2)
# template.j2
server {
listen {{ http_port }};
server_name {{ ansible_hostname }};
{% for site in sites %}
location /{{ site.name }} {
proxy_pass {{ site.backend }};
}
{% endfor %}
}
10. Roles
Role Structure
roles/
webserver/
tasks/main.yml
handlers/main.yml
templates/
files/
vars/main.yml
defaults/main.yml
meta/main.yml
Using Roles
- hosts: webservers
roles:
- common
- webserver
- role: database
vars:
db_name: production
11. Error Handling
# Ignore errors
- name: This might fail
command: /bin/false
ignore_errors: yes
# Block error handling
- block:
- name: Try this
command: /bin/something
rescue:
- name: Do this on error
debug:
msg: "Task failed"
always:
- name: Always do this
debug:
msg: "Cleanup"
# Failed when
- command: /usr/bin/somecommand
register: result
failed_when: "'ERROR' in result.stderr"
12. Vault (Encryption)
# Create encrypted file
ansible-vault create secrets.yml
# Encrypt existing file
ansible-vault encrypt vars.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Run playbook with vault
ansible-playbook site.yml --ask-vault-pass
13. Common Modules
File Operations
# File module
- file:
path: /etc/app
state: directory
mode: '0755'
# Copy module
- copy:
src: app.conf
dest: /etc/app/
backup: yes
# Template module
- template:
src: config.j2
dest: /etc/app/config
Package Management
# Package module (generic)
- package:
name: nginx
state: present
# APT (Debian/Ubuntu)
- apt:
name: apache2
update_cache: yes
# YUM (RedHat/CentOS)
- yum:
name: httpd
state: latest
Service Management
- service:
name: nginx
state: started
enabled: yes
# Systemd specific
- systemd:
name: nginx
state: restarted
daemon_reload: yes
14. Advanced Topics
Custom Modules
#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present')
)
)
result = dict(
changed=False,
message=''
)
module.exit_json(**result)
if __name__ == '__main__':
main()
Strategies
# Execution strategies
- hosts: all
strategy: free # Don't wait for all hosts
# Other options: linear (default), debug
Delegation
- name: Take out of load balancer
command: /usr/bin/remove_from_lb {{ inventory_hostname }}
delegate_to: loadbalancer
- name: Run locally
command: /usr/bin/local_script
delegate_to: localhost
15. Best Practices
- Use version control for playbooks
- Keep it simple - one role, one purpose
- Use meaningful names for tasks
- Always use
stateparameter - Tag your tasks for selective execution
- Use handlers for service restarts
- Encrypt sensitive data with Vault
- Test with
--check(dry run) - Use
ansible-lintfor code quality - Document your playbooks
16. Performance Optimization
# Fact caching
[defaults]
fact_caching = jsonfile
fact_caching_connection = /tmp/facts_cache
# Pipelining
[ssh_connection]
pipelining = True
# Forks (parallel execution)
[defaults]
forks = 50
# Disable fact gathering when not needed
- hosts: all
gather_facts: no
17. Debugging
# Debug module
- debug:
msg: "Variable value: {{ my_var }}"
verbosity: 2
# Register and debug
- command: /usr/bin/something
register: output
- debug:
var: output
# Pause for debugging
- pause:
prompt: "Check the system and press enter"
18. Ansible vs Other Tools Comparison
| Feature | Ansible | Puppet | Chef | Salt |
|---|---|---|---|---|
| Agent | Agentless (SSH) | Agent-based | Agent-based | Agent-based |
| Language | YAML | Ruby DSL | Ruby DSL | YAML/Python |
| Model | Push | Pull | Pull | Push/Pull |
| Learning Curve | Easy | Moderate | Steep | Moderate |
| Architecture | Simple | Master-Agent | Server-Node | Master-Minion |
19. Key Concepts Deep Dive
Idempotency Patterns
- File Operations:
state: present/absent/directory/link - Package Management:
state: present/latest/absent - Service Management:
state: started/stopped/restarted - Configuration: Use templates with checksums
Variable Precedence (Highest to Lowest)
- Extra vars (
-ecommand line) - Task vars (in task definition)
- Block vars (in block definition)
- Role and include vars
- Play vars_prompt
- Play vars_files
- Play vars
- Set_facts / registered vars
- Host facts
- Playbook host_vars
- Playbook group_vars
- Inventory host_vars
- Inventory group_vars
- Inventory vars
- Role defaults
Include vs Import Differences
- Static (import_*): Processed at parse time, can't use loops/conditionals on import
- Dynamic (include_*): Processed at runtime, supports loops/conditionals
Multi-OS Handling Strategies
# Method 1: OS Family conditionals
- name: Install Apache (Debian)
apt: name=apache2
when: ansible_os_family == "Debian"
- name: Install Apache (RedHat)
yum: name=httpd
when: ansible_os_family == "RedHat"
# Method 2: Variable mapping
vars:
apache_package:
Debian: apache2
RedHat: httpd
- name: Install Apache
package:
name: "{{ apache_package[ansible_os_family] }}"
20. Ansible Tower/AWX Features
Enterprise Features
- Role-Based Access Control (RBAC)
- Job Templates & Workflows
- Credential Management
- Inventory Sync from Cloud Providers
- RESTful API
- Audit Trails & Logging
- Schedule Jobs
- Survey Forms for Job Customization
Tower vs AWX
- Tower: Red Hat commercial product with support
- AWX: Open-source upstream project
- Key Differences: Support, stability, additional enterprise features
21. Troubleshooting Commands
# Check syntax
ansible-playbook playbook.yml --syntax-check
# List hosts
ansible all --list-hosts -i inventory
# Dry run
ansible-playbook playbook.yml --check
# Step through tasks
ansible-playbook playbook.yml --step
# Start at specific task
ansible-playbook playbook.yml --start-at-task="Install Apache"
# Run specific tags
ansible-playbook playbook.yml --tags="configuration"
# Increase verbosity
ansible-playbook playbook.yml -vvv
22. Security Best Practices
- Use SSH keys instead of passwords
- Encrypt sensitive data with ansible-vault
- Use become instead of running as root
- Limit sudo permissions for ansible user
- Validate input in custom modules
- Use no_log: true for sensitive tasks
- Rotate vault passwords regularly
Remember: Ansible's power lies in its simplicity. Start simple, grow complex only when needed.