Ansible Cheat Sheet¶
Fun fact: Ansible was created by Michael DeHaan in 2012. The name comes from Ursula Le Guin's science fiction novels, where an "ansible" is a faster-than-light communication device. Ansible's key innovation: agentless architecture — it uses SSH and Python, requiring nothing installed on managed hosts except Python (which ships with most Linux distributions).
Remember: Ansible's core principle: idempotency. Running the same playbook twice produces the same result.
state: presentchecks if something exists and only acts if it does not. This is why Ansible showschangedvsok—okmeans "already in desired state, no action taken."
Ad-Hoc Commands¶
ansible all -m ping -i inventory.yml
ansible webservers -m command -a "uptime"
ansible dbservers -m service -a "name=postgresql state=restarted" -b
ansible all -m copy -a "src=file.txt dest=/tmp/file.txt"
ansible all -m apt -a "name=nginx state=present" -b
| Flag | Purpose |
|---|---|
-i |
Inventory file |
-m |
Module name |
-a |
Module arguments |
-b |
Become (sudo) |
-u |
Remote user |
-k |
Ask for SSH password |
--check |
Dry-run |
--diff |
Show file changes |
Inventory¶
# inventory.yml
all:
children:
webservers:
hosts:
web1:
ansible_host: 10.0.1.10
web2:
ansible_host: 10.0.1.11
vars:
nginx_port: 80
dbservers:
hosts:
db1:
ansible_host: 10.0.2.10
Playbook Structure¶
---
- name: Configure web servers
hosts: webservers
become: true
vars:
app_port: 8080
tasks:
- name: Install packages
apt:
name: [nginx, curl]
state: present
- name: Copy config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
Role Structure¶
roles/myapp/
├── defaults/main.yml # Default vars (lowest precedence)
├── tasks/main.yml # Tasks
├── handlers/main.yml # Handlers
├── templates/ # Jinja2 templates
├── files/ # Static files
├── vars/main.yml # Vars (higher precedence)
└── meta/main.yml # Dependencies
Variable Precedence (low → high)¶
-e always wins.
Key Modules¶
| Module | Purpose | Example |
|---|---|---|
apt/yum |
Package management | apt: name=nginx state=present |
service |
Service control | service: name=nginx state=started enabled=true |
template |
Jinja2 → file | template: src=app.conf.j2 dest=/etc/app.conf |
copy |
Static file copy | copy: src=file dest=/opt/file mode=0644 |
lineinfile |
Edit single line | lineinfile: path=/etc/hosts line="10.0.0.1 db" |
user |
User management | user: name=deploy groups=sudo |
file |
File/dir management | file: path=/opt/app state=directory mode=0755 |
command |
Run command | command: /opt/deploy.sh |
shell |
Run shell command | shell: cat /etc/passwd | grep deploy |
debug |
Print variable | debug: var=ansible_hostname |
Conditionals & Loops¶
# Conditional
- name: Install on Debian
apt: name=nginx
when: ansible_os_family == "Debian"
# Loop
- name: Create users
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
loop:
- { name: alice, groups: sudo }
- { name: bob, groups: docker }
# Register + conditional
- command: which docker
register: docker_check
ignore_errors: true
- name: Install Docker
apt: name=docker.io
when: docker_check.rc != 0
Ansible Vault¶
ansible-vault encrypt secrets.yml
ansible-vault edit secrets.yml
ansible-vault decrypt secrets.yml
ansible-vault encrypt_string 'pass' --name 'db_password'
# Run with vault
ansible-playbook site.yml --ask-vault-pass
ansible-playbook site.yml --vault-password-file=~/.vault_pass
Jinja2 Quick Reference¶
{{ variable }} {# Output #}
{{ var | default("fallback") }} {# Filter #}
{% for item in list %} {# Loop #}
{% if condition %} {# Conditional #}
{{ ansible_hostname }} {# Fact #}
{{ groups['webservers'] }} {# Group members #}
Error Handling¶
# Ignore errors
- command: /opt/check.sh
ignore_errors: true
# Custom failure
- command: df -h /
register: result
failed_when: "'100%' in result.stdout"
# Block/rescue
- block:
- command: /opt/deploy.sh
rescue:
- command: /opt/rollback.sh
always:
- debug: msg="Deploy attempt complete"