Quick Start
Want to automate infrastructure management without writing complex scripts? This quick start introduces essential Ansible concepts through practical examples. You’ll build from simple playbooks to multi-host automation workflows.
This tutorial provides 5-30% coverage using the touchpoints approach - 10 core concepts with runnable examples. After completing this guide, continue to By Example - Beginner for comprehensive 0-40% coverage.
Prerequisites
Before starting, ensure you have completed Initial Setup. You should have:
- Ansible installed and verified
- Experience running basic playbooks
- Understanding of localhost targeting
- A terminal and text editor ready
Learning Path
This quick start covers 10 essential Ansible touchpoints:
%% Color Palette: Blue #0173B2, Orange #DE8F05, Teal #029E73, Purple #CC78BC
graph TD
A["1. Playbook Structure"] --> B["2. Inventory Files"]
B --> C["3. Core Modules"]
C --> D["4. Variables"]
D --> E["5. Facts"]
E --> F["6. Handlers"]
F --> G["7. Conditionals"]
G --> H["8. Loops"]
H --> I["9. Roles"]
I --> J["10. Vault"]
style A fill:#0173B2,color:#fff
style B fill:#0173B2,color:#fff
style C fill:#029E73,color:#fff
style D fill:#029E73,color:#fff
style E fill:#DE8F05,color:#fff
style F fill:#DE8F05,color:#fff
style G fill:#CC78BC,color:#fff
style H fill:#CC78BC,color:#fff
style I fill:#0173B2,color:#fff
style J fill:#DE8F05,color:#fff
Concept 1: Playbook Structure
What: YAML files declaring desired system state with plays and tasks.
Why: Foundation for all Ansible automation - declarative infrastructure as code.
Example: Multi-Task Playbook
Create playbook-structure.yml:
---
- name: Demonstrate playbook structure
hosts: localhost
gather_facts: false
tasks:
- name: Create directory
ansible.builtin.file:
path: /tmp/ansible-demo
state: directory
mode: "0755"
- name: Create file with content
ansible.builtin.copy:
dest: /tmp/ansible-demo/info.txt
content: |
Ansible playbook executed successfully
Timestamp: {{ ansible_date_time.iso8601 | default('Unknown') }}
mode: "0644"
- name: Display success message
ansible.builtin.debug:
msg: "Playbook completed - check /tmp/ansible-demo/info.txt"Run:
ansible-playbook playbook-structure.ymlKey points:
- One playbook file can contain multiple plays
- Each play targets specific hosts
- Tasks execute sequentially within a play
- Idempotent - safe to run multiple times
Concept 2: Inventory Files
What: Define target hosts and groups for automation.
Why: Manage infrastructure at scale with organized host groupings.
Example: Static Inventory
Create inventory.ini:
# Web servers group
[webservers]
web1.example.com
web2.example.com
# Database servers group
[databases]
db1.example.com
db2.example.com
# All production servers
[production:children]
webservers
databases
# Group variables
[production:vars]
ansible_user=deploy
ansible_port=22Create inventory-demo.yml:
---
- name: Inventory demonstration
hosts: localhost
gather_facts: false
tasks:
- name: Show inventory structure
ansible.builtin.debug:
msg: |
Inventories organize hosts into groups
Groups enable targeted automation
Variables can be set per-group
This playbook uses localhost as safe demoRun with custom inventory:
ansible-inventory -i inventory.ini --list
ansible-playbook -i inventory.ini inventory-demo.ymlKey points:
- Inventory organizes hosts into logical groups
- Groups enable selective task execution
- Variables set at group level apply to all hosts
- INI or YAML format supported
Concept 3: Core Modules
What: Built-in functions performing specific infrastructure operations.
Why: Ansible’s power comes from 3000+ modules for every task.
Example: Essential Modules
Create core-modules.yml:
---
- name: Core modules demonstration
hosts: localhost
gather_facts: false
tasks:
- name: File module - create directory
ansible.builtin.file:
path: /tmp/ansible-modules
state: directory
mode: "0755"
- name: Copy module - write file
ansible.builtin.copy:
dest: /tmp/ansible-modules/data.txt
content: "Sample data\n"
- name: Lineinfile module - modify file
ansible.builtin.lineinfile:
path: /tmp/ansible-modules/data.txt
line: "Added by lineinfile module"
state: present
- name: Command module - execute command
ansible.builtin.command:
cmd: cat /tmp/ansible-modules/data.txt
register: file_content
changed_when: false
- name: Debug module - show output
ansible.builtin.debug:
var: file_content.stdout_linesRun:
ansible-playbook core-modules.ymlKey points:
file: Manage files, directories, symlinkscopy: Copy files with inline contentlineinfile: Edit specific lines in filescommand: Execute shell commandsdebug: Display variables and messages- Each module is idempotent by default
Concept 4: Variables
What: Store reusable values for flexibility and parameterization.
Why: Make playbooks generic and environment-agnostic.
Example: Variable Usage
Create variables.yml:
---
- name: Variables demonstration
hosts: localhost
gather_facts: false
vars:
app_name: "myapp"
app_version: "1.0.0"
deploy_path: "/tmp/{{ app_name }}"
config:
port: 8080
host: "localhost"
tasks:
- name: Create app directory
ansible.builtin.file:
path: "{{ deploy_path }}"
state: directory
- name: Create config file
ansible.builtin.copy:
dest: "{{ deploy_path }}/config.txt"
content: |
Application: {{ app_name }}
Version: {{ app_version }}
Port: {{ config.port }}
Host: {{ config.host }}
- name: Display deployment info
ansible.builtin.debug:
msg: "Deployed {{ app_name }} v{{ app_version }} to {{ deploy_path }}"Run:
ansible-playbook variables.ymlRun with extra variables:
ansible-playbook variables.yml -e "app_version=2.0.0"Key points:
- Define with
vars:keyword in play - Access with Jinja2 template syntax
{{ variable }} - Override with
-eflag at runtime - Support nested dictionaries and lists
- Variable precedence: extra vars > play vars > inventory vars
Concept 5: Facts
What: Automatically gathered system information about target hosts.
Why: Make decisions based on OS, hardware, network configuration.
Example: Using Facts
Create facts.yml:
---
- name: Facts demonstration
hosts: localhost
gather_facts: true
tasks:
- name: Display operating system
ansible.builtin.debug:
msg: "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: Display hostname
ansible.builtin.debug:
msg: "Hostname: {{ ansible_hostname }}"
- name: Display Python version
ansible.builtin.debug:
msg: "Python: {{ ansible_python_version }}"
- name: Display memory info
ansible.builtin.debug:
msg: "Total RAM: {{ ansible_memtotal_mb }} MB"
- name: Display CPU cores
ansible.builtin.debug:
msg: "CPU cores: {{ ansible_processor_vcpus }}"
- name: Show all network interfaces
ansible.builtin.debug:
msg: "Interfaces: {{ ansible_interfaces | join(', ') }}"Run:
ansible-playbook facts.ymlView all available facts:
ansible localhost -m ansible.builtin.setupKey points:
gather_facts: truecollects system info automatically- Facts stored in variables like
ansible_* - Access facts with Jinja2 templates
- Use for conditional logic based on OS/hardware
- Disable with
gather_facts: falsefor faster execution
Concept 6: Handlers
What: Tasks that run only when notified and only once per play.
Why: Restart services only when configuration changes occur.
Example: Handlers for Service Restart
Create handlers.yml:
---
- name: Handlers demonstration
hosts: localhost
gather_facts: false
handlers:
- name: Restart application
ansible.builtin.debug:
msg: "APPLICATION RESTARTED (simulated)"
- name: Reload configuration
ansible.builtin.debug:
msg: "CONFIGURATION RELOADED (simulated)"
tasks:
- name: Create config directory
ansible.builtin.file:
path: /tmp/app-config
state: directory
notify: Reload configuration
- name: Update application config
ansible.builtin.copy:
dest: /tmp/app-config/app.conf
content: |
port=8080
debug=false
notify:
- Reload configuration
- Restart application
- name: Another task without changes
ansible.builtin.debug:
msg: "This task does not trigger handlers"Run:
ansible-playbook handlers.ymlKey points:
- Handlers run at end of play (after all tasks)
- Only run when notified by
notify:keyword - Run once even if notified multiple times
- Execute in order defined, not order notified
- Perfect for service restarts after config changes
Concept 7: Conditionals
What: Execute tasks only when specific conditions are met.
Why: Support multi-OS playbooks and environment-specific logic.
Example: Conditional Execution
Create conditionals.yml:
---
- name: Conditionals demonstration
hosts: localhost
gather_facts: true
vars:
environment: "production"
enable_debug: false
tasks:
- name: Production-only task
ansible.builtin.debug:
msg: "Running in PRODUCTION mode"
when: environment == "production"
- name: Development-only task
ansible.builtin.debug:
msg: "Running in DEVELOPMENT mode"
when: environment == "development"
- name: Debug mode task
ansible.builtin.debug:
msg: "Debug logging enabled"
when: enable_debug
- name: Linux-specific task
ansible.builtin.debug:
msg: "Detected Linux system"
when: ansible_system == "Linux"
- name: Multiple conditions (AND)
ansible.builtin.debug:
msg: "Production Linux system"
when:
- environment == "production"
- ansible_system == "Linux"
- name: Multiple conditions (OR)
ansible.builtin.debug:
msg: "Either production OR debug enabled"
when: environment == "production" or enable_debugRun:
ansible-playbook conditionals.ymlRun with different environment:
ansible-playbook conditionals.yml -e "environment=development"Key points:
- Use
when:keyword for conditions - Conditions use Jinja2 expressions
- Multiple conditions: list for AND,
orfor OR - Combine with facts for OS-specific tasks
- Skip tasks cleanly without errors
Concept 8: Loops
What: Execute same task multiple times with different inputs.
Why: Avoid repetitive task definitions for similar operations.
Example: Looping Through Lists
Create loops.yml:
---
- name: Loops demonstration
hosts: localhost
gather_facts: false
vars:
packages:
- name: package1
version: "1.0"
- name: package2
version: "2.0"
- name: package3
version: "1.5"
tasks:
- name: Create multiple directories
ansible.builtin.file:
path: "/tmp/loop-demo/{{ item }}"
state: directory
loop:
- dir1
- dir2
- dir3
- name: Create files with different content
ansible.builtin.copy:
dest: "/tmp/loop-demo/{{ item.name }}.txt"
content: "Version: {{ item.version }}\n"
loop: "{{ packages }}"
- name: Loop with index
ansible.builtin.debug:
msg: "Item {{ idx }}: {{ item }}"
loop:
- first
- second
- third
loop_control:
index_var: idx
- name: Loop dictionary
ansible.builtin.debug:
msg: "Key: {{ item.key }}, Value: {{ item.value }}"
loop: "{{ {'a': 1, 'b': 2, 'c': 3} | dict2items }}"Run:
ansible-playbook loops.ymlKey points:
loop:keyword iterates over lists- Access current item with
{{ item }} - Loop over complex data structures (dictionaries)
loop_controlprovides additional options- Use
index_varto access loop index - Prefer
loopover deprecatedwith_*keywords
Concept 9: Roles
What: Organize playbooks into reusable, structured components.
Why: Share automation code across projects and teams.
Example: Creating and Using Roles
Create role structure:
mkdir -p roles/webserver/{tasks,handlers,templates,vars,defaults}Create roles/webserver/tasks/main.yml:
---
- name: Create web directory
ansible.builtin.file:
path: "{{ web_root }}"
state: directory
mode: "0755"
- name: Deploy index page
ansible.builtin.template:
src: index.html.j2
dest: "{{ web_root }}/index.html"
mode: "0644"
notify: Reload webserverCreate roles/webserver/handlers/main.yml:
---
- name: Reload webserver
ansible.builtin.debug:
msg: "Webserver reloaded (simulated)"Create roles/webserver/templates/index.html.j2:
<!DOCTYPE html>
<html>
<head>
<title>{{ server_name }}</title>
</head>
<body>
<h1>{{ server_name }}</h1>
<p>Deployed by Ansible</p>
<p>Environment: {{ environment }}</p>
</body>
</html>Create roles/webserver/defaults/main.yml:
---
web_root: /tmp/webserver
server_name: "Demo Server"
environment: "development"Create roles.yml playbook:
---
- name: Roles demonstration
hosts: localhost
gather_facts: false
roles:
- role: webserver
vars:
server_name: "Production Web Server"
environment: "production"Run:
ansible-playbook roles.ymlVerify:
cat /tmp/webserver/index.htmlKey points:
- Roles organize automation into reusable units
- Standard directory structure: tasks, handlers, templates, vars, defaults
- Include roles with
roles:keyword - Override role variables in playbook
- Share roles via Ansible Galaxy
- Role dependencies managed in
meta/main.yml
Concept 10: Vault (Secrets Management)
What: Encrypt sensitive data in playbooks and inventory.
Why: Secure passwords, API keys, certificates in version control.
Example: Encrypted Variables
Create unencrypted file secrets.yml:
---
db_password: "super_secret_password"
api_key: "abc123xyz789"Encrypt with Vault:
# Encrypt file
ansible-vault encrypt secrets.yml
# Enter password when promptedCreate vault-demo.yml:
---
- name: Vault demonstration
hosts: localhost
gather_facts: false
vars_files:
- secrets.yml
tasks:
- name: Use encrypted variable (safe - not displayed)
ansible.builtin.debug:
msg: "Database password is configured"
- name: Create config with secret
ansible.builtin.copy:
dest: /tmp/app-config.txt
content: |
# Configuration file
DB_PASSWORD={{ db_password }}
API_KEY={{ api_key }}
mode: "0600"Run with vault password:
ansible-playbook vault-demo.yml --ask-vault-pass
echo "my_vault_password" > .vault-pass
ansible-playbook vault-demo.yml --vault-password-file .vault-pass
rm .vault-passOther vault operations:
ansible-vault view secrets.yml
ansible-vault edit secrets.yml
ansible-vault decrypt secrets.yml
ansible-vault rekey secrets.ymlKey points:
- Vault encrypts YAML files containing secrets
- Use
--ask-vault-passor--vault-password-file - Encrypt entire files or specific variables
- Safe to commit encrypted files to version control
- Multiple vault IDs for different secret scopes
- Never commit vault password files
Learning Path Summary
You’ve completed 10 essential Ansible touchpoints:
%% Color Palette: Blue #0173B2, Orange #DE8F05, Teal #029E73, Purple #CC78BC
graph TD
A["Playbooks &<br/>Inventory"] --> B["Modules &<br/>Variables"]
B --> C["Facts &<br/>Handlers"]
C --> D["Conditionals &<br/>Loops"]
D --> E["Roles &<br/>Vault"]
style A fill:#0173B2,color:#fff
style B fill:#029E73,color:#fff
style C fill:#DE8F05,color:#fff
style D fill:#CC78BC,color:#fff
style E fill:#0173B2,color:#fff
Next Steps
Now that you understand core Ansible concepts:
- By Example - Beginner: Deep dive into 0-40% coverage with 25+ annotated examples
- Visit By Example - Beginner
- By Example - Intermediate: Advance to 40-75% coverage with complex workflows
- Continue to By Example - Intermediate
- By Example - Advanced: Master 75-95% coverage with enterprise patterns
- Progress to By Example - Advanced
Further Resources
Official Documentation:
- Ansible User Guide - Comprehensive guides
- Module Index - All 3000+ modules
- Best Practices - Production patterns
- Ansible Galaxy - Community roles and collections
Key Concepts:
- Playbooks: YAML files declaring desired state
- Inventory: Host and group organization
- Modules: Built-in functions for infrastructure tasks
- Variables: Parameterize playbooks for flexibility
- Facts: Auto-discovered system information
- Handlers: Conditional task execution (service restarts)
- Roles: Reusable automation components
- Vault: Encrypted secrets management
Summary
You’ve completed the Ansible Quick Start with 5-30% coverage! You now understand:
- Playbook structure and multi-task workflows
- Inventory organization and host grouping
- Core modules for common operations
- Variable definition and usage
- Fact gathering and system information
- Handlers for conditional actions
- Conditional execution and loops
- Role-based code organization
- Vault secrets management
Continue your journey with comprehensive By Example tutorials for deeper mastery of Ansible automation.