Post

Ansible Cheatsheet - Quick Reference Guide

A comprehensive Ansible cheatsheet covering playbooks, modules, inventory, variables, and common automation tasks

Ansible Cheatsheet - Quick Reference Guide

Overview

video grab from Youtube

What is Ansible?

Open-source, agentless IT automation tool for configuration management, app deployment, provisioning, orchestration, network & security automation.

Who created Ansible?

Created by Michael DeHaan (2012), acquired by Red Hat (2015)

Why use Ansible?

Radically simple, reliable automation: agentless, push-based, idempotent, YAML playbooks, low learning curve, huge module ecosystem, strong community.

Where is Ansible used?

Control node: any Python-capable system (Linux/macOS/Windows); manages Linux, Windows, network gear, clouds (AWS/Azure/GCP), containers, virtually anywhere via SSH/WinRM; global enterprise adoption.

How to use Ansible?

Write YAML playbooks (desired state) + inventory → run ansible-playbook → control node pushes/executes temporary Python modules over SSH/WinRM → idempotent changes, no agents left behind.

Installation

Install Ansible

1
2
3
4
5
6
7
8
# Create virtual environment for python
python3 -m venv .ansible-venv

# Python pip
pip install ansible

# Verify installation
ansible --version

Basic Commands

Ad-Hoc Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Ping hosts
ansible all -m ping
ansible webservers -m ping

# Execute command
ansible all -a "uptime"
ansible all -a "df -h"

# Copy file
ansible all -m copy -a "src=/path/file dest=/tmp/file"

# Install package
ansible all -m apt -a "name=nginx state=present" --become

# Service management
ansible all -m systemd -a "name=nginx state=started" --become

Playbook Execution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Run playbook
ansible-playbook playbook.yml

# Run with inventory
ansible-playbook -i inventory.ini playbook.yml

# Run with tags
ansible-playbook playbook.yml --tags "web,db"

# Skip tags
ansible-playbook playbook.yml --skip-tags "debug"

# Limit to specific hosts
ansible-playbook playbook.yml --limit webservers

# Check mode (dry run)
ansible-playbook playbook.yml --check

# Verbose output
ansible-playbook playbook.yml -v
ansible-playbook playbook.yml -vv
ansible-playbook playbook.yml -vvv

# Run with vault password
ansible-playbook playbook.yml --ask-vault-pass
ansible-playbook playbook.yml --vault-password-file vault.txt

Inventory

Static Inventory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# inventory.ini
[webservers]
web1 ansible_host=192.168.1.10
web2 ansible_host=192.168.1.11

[dbservers]
db1 ansible_host=192.168.1.20

[webservers:vars]
ansible_user=admin
ansible_ssh_private_key_file=~/.ssh/id_rsa

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Dynamic Inventory

1
2
3
4
5
# AWS EC2
ansible-playbook -i ec2.py playbook.yml

# Use inventory script
ansible-playbook -i inventory.py playbook.yml

Inventory Variables

1
2
3
4
5
6
[server1]
192.168.1.10 ansible_user=admin ansible_port=2222

[servers:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
ansible_python_interpreter=/usr/bin/python3

Playbook Structure

Basic Playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
- name: Configure Web Server
  hosts: webservers
  become: yes
  gather_facts: yes

  vars:
    nginx_port: 80
    app_user: www-data

  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present

    - name: Start Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

Multiple Plays

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
- name: Configure Web Servers
  hosts: webservers
  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present

- name: Configure Database
  hosts: dbservers
  tasks:
    - name: Install PostgreSQL
      apt:
        name: postgresql
        state: present

Common Modules

Package Management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# APT (Debian/Ubuntu)
- name: Install package
  apt:
    name: nginx
    state: present
    update_cache: yes

- name: Install multiple packages
  apt:
    name:
      - nginx
      - mysql-server
    state: present

# YUM (RHEL/CentOS)
- name: Install package
  yum:
    name: nginx
    state: present

# DNF (Fedora)
- name: Install package
  dnf:
    name: nginx
    state: present

File Operations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Copy file
- name: Copy file
  copy:
    src: /local/path/file.conf
    dest: /remote/path/file.conf
    owner: root
    group: root
    mode: '0644'

# Template file
- name: Configure Nginx
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    backup: yes

# Create directory
- name: Create directory
  file:
    path: /opt/app
    state: directory
    mode: '0755'

# Create file
- name: Create file
  file:
    path: /tmp/test.txt
    state: touch
    mode: '0644'

# Line in file
- name: Add line to file
  lineinfile:
    path: /etc/hosts
    line: '192.168.1.10 example.com'
    state: present

# Block in file
- name: Add block
  blockinfile:
    path: /etc/ssh/sshd_config
    block: |
      Match User ansible
        ForceCommand /usr/bin/false
    marker: "# {mark} ANSIBLE MANAGED BLOCK"

Service Management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Systemd
- name: Start service
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Restart service
  systemd:
    name: nginx
    state: restarted

# Service (generic)
- name: Start service
  service:
    name: nginx
    state: started
    enabled: yes

User Management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Create user
- name: Create user
  user:
    name: appuser
    uid: 1000
    group: appgroup
    shell: /bin/bash
    home: /home/appuser
    create_home: yes

# Add user to group
- name: Add user to group
  user:
    name: appuser
    groups: docker
    append: yes

Command Execution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Shell command
- name: Run command
  shell: |
    cd /opt/app
    ./setup.sh
  args:
    creates: /opt/app/.installed

# Command (safer, no shell)
- name: Run command
  command: /usr/bin/script.sh arg1 arg2

# Raw command
- name: Install Python
  raw: apt-get install -y python3

Variables

Variable Types

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Playbook variables
vars:
  app_name: myapp
  app_port: 8080

# Host variables (inventory)
[webservers]
web1 ansible_host=192.168.1.10 app_port=8080

# Group variables (group_vars/webservers.yml)
app_name: myapp
app_port: 8080

# Facts (gathered automatically)
- name: Display OS
  debug:
    msg: ""

# Registered variables
- name: Get version
  command: nginx -v
  register: nginx_version

- name: Display version
  debug:
    msg: ""

Variable Precedence

  1. Command line (-e)
  2. Playbook vars
  3. Host vars
  4. Group vars
  5. Facts
  6. Role defaults

Conditionals & Loops

Conditionals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# When condition
- name: Install on Debian
  apt:
    name: nginx
  when: ansible_os_family == "Debian"

- name: Install on RedHat
  yum:
    name: nginx
  when: ansible_os_family == "RedHat"

# Multiple conditions
- name: Install package
  apt:
    name: nginx
  when:
    - ansible_os_family == "Debian"
    - ansible_distribution_version == "22.04"

# Check if file exists
- name: Copy config
  copy:
    src: config.conf
    dest: /etc/config.conf
  when: config_file is defined

Loops

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Simple loop
- name: Install packages
  apt:
    name: ""
    state: present
  loop:
    - nginx
    - mysql
    - redis

# Loop with dictionary
- name: Create users
  user:
    name: ""
    uid: ""
  loop:
    - { name: user1, uid: 1001 }
    - { name: user2, uid: 1002 }

# Loop with condition
- name: Install packages
  apt:
    name: ""
  loop: ""
  when: item is not skipped

Handlers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
- name: Configure Nginx
  hosts: webservers
  tasks:
    - name: Update config
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: restart nginx

    - name: Update site config
      template:
        src: site.conf.j2
        dest: /etc/nginx/sites-available/default
      notify: restart nginx

  handlers:
    - name: restart nginx
      systemd:
        name: nginx
        state: restarted

Roles

Role Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
roles/
  webserver/
    tasks/
      main.yml
    handlers/
      main.yml
    vars/
      main.yml
    defaults/
      main.yml
    templates/
      nginx.conf.j2
    files/
      index.html
    meta/
      main.yml

Using Roles

1
2
3
4
5
6
7
8
---
- name: Configure servers
  hosts: all
  roles:
    - webserver
    - database
    - { role: common, tags: ['common'] }
    - { role: app, when: app_install | bool }

Tags

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
- name: Install packages
  apt:
    name: nginx
  tags:
    - packages
    - web

- name: Configure service
  template:
    src: config.j2
    dest: /etc/config.conf
  tags: config

# Run with tags
ansible-playbook playbook.yml --tags "packages,web"
ansible-playbook playbook.yml --skip-tags "debug"

Vault

Encrypt Files

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create encrypted file
ansible-vault create secrets.yml

# Edit encrypted file
ansible-vault edit secrets.yml

# View encrypted file
ansible-vault view secrets.yml

# Encrypt existing file
ansible-vault encrypt secrets.yml

# Decrypt file
ansible-vault decrypt secrets.yml

# Change password
ansible-vault rekey secrets.yml

Using Vault

1
2
3
4
5
6
# In playbook
vars_files:
  - secrets.yml

# Or include
- include_vars: secrets.yml
1
2
3
# Run with vault
ansible-playbook playbook.yml --ask-vault-pass
ansible-playbook playbook.yml --vault-password-file vault.txt

Error Handling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Ignore errors
- name: Command that might fail
  command: /usr/bin/might-fail
  ignore_errors: yes

# Error handling block
- name: Try operation
  block:
    - name: Risky task
      command: /usr/bin/risky
  rescue:
    - name: Handle error
      debug:
        msg: "Error occurred, continuing..."
  always:
    - name: Always run
      debug:
        msg: "This always runs"

Debugging

1
2
3
4
5
6
7
8
9
10
11
12
13
# Debug variables
- name: Debug variable
  debug:
    msg: ""

- name: Debug all vars
  debug:
    var: hostvars[inventory_hostname]

# Pause for debugging
- name: Pause
  pause:
    prompt: "Press Enter to continue"

Best Practices

File Organization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
project/
├── playbooks/
│   ├── site.yml
│   ├── webservers.yml
│   └── dbservers.yml
├── inventory/
│   ├── production.ini
│   └── staging.ini
├── group_vars/
│   ├── all.yml
│   └── webservers.yml
├── host_vars/
│   └── web1.yml
├── roles/
│   └── common/
└── ansible.cfg

ansible.cfg

1
2
3
4
5
6
7
8
[defaults]
inventory = inventory/production.ini
roles_path = roles
host_key_checking = False
retry_files_enabled = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts

Quick Reference

CommandDescription
ansible all -m pingTest connectivity
ansible-playbook playbook.ymlRun playbook
ansible-playbook playbook.yml --checkDry run
ansible-playbook playbook.yml --tags webRun tagged tasks
ansible-vault create file.ymlCreate encrypted file
ansible-galaxy init role_nameCreate new role
ansible all -a "uptime"Run ad-hoc command

Common Patterns

Idempotent Package Installation

1
2
3
4
5
6
7
8
9
- name: Install packages
  apt:
    name: ""
    state: present
    update_cache: yes
  vars:
    packages:
      - nginx
      - mysql-server

Conditional Service Restart

1
2
3
4
5
6
- name: Update config
  template:
    src: config.j2
    dest: /etc/config.conf
  notify: restart service
  when: config_changed | default(false)

File Backup

1
2
3
4
5
6
- name: Backup config
  copy:
    src: /etc/config.conf
    dest: /etc/config.conf.backup
    remote_src: yes
  when: backup_config | default(true)

Resources

This post is licensed under CC BY 4.0 by the author.