Ansible Basics Cheat Sheet

Key Concepts

  • Control Node: Where Ansible is installed and runs from
  • Managed Nodes: Servers managed by Ansible (no agent required)
  • Inventory: List of managed nodes
  • Playbooks: YAML files describing automation tasks
  • Tasks: Individual units of work
  • Modules: Tools for executing specific actions
  • Roles: Reusable collections of tasks
  • Handlers: Tasks run only when notified

Installation

# Ubuntu/Debian
$ sudo apt update
$ sudo apt install ansible

# RHEL/CentOS
$ sudo yum install epel-release
$ sudo yum install ansible

# macOS
$ brew install ansible

# Python pip (recommended for version control)
$ pip install ansible

Configuration File

Location hierarchy (first one found is used):

  1. ANSIBLE_CONFIG environment variable
  2. ./ansible.cfg (current directory)
  3. ~/.ansible.cfg (home directory)
  4. /etc/ansible/ansible.cfg (system-wide)

Essential settings:

[defaults]
inventory = ./inventory
remote_user = ansible
host_key_checking = False
forks = 20
timeout = 30

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

Inventory Basics

Simple inventory file (INI format)

# Individual hosts
web1.example.com
web2.example.com ansible_host=192.168.1.101

# Groups
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com
db2.example.com

# Group of groups
[datacenter:children]
webservers
dbservers

# Variables
[webservers:vars]
http_port=80

YAML format inventory

all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
          ansible_host: 192.168.1.101
      vars:
        http_port: 80
    dbservers:
      hosts:
        db1.example.com:
        db2.example.com:

Common inventory parameters

  • ansible_host: IP address/hostname
  • ansible_port: SSH port
  • ansible_user: SSH username
  • ansible_connection: Connection type (ssh, local, docker)
  • ansible_ssh_private_key_file: SSH private key

Ad-hoc Commands

Basic syntax:

ansible [host-pattern] -m [module] -a "[module options]" [options]

Common examples:

# Ping all hosts
$ ansible all -m ping

# Run shell command
$ ansible webservers -m shell -a "uptime"

# Check facts (system info)
$ ansible web1.example.com -m setup

# File operations
$ ansible all -m file -a "path=/tmp/test state=touch mode=0644"

# Package management
$ ansible webservers -m apt -a "name=nginx state=present"

# User management
$ ansible all -b -m user -a "name=deploy state=present"

# Service management
$ ansible webservers -b -m service -a "name=nginx state=started enabled=yes"

# Copy files
$ ansible all -m copy -a "src=/local/path dest=/remote/path"

Basic Playbook Structure

---
- name: Example playbook
  hosts: webservers
  become: yes
  vars:
    http_port: 80
    max_clients: 200
  
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
        update_cache: yes
      
    - name: Configure nginx site
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/sites-available/default
      notify: Restart nginx
  
  handlers:
    - name: Restart nginx
      service:
        name: nginx
        state: restarted

Running Playbooks

# Basic execution
$ ansible-playbook playbook.yml

# Dry run (no changes)
$ ansible-playbook --check playbook.yml

# Run against specific hosts
$ ansible-playbook playbook.yml --limit web1.example.com

# Pass variables
$ ansible-playbook playbook.yml -e "http_port=8080"

# With vault password
$ ansible-playbook playbook.yml --ask-vault-pass

Variables

Variable definition in playbooks

vars:
  http_port: 80
  max_clients: 200

Variable files

# vars/server.yml
http_port: 80
max_clients: 200

Referenced in playbook:

vars_files:
  - vars/server.yml

Command line variables

$ ansible-playbook playbook.yml -e "http_port=8080 max_clients=250"
$ ansible-playbook playbook.yml --extra-vars "@vars/production.json"

Using registered variables

- name: Check service status
  command: systemctl status nginx
  register: result
  
- name: Show status
  debug:
    var: result.stdout

Conditionals

When clause

- name: Install Apache on RedHat systems
  yum:
    name: httpd
    state: present
  when: ansible_os_family == "RedHat"

- name: Create file if not exists
  file:
    path: /etc/app.conf
    state: touch
  when: not stat_result.stat.exists

Multiple conditions

- name: Install package if sufficient memory
  apt:
    name: large-app
    state: present
  when: ansible_memtotal_mb > 1024 and ansible_distribution == "Ubuntu"

Loops

Simple loop

- name: Create users
  user:
    name: "{{ item }}"
    state: present
  loop:
    - alice
    - bob
    - charlie

Loop with dictionary

- name: Create users with properties
  user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    state: present
  loop:
    - { name: alice, groups: admin }
    - { name: bob, groups: developers }
    - { name: charlie, groups: developers }

Handlers

tasks:
  - name: Configure nginx
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: Restart nginx

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

Templates (Jinja2)

Basic template (nginx.conf.j2)

server {
    listen {{ http_port | default(80) }};
    server_name {{ server_name }};
    
    root {{ doc_root }};
    
    location / {
        try_files $uri $uri/ =404;
    }
}

Conditionals in templates

{% if ansible_distribution == 'Ubuntu' %}
apt_cmd = apt-get
{% elif ansible_distribution == 'CentOS' %}
apt_cmd = yum
{% endif %}

Loops in templates

{% for host in groups['webservers'] %}
server {{ host }};
{% endfor %}

Simple Role Structure

roles/
  webserver/
    defaults/        # Default variables
      main.yml
    files/           # Static files
    handlers/        # Handlers
      main.yml
    tasks/           # Tasks
      main.yml
    templates/       # Jinja2 templates
    vars/            # Role variables
      main.yml

Creating a role

$ ansible-galaxy init rolename

Using roles in playbooks

- hosts: webservers
  roles:
    - webserver
    - database

Error Handling

Ignoring errors

- name: Run this command anyway
  command: /opt/app/setup.sh
  ignore_errors: yes

Block with rescue

- block:
    - name: Service update
      service:
        name: myapp
        state: restarted
  rescue:
    - name: Fallback task
      debug:
        msg: "Service update failed"
  always:
    - name: Always run this
      debug:
        msg: "Service update attempted"

Ansible Vault

Create encrypted file

$ ansible-vault create secrets.yml

Edit encrypted file

$ ansible-vault edit secrets.yml

Encrypt existing file

$ ansible-vault encrypt vars/credentials.yml

Run playbook with vault

$ ansible-playbook site.yml --ask-vault-pass
$ ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt

Common Modules

File management

  • file: Manage files and directories
  • copy: Copy files to remote hosts
  • template: Process Jinja2 templates
  • lineinfile: Modify specific lines in files
  • fetch: Get files from remote hosts

Package management

  • apt: Manage Debian/Ubuntu packages
  • yum: Manage RHEL/CentOS packages
  • dnf: Manage Fedora packages
  • package: Generic package manager

Service management

  • service: Manage services
  • systemd: Manage systemd services

User management

  • user: Manage user accounts
  • group: Manage groups
  • authorized_key: Add/remove SSH authorized keys

System

  • command: Execute commands
  • shell: Execute shell commands
  • reboot: Reboot systems
  • cron: Manage cron jobs
  • mount: Manage mounts

Utilities

  • debug: Print statements during execution
  • wait_for: Wait for conditions
  • assert: Assert given expressions are true
  • set_fact: Set variables

Best Practices

  1. Organization

    • Use roles for reusable code
    • Group related tasks
    • Keep playbooks focused on specific purposes
  2. Variables

    • Use descriptive names
    • Keep sensitive data in Ansible Vault
    • Set defaults in roles/defaults/main.yml
  3. Idempotence

    • Ensure tasks can run multiple times without side effects
    • Use state parameters consistently
  4. Testing

    • Use –syntax-check to validate playbooks
    • Use –check for dry runs
    • Test on staging before production
  5. Performance

    • Increase forks in ansible.cfg
    • Use gather_facts: no when not needed
    • Use –limit for targeting specific hosts
Scroll to Top