🤖 What is Ansible?
›Ansible is an agentless IT automation tool by Red Hat. It connects to servers over SSH and runs tasks defined in YAML files called playbooks. No agent needs to be installed on target servers — this is its biggest advantage over Chef and Puppet.
Ansible vs Chef vs Puppet
| Feature | Ansible | Puppet | Chef |
|---|---|---|---|
| Agent required | No — agentless (SSH only) | Yes — Puppet agent | Yes — Chef client |
| Language | YAML — readable by everyone | Puppet DSL (Ruby-based) | Ruby DSL (complex) |
| Model | Push — control node pushes | Pull — agents pull config | Pull — agents pull config |
| Learning curve | Low — write YAML in hours | High — weeks to master | High — weeks to master |
| Setup time | Minutes — pip install ansible | Days — install agents everywhere | Days — install agents everywhere |
| Best for | Ad-hoc automation, CI/CD integration | Continuous compliance enforcement | Complex enterprise config management |
Where Ansible fits in the DevOps toolchain
| Tool | What it does | Analogy |
|---|---|---|
| Terraform | Provisions servers, networks, databases in cloud | Builder — creates the house |
| Ansible | Configures what is inside the servers | Interior designer — furnishes the house |
| Jenkins/GitHub Actions | Deploys application code | Moving company — brings your stuff in |
📋 Inventory — Static, Dynamic, Group Vars
›The inventory tells Ansible which servers to manage and how to group them. Groups let you target subsets: run tasks on all webservers, or just databases, or just production servers.
Group and host variables
Dynamic Inventory — for cloud environments
Static inventory files are unmanageable for cloud environments where VMs are created and destroyed regularly. Dynamic inventory queries cloud APIs at runtime.
📝 Playbooks — Tasks, Handlers, Templates
›A playbook is a YAML file that defines tasks to run on target servers. Each task uses an Ansible module (copy, template, service, package, command, etc.). Tasks run in order — if one fails, the play stops.
Handlers — run once at the end
Handlers are tasks triggered by notify — they run only once at the end of a play regardless of how many tasks triggered them. Use for: restart service, reload config, clear cache.
Jinja2 Templates — dynamic config files
📦 Roles — Reusable Automation
›A role is a reusable, structured collection of tasks, vars, templates, and handlers. Instead of one giant playbook, roles make automation modular and shareable across projects and teams. This is what separates junior from senior Ansible usage.
Role directory structure
Complete role example — nginx with TLS
🔧 Variables, Precedence & Vault
›Variable precedence — most important concept
Ansible has 22 variable precedence levels. For interviews, know these 6 in order:
| Priority | Source | Example |
|---|---|---|
| Lowest | Role defaults | role/defaults/main.yml |
| 2 | Inventory vars | inventory.ini host variables |
| 3 | Group vars | group_vars/webservers.yml |
| 4 | Host vars | host_vars/web-01.yml |
| 5 | Playbook vars | vars: section in playbook |
| Highest | Extra vars (-e flag) | ansible-playbook deploy.yml -e "env=prod" |
Ansible Vault — encrypt secrets
Vault encrypts sensitive data (passwords, API keys) so they can be safely stored in Git. The encrypted file looks like AES256 ciphertext — useless without the vault password.
🖥️ CLI Commands — Complete Reference
›🏢 Ansible Automation Platform (AAP / Tower)
›AAP (Ansible Automation Platform) is enterprise Ansible. It adds: Web UI, REST API, RBAC, job scheduling, audit logs, and credential management on top of standard Ansible. At HPE/Vodafone scale you need AAP — CLI Ansible is unmanageable for teams.
What AAP adds over CLI Ansible
| Before AAP (CLI) | After AAP |
|---|---|
| Manual inventory.ini files | Dynamic inventory synced from AWS/Azure |
| SSH keys on engineer laptops | Credentials stored in AAP vault |
| No audit trail | Full job history: who, what, when, output |
| No access control | RBAC: Dev team cannot run prod playbooks |
| Cron jobs on control node | Schedules in AAP with Slack notifications |
| Manual playbook updates | Projects auto-sync from Git on every push |
AAP Core Objects
| Object | Purpose |
|---|---|
| Organization | Top-level tenant grouping (Telecom Org, Healthcare Org) |
| Inventory | Server lists — static or dynamic. Scoped to an org. |
| Credential | SSH keys, vault passwords, cloud creds — stored encrypted |
| Project | Link to a Git repo containing playbooks. Auto-syncs on commit. |
| Job Template | Defines: which playbook + inventory + credentials + vars. The "run button" |
| Workflow Template | Chain multiple Job Templates: backup → deploy → verify → notify |
| Schedule | Run Job Templates on cron schedule without Jenkins |
AAP RBAC — role levels
| Role | Permissions |
|---|---|
| Admin | Full control — create, edit, delete, execute |
| Execute | Can run Job Templates — cannot edit them |
| Use | Can reference Credential/Inventory — cannot view secret values |
| Update | Can sync Projects and Inventories |
| Read | View only — can see job history |
🚀 Production Patterns — CI/CD, Rolling, Idempotency
›Idempotency — the most important Ansible concept
An idempotent playbook produces the same result whether run once or 100 times. Running a properly written Ansible playbook against an already-configured server should result in "OK" (no changes) not "Changed" or "Failed". This is the difference between professional and amateur Ansible usage.
Rolling deployment with serial
Ansible in Jenkins CI/CD pipeline
🔍 Troubleshooting — Common Issues
›| Error | Cause | Fix |
|---|---|---|
| SSH connection refused | Wrong IP, firewall blocking port 22, wrong SSH user | Check ansible_host, ansible_user, ansible_port |
| Permission denied (publickey) | SSH key not added to authorized_keys | Copy SSH key: ssh-copy-id user@host |
| Python not found | Old server without Python, or wrong path | Set ansible_python_interpreter=/usr/bin/python3 |
| sudo password required | become: yes but no sudo password configured | Use --ask-become-pass or configure NOPASSWD in sudoers |
| Task not idempotent | Using shell/command module instead of dedicated module | Use package/service/file modules instead of shell |
| Variable undefined | Variable not set in inventory or vars files | Check variable precedence, use default() filter |