Infrastructure Automation Reference

Ansible

$ ansible --version  ·  Complete Cheat Sheet

01 — Core Concepts
📖Key Terminology
TermDescription
Control NodeMachine where Ansible is installed and runs from
Managed NodeRemote host Ansible manages — no agent required
InventoryFile listing hosts and groups to manage
PlaybookYAML file with ordered list of plays and tasks
PlayMaps a set of hosts to a list of tasks
TaskSingle unit of work — calls exactly one module
ModuleReusable unit of code (apt, copy, template…)
RoleStructured, reusable unit of playbook content
HandlerTask triggered only when notified by another task
FactSystem info auto-gathered from managed nodes
TemplateJinja2 file rendered with variable substitution
VaultEncryption for sensitive data in playbooks
CollectionDistributable package of roles, modules, plugins
⚙️Installation & Config
# Install on Ubuntu/Debian sudo apt update && sudo apt install -y ansible # Install via pip pip3 install ansible # Verify installation ansible --version
# Config file search order 1. ANSIBLE_CONFIG (env variable) 2. ./ansible.cfg (current directory) 3. ~/.ansible.cfg (home directory) 4. /etc/ansible/ansible.cfg
# ansible.cfg example [defaults] inventory = ./inventory remote_user = ubuntu private_key_file = ~/.ssh/id_rsa host_key_checking = False forks = 10 timeout = 30
02 — Inventory
📄INI Formathosts
[webservers] web1.example.com web2.example.com ansible_port=2222 [dbservers] db1.example.com db2.example.com [datacenter:children] webservers dbservers [all:vars] ansible_user = ubuntu ansible_ssh_private_key_file= ~/.ssh/id_rsa
📄YAML Formatinventory.yml
all: children: webservers: hosts: web1: ansible_host: 192.168.1.10 web2: ansible_host: 192.168.1.11 dbservers: hosts: db1: ansible_host: 192.168.1.20 vars: ansible_user: ubuntu
# Dynamic inventory commands ansible-inventory -i aws_ec2.yml --list ansible-inventory -i inventory/ --graph
🔑Connection Variables
VariablePurpose
ansible_hostIP / hostname to connect to
ansible_portSSH port (default 22)
ansible_userRemote user for SSH
ansible_passwordSSH password — use vault!
ansible_ssh_private_key_filePath to private key
ansible_becomeEnable privilege escalation
ansible_become_userUser to become (default root)
ansible_become_methodsudo, su, pbrun, pfexec…
ansible_connectionssh, local, docker, winrm…
ansible_python_interpreterPython path on remote host
🎯Host Patterns
PatternMatches
all / *All hosts in inventory
webserversAll hosts in a group
web1.example.comSpecific host
web*Wildcard name match
web:dbUnion of two groups
web:&dbIntersection (in both)
web:!stagingweb minus staging group
webservers[0]First host in group
webservers[0:2]First three hosts
~web.*\.comRegex pattern
03 — Ad-Hoc Commands
Common Commands
# Syntax ansible <pattern> -m <module> -a "args" [options] # Ping all hosts ansible all -m ping # Run shell command ansible webservers -m shell -a "uptime" # Copy a file ansible all -m copy -a "src=/tmp/f dest=/tmp/f" # Install package (with sudo) ansible webservers -m apt \ -a "name=nginx state=present" -b # Gather all facts ansible web1 -m setup # Filter specific fact ansible web1 -m setup -a "filter=ansible_os_family"
🚩Common Flags
FlagDescription
-i inventoryInventory file, directory or script
-u userRemote SSH user
-bBecome (sudo / privilege escalation)
-KPrompt for become password
--ask-passPrompt for SSH password
-f 10Forks / parallelism level
-v / -vvvVerbosity (1–4 levels)
--checkDry run — no changes made
--diffShow diffs for changed files
-l host1,host2Limit to specific hosts
--tags tag1Run only tagged tasks
04 — Playbooks
📝Full Playbook ExampleYAML
--- # Full playbook structure - name: Configure web servers hosts: webservers become: true gather_facts: true vars: http_port: 80 app_version: "1.2.3" vars_files: - vars/main.yml - vault/secrets.yml pre_tasks: - name: Update apt cache ansible.builtin.apt: update_cache: true cache_valid_time: 3600 tasks: - name: Install nginx ansible.builtin.apt: name: nginx state: present tags: [install, nginx] notify: Restart nginx - name: Deploy config ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root mode: '0644' handlers: - name: Restart nginx ansible.builtin.service: name: nginx state: restarted
# Run a playbook ansible-playbook site.yml # Useful flags -i inventory inventory source --check dry run (no changes) --diff show file diffs -v / -vvvv verbosity level 1–4 --tags "web,db" run tagged tasks only --skip-tags "x" skip these tags -l webservers limit to host/group --start-at-task "name" --step confirm each task -e "key=val" extra vars (highest prio) --list-tasks show tasks, no run --list-hosts show target hosts --syntax-check validate YAML syntax
# Variable precedence (low → high) 1. role defaults 2. inventory vars 3. inventory group_vars 4. inventory host_vars 5. playbook group_vars 6. playbook host_vars 7. host facts / cached facts 8. play vars / vars_files 9. role vars 10. block / task vars 11. include_vars 12. set_facts / registered vars 13. -e extra vars ← WINS
05 — Essential Modules
📁Files & Templates
# copy - name: Copy config file ansible.builtin.copy: src: files/app.conf dest: /etc/app/app.conf owner: root group: root mode: '0644'
# template — Jinja2 rendering - name: Render nginx config ansible.builtin.template: src: templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf
# file — dirs, perms, symlinks - name: Create directory ansible.builtin.file: path: /var/www/html state: directory mode: '0755'
# lineinfile — manage single lines - name: Ensure line exists ansible.builtin.lineinfile: path: /etc/sysctl.conf regexp: '^net.ipv4.ip_forward' line: 'net.ipv4.ip_forward = 1' state: present
📦Package Management
# apt — Debian / Ubuntu - name: Install packages ansible.builtin.apt: name: - nginx - curl - git state: present update_cache: true
# dnf — RHEL / CentOS / Fedora - name: Install httpd ansible.builtin.dnf: name: httpd state: latest
# pip — Python packages - name: Install Python deps ansible.builtin.pip: name: [flask, gunicorn] virtualenv: /opt/myapp/venv
Package States
present absent latest removed purged
⚙️Services & System
# service - name: Start and enable nginx ansible.builtin.service: name: nginx state: started # stopped|restarted|reloaded enabled: true
# command — no shell features - name: Initialize app ansible.builtin.command: cmd: /usr/bin/myapp --init creates: /etc/myapp/done # skip if exists
# shell — pipes, redirection, globs - name: Get OS info ansible.builtin.shell: cmd: cat /etc/os-release | grep ID
# cron — schedule a job - name: Daily backup at 2am ansible.builtin.cron: name: backup minute: "0" hour: "2" job: /opt/backup.sh
👤Users & SSH Keys
# user - name: Create deploy user ansible.builtin.user: name: deploy shell: /bin/bash groups: sudo,docker append: true create_home: true state: present
# authorized_key - name: Add SSH key ansible.posix.authorized_key: user: deploy state: present key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
# fetch — pull file from remote - name: Download log file ansible.builtin.fetch: src: /var/log/app.log dest: ./logs/ flat: false
06 — Control Flow
🔄Loops
# Simple list loop - name: Install packages ansible.builtin.apt: name: "{{ item }}" state: present loop: - nginx - redis - postgresql
# Loop over list of dicts - name: Create users ansible.builtin.user: name: "{{ item.name }}" uid: "{{ item.uid }}" loop: - { name: alice, uid: 1001 } - { name: bob, uid: 1002 }
# loop_control — clean output loop_control: label: "{{ item.name }}" # display name only loop_var: user # rename 'item' index_var:idx # current index
# with_sequence - name: Create numbered dirs ansible.builtin.file: path: "/opt/app{{ item }}" state: directory with_sequence: start=1 end=5
🔀Conditionals & Error Handling
# when — single condition - name: Install on Debian only ansible.builtin.apt: name: nginx when: ansible_os_family == "Debian"
# when — multiple conditions (AND) when: - ansible_os_family == "Debian" - ansible_distribution_major_version | int >= 20
# register + use result - name: Check service status ansible.builtin.command: cmd: systemctl is-active nginx register: nginx_status ignore_errors: true - name: Show result ansible.builtin.debug: msg: "nginx: {{ nginx_status.rc == 0 | ternary('up','down') }}"
# block / rescue / always - block: - name: Try risky task ansible.builtin.command: /may/fail rescue: - name: Handle failure ansible.builtin.debug: msg: "Task failed, recovering" always: - name: Always runs ansible.builtin.debug: msg: "Cleanup done"
07 — Roles & Collections
🎭Role Structure
# Create role skeleton ansible-galaxy role init myrole
myrole/ ├── defaults/main.yml ← lowest priority vars ├── vars/main.yml ← high priority vars ├── tasks/main.yml ← main task list ├── handlers/main.yml ← handlers ├── templates/ ← Jinja2 .j2 files ├── files/ ← static files ├── meta/main.yml ← metadata & deps └── README.md
# Use roles in a playbook - hosts: webservers roles: - common - role: nginx vars: nginx_port: 8080 tags: [web] when: deploy_web | bool
🌐Galaxy & Collections
# Install role from Galaxy ansible-galaxy role install geerlingguy.nginx ansible-galaxy role install -r requirements.yml
# requirements.yml roles: - name: geerlingguy.nginx version: 3.1.0 collections: - name: community.general version: ">=4.0.0" - name: amazon.aws
# Useful collections ansible.posix POSIX utilities community.general Broad extra modules community.docker Docker management amazon.aws AWS cloud modules google.cloud GCP modules azure.azcollection Azure modules kubernetes.core Kubernetes management
08 — Vault & Security
🔐Ansible Vault Commands
# Create encrypted file ansible-vault create secrets.yml # Encrypt existing file ansible-vault encrypt vars/passwords.yml # View / edit encrypted file ansible-vault view secrets.yml ansible-vault edit secrets.yml # Decrypt file ansible-vault decrypt secrets.yml # Encrypt a single string ansible-vault encrypt_string 'mysecret' --name db_pass
🗝️Using Vault & Utilities
# Run with vault password prompt ansible-playbook site.yml --ask-vault-pass # Use a password file ansible-playbook site.yml \ --vault-password-file ~/.vault_pass # Set in ansible.cfg [defaults] vault_password_file = ~/.vault_pass
# ansible-doc — module help ansible-doc ansible.builtin.apt ansible-doc -l # list all modules # ansible-config ansible-config dump --only-changed ansible-config list # ansible-lint pip install ansible-lint ansible-lint site.yml
09 — Jinja2 Templating
🧪Variables & Filters
# Variable access "{{ variable }}" "{{ dict.key }}" "{{ list[0] }}" "{{ nested['key'] }}"
# Filters "{{ var | default('fallback') }}" "{{ var | upper }}" "{{ var | lower }}" "{{ var | trim }}" "{{ var | replace('a', 'b') }}" "{{ list | join(',') }}" "{{ list | length }}" "{{ list | first }}" "{{ list | sort }}" "{{ list | unique }}" "{{ num | int }}" "{{ var | bool }}" "{{ var | to_json }}" "{{ var | from_json }}" "{{ var | b64encode }}" "{{ var | b64decode }}" "{{ var | hash('sha256') }}" "{{ var | password_hash('sha512') }}"
🔍Tests, Lookups & Control
# Tests — used in when: var is defined var is undefined var is none var is string var is number path is file path is directory path is exists
# Lookups "{{ lookup('file', '/etc/hostname') }}" "{{ lookup('env', 'HOME') }}" "{{ lookup('pipe', 'date +%Y') }}"
# Conditionals in templates {% if env == 'prod' %} workers 8; {% elif env == 'staging' %} workers 2; {% else %} workers 1; {% endif %}
# Loops in templates {% for host in groups['webservers'] %} server {{ hostvars[host].ansible_host }}; {% endfor %}
🪄Magic Variables
VariableDescription
hostvarsAll variables for all hosts
groupsAll inventory groups and their hosts
group_namesGroups the current host belongs to
inventory_hostnameCurrent host's inventory name
play_hostsActive hosts in the current play
ansible_play_batchHosts in the current serial batch
role_pathFilesystem path of current role
playbook_dirDirectory containing the playbook
10 — Advanced Features
Performance & Strategy
# Serial — rolling updates - hosts: webservers serial: 2 # 2 hosts at a time serial: "20%" # percentage serial: [1, 5, 10] # ramp-up max_fail_percentage: 25
# Strategy plugins strategy: linear # default: task by task strategy: free # each host runs ASAP strategy: debug # interactive debugger
# Async — fire and forget - name: Long running task ansible.builtin.command: /opt/long.sh async: 600 # max seconds poll: 0 # 0 = fire & forget register: job - name: Wait for job ansible.builtin.async_status: jid: "{{ job.ansible_job_id }}" register: result until: result.finished retries: 30 delay: 20
🔁Delegation, Retries & Caching
# delegate_to - name: Run on localhost ansible.builtin.command: /opt/notify.sh delegate_to: localhost
# run_once — first host only - name: DB migration ansible.builtin.command: migrate.sh run_once: true delegate_to: db1.example.com
# Retry until success - name: Poll health endpoint ansible.builtin.uri: url: http://localhost/health register: health until: health.status == 200 retries: 10 delay: 5
# Fact caching (ansible.cfg) [defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/facts_cache fact_caching_timeout = 86400 # 1 day
11 — Common Facts Reference
📊Frequently Used Ansible Facts
FactExample
ansible_hostnameweb1
ansible_fqdnweb1.example.com
ansible_default_ipv4.address10.0.0.5
ansible_all_ipv4_addresses[10.0.0.5]
FactExample
ansible_os_familyDebian
ansible_distributionUbuntu
ansible_distribution_version22.04
ansible_distribution_major_version22
ansible_kernel5.15.0-91
FactExample
ansible_architecturex86_64
ansible_processor_vcpus4
ansible_memtotal_mb7962
ansible_pkg_mgrapt
ansible_service_mgrsystemd