Ansible Cheatsheet
Table of Contents
- Ansible Basics
- Inventory
- Ad-Hoc Commands
- Playbooks
- Variables
- Conditionals & Loops
- Handlers
- Roles
- Ansible Vault
- Modules
- Templates
- Interview Scenarios
Ansible Basics
1. Installation
# Ubuntu/Debian
sudo apt update
sudo apt install ansible
# RHEL/CentOS
sudo yum install ansible
# macOS
brew install ansible
# Python pip
pip install ansible
# Verify
ansible --version2. Configuration
# ansible.cfg (priority order)
1. ANSIBLE_CONFIG environment variable
2. ./ansible.cfg (in current directory)
3. ~/.ansible.cfg (home directory)
4. /etc/ansible/ansible.cfg (default)
# Example ansible.cfg
[defaults]
inventory = ./inventory
host_key_checking = False
retry_files_enabled = False
forks = 20
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = FalseInventory
3. Static Inventory
# inventory/hosts (INI format)
[webservers]
web1.example.com
web2.example.com ansible_host=10.0.0.2
web3.example.com ansible_host=10.0.0.3 ansible_port=2222
[databases]
db1.example.com
db2.example.com
[production:children]
webservers
databases
[all:vars]
ansible_user=admin
ansible_ssh_private_key_file=~/.ssh/id_rsa
[webservers:vars]
http_port=80
max_clients=2004. YAML Inventory
# inventory/hosts.yml
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_host: 10.0.0.2
web3.example.com:
ansible_host: 10.0.0.3
ansible_port: 2222
vars:
http_port: 80
max_clients: 200
databases:
hosts:
db1.example.com:
db2.example.com:
vars:
ansible_user: admin
ansible_ssh_private_key_file: ~/.ssh/id_rsa5. Dynamic Inventory
# List hosts
ansible-inventory --list
ansible-inventory --graph
# AWS EC2 dynamic inventory (using plugin)
# inventory/aws_ec2.yml
plugin: aws_ec2
regions:
- us-east-1
keyed_groups:
- key: tags.Environment
prefix: envAd-Hoc Commands
6. Basic Commands
# Ping all hosts
ansible all -m ping
# Ping specific group
ansible webservers -m ping
# Check uptime
ansible all -a "uptime"
# Run as sudo
ansible all -a "systemctl status nginx" --become
# Use specific user
ansible all -a "whoami" -u admin
# Limit to specific hosts
ansible all -m ping --limit web1.example.com
ansible all -m ping --limit "web1.example.com,web2.example.com"7. Common Ad-Hoc Operations
# Install package
ansible webservers -m apt -a "name=nginx state=present" --become
# Restart service
ansible webservers -m service -a "name=nginx state=restarted" --become
# Copy file
ansible all -m copy -a "src=/local/file dest=/remote/file mode=0644"
# Create directory
ansible all -m file -a "path=/opt/app state=directory mode=0755" --become
# Fetch file from remote
ansible all -m fetch -a "src=/etc/hosts dest=/tmp/hosts"
# Check disk space
ansible all -a "df -h"
# Gather facts
ansible all -m setup
ansible all -m setup -a "filter=ansible_distribution*"Playbooks
8. Basic Playbook Structure
# playbook.yml
---
- name: Configure web servers
hosts: webservers
become: yes
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Start nginx service
service:
name: nginx
state: started
enabled: yes
- name: Copy index.html
copy:
src: files/index.html
dest: /var/www/html/index.html
mode: '0644'9. Run Playbooks
# Run playbook
ansible-playbook playbook.yml
# Check syntax
ansible-playbook playbook.yml --syntax-check
# Dry run
ansible-playbook playbook.yml --check
# Verbose output
ansible-playbook playbook.yml -v
ansible-playbook playbook.yml -vvv
# Limit to specific hosts
ansible-playbook playbook.yml --limit web1.example.com
# Tags
ansible-playbook playbook.yml --tags="install"
ansible-playbook playbook.yml --skip-tags="install"
# Start at specific task
ansible-playbook playbook.yml --start-at-task="Install nginx"Variables
10. Define Variables
# In playbook
---
- name: Example
hosts: webservers
vars:
http_port: 80
server_name: example.com
tasks:
- name: Configure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
# In separate file
# vars/main.yml
http_port: 80
server_name: example.com
# Use in playbook
---
- name: Example
hosts: webservers
vars_files:
- vars/main.yml11. Variable Precedence
# Lowest to highest precedence:
1. role defaults
2. inventory file/script group vars
3. inventory group_vars/all
4. inventory group_vars/*
5. playbook group_vars/all
6. playbook group_vars/*
7. inventory file/script host vars
8. inventory host_vars/*
9. playbook host_vars/*
10. host facts
11. play vars
12. play vars_prompt
13. play vars_files
14. role vars
15. block vars
16. task vars
17. extra vars (-e option)12. Registered Variables
- name: Get service status
command: systemctl status nginx
register: nginx_status
ignore_errors: yes
- name: Show status
debug:
msg: "{{ nginx_status.stdout }}"
- name: Conditional on result
service:
name: nginx
state: started
when: nginx_status.rc != 0Conditionals & Loops
13. Conditionals
- name: Install package on Debian
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install package on RedHat
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Multiple conditions
service:
name: nginx
state: started
when:
- ansible_os_family == "Debian"
- ansible_distribution_version == "20.04"
- name: OR condition
debug:
msg: "Development or staging"
when: environment == "dev" or environment == "staging"14. Loops
# Simple loop
- name: Install multiple packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- git
- curl
# Loop with dictionary
- name: Create users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'john', groups: 'developers' }
- { name: 'jane', groups: 'admins' }
# Loop with_items (legacy)
- name: Install packages
apt:
name: "{{ item }}"
state: present
with_items:
- nginx
- git
# Loop over dict
- name: Configure firewall
ufw:
rule: allow
port: "{{ item.value }}"
proto: tcp
loop: "{{ lookup('dict', ports) }}"
vars:
ports:
http: 80
https: 443Handlers
15. Handlers
---
- name: Configure web server
hosts: webservers
tasks:
- name: Copy nginx config
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: Install package
apt:
name: nginx-extras
state: present
notify:
- restart nginx
- reload nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
- name: reload nginx
service:
name: nginx
state: reloadedRoles
16. Create Role
# Generate role structure
ansible-galaxy init nginx
# Role directory structure:
nginx/
├── defaults/ # Default variables
│ └── main.yml
├── files/ # Static files
├── handlers/ # Handlers
│ └── main.yml
├── meta/ # Role metadata
│ └── main.yml
├── tasks/ # Main tasks
│ └── main.yml
├── templates/ # Jinja2 templates
├── tests/ # Test playbooks
│ └── test.yml
└── vars/ # Other variables
└── main.yml17. Use Roles
# playbook.yml
---
- name: Configure servers
hosts: webservers
roles:
- common
- nginx
- { role: database, when: "'databases' in group_names" }
# With variables
- name: Configure servers
hosts: webservers
roles:
- role: nginx
vars:
http_port: 808018. Install Roles from Galaxy
# Install role
ansible-galaxy install geerlingguy.nginx
# Install from requirements
# requirements.yml
---
roles:
- name: geerlingguy.nginx
version: 3.1.2
- src: https://github.com/user/role
name: custom_role
ansible-galaxy install -r requirements.yml
# List installed roles
ansible-galaxy list
# Remove role
ansible-galaxy remove geerlingguy.nginxAnsible Vault
19. Vault Operations
# Create encrypted file
ansible-vault create secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Encrypt existing file
ansible-vault encrypt vars.yml
# Decrypt file
ansible-vault decrypt secrets.yml
# View encrypted file
ansible-vault view secrets.yml
# Change password
ansible-vault rekey secrets.yml
# Encrypt string
ansible-vault encrypt_string 'secret_password' --name 'db_password'20. Use Vaulted Files
# Run playbook with vault
ansible-playbook playbook.yml --ask-vault-pass
# Use password file
ansible-playbook playbook.yml --vault-password-file ~/.vault_pass
# Multiple vault passwords
ansible-playbook playbook.yml --vault-id dev@prompt --vault-id prod@~/.vault_pass_prodModules
21. File Modules
# Copy file
- copy:
src: /local/file
dest: /remote/file
owner: root
group: root
mode: '0644'
# Template (Jinja2)
- template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
backup: yes
# Create file/directory
- file:
path: /opt/app
state: directory
mode: '0755'
# Create symlink
- file:
src: /usr/local/app/current
dest: /usr/local/app/releases/v1.0
state: link
# Fetch file from remote
- fetch:
src: /etc/hosts
dest: /tmp/hosts
flat: yes22. Package Modules
# Generic package module
- package:
name: nginx
state: present
# APT (Debian/Ubuntu)
- apt:
name: nginx
state: present
update_cache: yes
cache_valid_time: 3600
# YUM/DNF (RHEL/CentOS)
- yum:
name: nginx
state: latest
# Multiple packages
- apt:
name:
- nginx
- git
- curl
state: present23. Service Modules
- service:
name: nginx
state: started
enabled: yes
# Systemd
- systemd:
name: nginx
state: restarted
daemon_reload: yes
enabled: yesTemplates
24. Jinja2 Templates
# templates/nginx.conf.j2
server {
listen {{ http_port }};
server_name {{ server_name }};
{% if enable_ssl %}
listen 443 ssl;
ssl_certificate {{ ssl_cert_path }};
ssl_certificate_key {{ ssl_key_path }};
{% endif %}
{% for location in locations %}
location {{ location.path }} {
proxy_pass {{ location.backend }};
}
{% endfor %}
}
# Variables and filters
{{ variable | default('default_value') }}
{{ variable | upper }}
{{ variable | lower }}
{{ list_var | join(', ') }}
{{ dict_var | to_json }}
{{ dict_var | to_yaml }}25. Use Templates
- name: Configure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
validate: 'nginx -t -c %s'
notify: restart nginxInterview Scenarios
Scenario 1: Deploy Application Stack
---
- name: Deploy LAMP stack
hosts: webservers
become: yes
vars:
mysql_root_password: !vault |
$ANSIBLE_VAULT;1.1;AES256...
tasks:
- name: Install packages
apt:
name:
- apache2
- mysql-server
- php
- php-mysql
state: present
update_cache: yes
- name: Start services
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- apache2
- mysql
- name: Deploy application
git:
repo: 'https://github.com/user/app.git'
dest: /var/www/html
version: main
notify: restart apache
handlers:
- name: restart apache
service:
name: apache2
state: restartedScenario 2: Zero-Downtime Deployment
---
- name: Rolling deployment
hosts: webservers
serial: 1 # One host at a time
pre_tasks:
- name: Remove from load balancer
local_action:
module: uri
url: "http://loadbalancer/api/remove/{{ inventory_hostname }}"
method: POST
tasks:
- name: Deploy new version
copy:
src: app-v2.0.tar.gz
dest: /opt/app/
- name: Extract archive
unarchive:
src: /opt/app/app-v2.0.tar.gz
dest: /opt/app/
remote_src: yes
- name: Restart application
systemd:
name: myapp
state: restarted
- name: Wait for service
wait_for:
port: 8080
delay: 5
timeout: 60
post_tasks:
- name: Add back to load balancer
local_action:
module: uri
url: "http://loadbalancer/api/add/{{ inventory_hostname }}"
method: POST
- name: Smoke test
uri:
url: "http://{{ inventory_hostname }}:8080/health"
status_code: 200Scenario 3: Security Hardening
---
- name: Security hardening
hosts: all
become: yes
tasks:
- name: Update all packages
apt:
upgrade: dist
update_cache: yes
- name: Disable root login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
notify: restart sshd
- name: Configure firewall
ufw:
rule: "{{ item.rule }}"
port: "{{ item.port }}"
proto: "{{ item.proto }}"
loop:
- { rule: 'allow', port: '22', proto: 'tcp' }
- { rule: 'allow', port: '80', proto: 'tcp' }
- { rule: 'allow', port: '443', proto: 'tcp' }
- name: Enable firewall
ufw:
state: enabled
- name: Install fail2ban
apt:
name: fail2ban
state: present
- name: Enable automatic security updates
apt:
name: unattended-upgrades
state: present
handlers:
- name: restart sshd
service:
name: sshd
state: restartedTotal Commands: 80+ Ansible operations
Last updated on