Skip to content

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: present checks if something exists and only acts if it does not. This is why Ansible shows changed vs okok means "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)

role defaults → inventory vars → playbook vars →
task vars → extra vars (-e)

-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"