Ansible: Infrastructure Automation Platform
Simple IT automation platform that automates software provisioning, configuration management, and application deployment. Agentless architecture with idempotent, declarative YAML playbooks.
- Step 1
What is Ansible?
Ansible is a simple, agentless IT automation platform that automates software provisioning, configuration management, application deployment, and other IT processes. Created by Michael DeHaan in 2012 and now owned by Red Hat, Ansible has become one of the most popular configuration management tools with over 63,000 GitHub stars.
Key philosophy: Simplicity. Ansible uses agentless architecture (SSH for Linux/Windows, no background service needed), human-readable YAML playbooks, and push-based execution.
Core capabilities:
- Configuration management: Configure systems once, maintain consistently
- Application deployment: Automate app releases and updates
- Orchestration: Coordinate multiple systems for complex workflows
- Cloud automation: Manage AWS, Azure, Google Cloud, and more
- Multi-cloud and hybrid infrastructure support
- Security and compliance automation
Idempotency: Playbooks are idempotent — running the same playbook multiple times produces the same result, only making changes when needed.
Key concepts: ├── Playbooks (.yaml) - Declarative automation scripts ├── Roles - Reusable, organized playbook components ├── Inventory - List of managed systems ├── Modules - Reusable automation units (7000+ available) ├── Facts - System information gathered via gather_facts └── Galaxy - Community repository for roles and collections - Step 2
Technology stack
Ansible is built primarily in Python with a modular, extensible architecture designed for agentless operation.
Core implementation:
- Language: Python 3.10+ (3.11, 3.12, 3.13 supported)
- Architecture: Agentless, push-based via SSH (Linux) or WinRM (Windows)
- Configuration language: YAML (YAML Ain't Markup Language)
- Package management: pip, PyPI for dependencies
Key libraries and dependencies:
- Jinja2: Template engine for dynamic configuration files
- PyYAML: YAML parsing for playbooks
- Paramiko: SSH2 protocol implementation (pure Python)
- libssh: Alternative SSH library for better performance
- Cryptography: SSL/TLS, encryption operations
- Virtual environments: venv, virtualenv for isolation
Control node requirements:
- Ansible is installed only on the control node (central management system)
- Managed nodes require only SSH access (Linux) or WinRM (Windows) — no Ansible installation needed
- Control node can be any machine capable of running Python
Execution model:
- Control node SSHs into targets and copies small Python modules
- Modules execute on the target and return JSON results
- Ad-hoc commands or playbooks can be run
- State changes are applied and verified
Architecture: ┌──────────────────┐ │ Control Node │ ← Ansible installed here │ (Ansible runs) │ └──────┬───────────┘ │ SSH/WinRM ┌──┴─────┐ │ │ ┌───▼────┐ ┌─▼───────┐ │ Linux │ │ Windows │ │ Node │ │ Node │ │ │ │ (WinRM) │ └───────┘ └─────────┘ No software needed on target nodes! - Step 3
Installation: Control node setup
Ansible is installed only on the control node — the machine that manages your infrastructure. Choose the installation method that best fits your environment.
Ubuntu/Debian (APT): Ubuntu repositories may have older versions. For the latest, use the Ansible repo or pip.
Red Hat/CentOS/Fedora (Yum/DNF): Ansible is available in EPEL or the official Ansible repository for RHEL.
macOS (Homebrew): Simple installation via Homebrew package manager.
pip (Recommended for latest version): Install from PyPI using pip. Consider using a virtual environment for isolation.
Docker/Podman: Run Ansible in a container for portable, reproducible environments.
# Method 1: pip (Recommended - latest version) pip install ansible-core # Verify installation ansible --version # Method 2: Ubuntu/Debian sudo apt update sudo apt install ansible # For latest version, add Ansible repo first: sudo apt-get install -y software-properties-common sudo add-apt-repository --yes --update ppa:ansible/ansible sudo apt-get install -y ansible # Method 3: RHEL/CentOS 8+ sudo dnf install -y epel-release sudo dnf install -y ansible # Method 4: macOS brew install ansible # Method 5: Docker podman run -it --rm \ -v $PWD:/projects:Z \ -w /projects \ quay.io/ansible/ansible-runner \ ansible --version # Verify installation ansible --version # Output shows version, config file, and module paths - Step 4
First connection
Before running playbooks, ensure Ansible can connect to your target systems. Set up the inventory file listing the hosts you want to manage, then test connectivity with the built-in ping module.
For SSH connections (Linux):
- SSH keys are recommended for passwordless authentication
- Ansible uses the system SSH configuration by default
- Public key authentication is set up once per user
For Windows connections:
- Requires WinRM to be enabled on target Windows systems
- Use ansible-windows playbook or PowerShell scripts to configure WinRM
- Authentication via username/password or certificate
Local testing: You can test Ansible against localhost without a remote target.
# Step 1: Create inventory file (hosts) ano hosts # Add: # [web] # web1 ansible_host=192.168.1.100 # # [db] # db1 ansible_host=192.168.1.101 # # [all:vars] # ansible_user=ubuntu # ansible_password=yourpassword # Better: use SSH keys # Step 2: Test connectivity with ping module ansible all -i hosts -m ping # Expected output: # web1 | SUCCESS => {"changed": false, "ping": "pong"} # db1 | SUCCESS => {"changed": false, "ping": "pong"} # Step 3: SSH key setup (recommended - no password needed) ssh-keygen -t ed25519 -C "ansible@control" ssh-copy-id user@target_host # Now run ansible without password prompts # Step 4: Test passwordless connection ansible all -m ping # Uses default /etc/ansible/hosts⚠ Heads up: Never use passwords in playbooks or version control. Use SSH keys with passphrases for security, or Ansible Vault for sensitive data. - Step 5
Inventory management
Inventory is the central list of all managed hosts in Ansible. You can define hosts statically in files, dynamically via plugins and scripts, or using dynamic inventory plugins for cloud providers.
Static inventory formats:
- INI format: Traditional, human-readable
- YAML format: More structured, supports nested data
- Host aliases: Assign friendly names to IP addresses
Grouping:
- Define groups of hosts for logical organization (web, db, prod, dev)
- Nested groups: Child groups inherit from parent groups
- Host variables and group variables customize behavior
Dynamic inventory:
- Cloud providers: AWS, Azure, GCP, DigitalOcean
- Virtualization: VMware, LXC, Docker
- Custom scripts returning JSON
Inventory plugins (Ansible 2.x+):
- Built-in plugins for major cloud providers
- Script-based legacy dynamic inventory
# hosts (INI format - traditional) [web] web1.example.com web2.example.com [db] db1.example.com [production:children] web db # inventory.yaml (YAML format) all: children: webservers: hosts: www1: ansible_host: 192.168.1.10 http_port: 8080 www2: ansible_host: 192.168.1.11 http_port: 8080 databases: hosts: db1: ansible_host: 192.168.1.20 production: children: webservers: databases: vars: deploy_env: production # Group and host variables # group_vars/webservers.yml http_port: 80 max_clients: 200 # host_vars/www1.example.com.yml http_port: 8080 - Step 6
Your first playbook
Playbooks are Ansible automation scripts written in YAML. They define the desired state of your systems. Ansible ensures that state is reached idempotently.
Playbook structure:
- Play: A single task assignment to a set of hosts
- Tasks: Individual actions to achieve desired state
- Variables: Values used in tasks
- Templates: Jinja2 templates for dynamic file generation
- Handlers: Tasks triggered by notifications (e.g., restart services)
Key concepts:
- Idempotency: Running the playbook twice produces the same result
- Declarative: Define what, not how
- Order: Tasks run in order, but module-level idempotency is preferred
# hello.yml - Simple playbook example --- - name: Configure web servers hosts: webservers become: true # Run with sudo privileges vars: http_port: 80 max_clients: 200 tasks: - name: Ensure Apache is installed ansible.builtin.apt: name: apache2 state: present when: ansible_os_family == "Debian" - name: Ensure Nginx is installed ansible.builtin.yum: name: nginx state: present when: ansible_os_family == "RedHat" - name: Deploy configuration file ansible.builtin.template: src: templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: Restart nginx - name: Ensure Apache is running ansible.builtin.service: name: apache2 state: started enabled: yes handlers: - name: Restart nginx ansible.builtin.service: name: nginx state: restarted - Step 7
Running playbooks
Playbooks are executed using the
ansible-playbookcommand. You can customize execution with various options for verbosity, checking for changes, limiting targets, and more.Basic execution: Run a playbook against its default inventory or specify a custom inventory file.
Execution modes:
- Normal: Apply changes to targets
- Check mode: Test playbook without making changes (dry run)
- Diff mode: Show what changes will be made
- Step mode: Confirm each task before running
Output and logging:
- Verbosity levels: -v to -vvvv for detailed output
- Log files for auditing and debugging
Selecting targets:
- Host patterns: web:, production:, all:
- Limit to specific hosts: --limit web1,web2
- Start from specific play/task: --start-at-task
# Basic playbook execution ansible-playbook hello.yml # With custom inventory ansible-playbook -i hosts hello.yml # Check mode (dry run, no changes) ansible-playbook --check hello.yml # Show what will change (diff) ansible-playbook --check --diff hello.yml # Verbose output levels ansible-playbook -v hello.yml # Normal verbosity ansible-playbook -vvvv hello.yml # Debug mode # Limit execution to specific hosts ansible-playbook -i hosts hello.yml --limit webservers ansible-playbook -i hosts hello.yml --limit "db1.example.com" # Execute specific play or task ansible-playbook hello.yml --start-at-play "Configure" ansible-playbook hello.yml --start-at-task "Install Apache" # Run with specific user ansible-playbook hello.yml --user ansible # Parallelism (default: 5 hosts at once) ansible-playbook hello.yml -f 20 # 20 hosts in parallel - Step 8
Ansible modules and collections
Modules are reusable units of automation that perform specific tasks. Ansible has 7000+ community modules covering everything from package management to cloud resources.
Module categories:
- Files: copy, template, file, lineinfile, blockinfile
- System: service, user, group, mount, cron
- Package: apt, yum, dnf, zypper, pkgng
- Networking: iptables, interface, network modules
- Cloud: aws_ec2, azure_vm, google_compute_instance
- Language: pip, npm, gem, go, docker
Collections: Collections are distributions of Ansible content (playbooks, roles, modules) organized by namespace and name. They provide a structured way to distribute and version Ansible code.
Built-in vs external:
- builtin: Included with core Ansible installation
- ansible.builtin: Namespaced builtin modules (preferred)
- community: Community-maintained collections
- vendor: Third-party collections (amazon.aws, ansible.netcommon, etc.)
# Common module examples --- - name: Using various Ansible modules hosts: all tasks: # Package management - name: Install packages (apt) ansible.builtin.apt: name: - nginx - git - vim state: present update_cache: yes # File operations - name: Create file ansible.builtin.copy: content: "Hello World" dest: /tmp/greeting.txt mode: '0644' - name: Template file ansible.builtin.template: src: /path/to/template.j2 dest: /etc/myapp/config.yml # Service management - name: Start service ansible.builtin.service: name: nginx state: started enabled: yes # User management - name: Create user ansible.builtin.user: name: deploy groups: sudo shell: /bin/bash create_home: yes - Step 9
Ansible Galaxy and Collections
Ansible Galaxy is the official community repository for Ansible content — roles, collections, and playbooks. It's like PyPI but for Ansible.
Galaxy benefits:
- Pre-built, tested roles for common applications
- Industry-standard best practices
- Community-maintained and verified content
- Version control and dependency management
Collections:
- Namespace/name format:
community.general,ansible.netcommon - Multiple modules, roles, playbooks in one distribution
- Dependency support
- Semantic versioning
Managing collections:
ansible-galaxy collection installdownloads to localcollectionsdirectory in project for reproducibilityrequirements.ymlfor dependency management
# Create requirements file cat > requirements.yml << 'EOF' --- collections: - name: community.general version: ">=6.0.0" - name: ansible.netcommon - name: amazon.aws roles: - name: geerlingguy.docker version: "7.0.0" - name: geerlingguy.nginx version: "3.0.0" # Install collections and roles ansible-galaxy install -r requirements.yml # Install specific collection only ansible-galaxy collection install community.general # Search for content ansible-galaxy search nginx ansible-galaxy collection search docker # View collection contents ansible-galaxy collection info community.general # Create your own collection ansible-galaxy collection init myorg.my_collection # Import to Galaxy (after publishing) galaxy-cli login # Sign in galaxy-cli publish myorg-my_collection-1.0.0.tar.gz - Step 10
Roles: Reusable playbooks
Roles organize playbooks into a standard directory structure, making them reusable, shareable, and testable. Roles are the building blocks of Ansible automation.
Role structure:
tasks/main.yml: Main task listhandlers/main.yml: Tasks to be triggeredtemplates/: Jinja2 templatesfiles/: Files to copy to targetsvars/main.yml: Default variablesdefaults/main.yml: Default role variables (lowest priority)meta/main.yml: Dependencies and metadatatests/: Test files and playbook
Role usage:
- Include in playbooks with
roles:section - Pass variables to override defaults
- Organize complex configurations
- Share and distribute via Galaxy
# Generate role skeleton ansible-galaxy init wordpress # Creates directory structure: # wordpress/ # ├── defaults/ # │ └── main.yml # Low-priority vars # ├── meta/ # │ └── main.yml # Role metadata, dependencies # ├── tasks/ # │ └── main.yml # Main tasks # ├── handlers/ # │ └── main.yml # Triggered tasks # ├── templates/ # │ └── # Jinja2 .j2 files # ├── files/ # │ └── # Static files to copy # ├── vars/ # │ └── main.yml # Role-specific vars # └── tests/ # Use role in playbook --- - name: Deploy WordPress site hosts: webservers roles: - role: geerlingguy.docker - role: geerlingguy.mysql db_name: wordpress_db db_user: wordpress db_password: "secur3pass" - role: wordpress tags: ['deploy'] # Role variables can be overridden: # - at invocation (highest priority) # - via extra vars (-e flag) # - in vars/ directory # - in defaults/ (lowest priority) - Step 11
Variables and templating
Ansible supports extensive variable management and the powerful Jinja2 templating engine.
Variable sources (priority order, highest to lowest):
- Command-line
-e(--extra-vars) override - Playbook
vars(inline vars) - Role
vars/directory host_vars/andgroup_vars/files- Role
defaults/directory
Jinja2 templates:
- Dynamic configuration file generation
- Conditional logic with
{% if %} - Loops with
{% for %} - Filters for data transformation
- Includes and extends for code reuse
Facts: Ansible automatically gathers system information (OS, IP, hostname, memory, etc.) that's available as variables. Use
setupmodule to gather specific facts.# Playbook with variables --- - name: Variable demonstration hosts: all vars: app_name: "myapp" app_port: 8080 tasks: - name: Show variables ansible.builtin.debug: msg: | App: {{ app_name }} Port: {{ app_port }} Hostname: {{ inventory_hostname }} OS: {{ ansible_distribution }} IP: {{ ansible_default_ipv4.address }} - name: Conditional task ansible.builtin.debug: msg: "This runs on {{ ansible_os_family }}" when: ansible_os_family in ['Debian', 'RedHat'] - name: Loop example ansible.builtin.apt: name: "{{ item }}" state: present loop: ["nginx", "git", "curl"] when: ansible_os_family == 'Debian' # Template file example (templates/app.conf.j2): # server {{ server_name }} { # listen {{ port | default(80) }}; # {% for backend in backends %} # upstream {{ backend }}; # {% endfor %} # } - Command-line
- Step 12
Ansible Vault: Sensitive data
Ansible Vault encrypts sensitive data (passwords, API keys, secrets) using AES-256 encryption. This allows you to securely store secrets in version control without exposing them.
Vault usage:
- Encrypt individual files or strings
- Vault password prompts or key files
- Decrypt at playbook runtime
- Edit encrypted files inline
Security considerations:
- Protect your vault password/key
- Use environment variables for CI/CD
- Consider external secrets managers for production
- Don't commit decrypted files to version control
# Encrypt a file ansible-vault encrypt secrets.yml # Encrypt a new file (opens editor) ansible-vault create db_creds.yml # Edit encrypted file ansible-vault edit secrets.yml # Decrypt file (view contents) ansible-vault decrypt secrets.yml # Encrypt a string (outputs YAML variable) ansible-vault encrypt_string 'my_secret_password' --name 'database_password' # Run playbook with Vault password ansible-playbook -i hosts site.yml --ask-vault-password # OR: ansible-playbook -i hosts site.yml --vault-password-file ~/.vault_pass # Use vault environment variable (CI/CD) export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass ansible-playbook site.yml # Vault in playbook --- - hosts: all vars_files: - vault/vars.yml - vault/secrets.yml tasks: - name: Use secure password ansible.builtin.user: name: admin password: "{{ vault_ssh_key | password_hash('sha512') }}" no_log: true # Don't output sensitive data - Step 13
Cloud integration
Ansible integrates with all major cloud providers through provider-specific modules and collections. Automate provisioning, configuration, and management of cloud resources.
Supported providers:
- AWS: EC2, S3, RDS, VPC, Lambda, IAM, and more (amazon.aws collection)
- Azure: VMs, networks, storage, Kubernetes (azure.azcollection)
- Google Cloud: Compute Engine, GKE, Pub/Sub (google.cloud collection)
- Other: DigitalOcean, Packet/Bare Metal, OpenStack, OVH
Cloud inventory plugins: Dynamically discover instances from cloud, build inventory automatically.
Common patterns:
- Provision cloud infrastructure
- Configure cloud resources
- Hybrid cloud orchestration
- Cloud migration automation
# AWS example - Launch EC2 instance --- - name: AWS infrastructure hosts: localhost tasks: - name: Launch web server amazon.aws.ec2_instance: name: "my-webserver" image_id: "ami-0c55b159cbfafe1f0" instance_type: "t3.micro" key_name: "my-keypair" region: "us-east-1" security_group: "web-traffic" wait: true exact_count: 1 filters: "tag:Name": "my-webserver" tags: Environment: production Project: demo register: ec2 - name: Create security group amazon.aws.ec2_group: name: "allow-ssh-https" description: Allow SSH and HTTPS rules: - proto: tcp ports: - "22" - "443" cidr_ip: "0.0.0.0/0" - name: Create S3 bucket amazon.aws.s3: bucket: "my-app-assets" region: "us-east-1" object: "index.html" dest: "/path/to/index.html" ACL: public-read - Step 14
CI/CD integration
Ansible integrates seamlessly with CI/CD pipelines for automated testing, deployment, and infrastructure management.
Common CI/CD patterns:
- Test playbooks on every commit/mr
- Automate deployments on merge to main
- Infrastructure as code in version control
- Automated testing with Molecule
Testing approaches:
- Molecule: End-to-end testing for roles
- ansible-lint: Validate playbook style
- Check mode: Dry-run deployments
- Containerized testing: Run tests in isolated environments
# .gitlab-ci.yml example stages: - test - lint - deploy test: image: quay.io/ansible/ansible:latest stage: test script: - pip install molecule - molecule test lint: stage: lint script: - pip install ansible-lint - ansible-lint site.yml deploy: stage: deploy image: quay.io/ansible/ansible:latest only: - main script: - ansible-playbook -i inventory/live site.yml environment: name: production # GitHub Actions example name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Ansible run: pip install ansible-core - name: Run playbook run: ansible-playbook deploy.yml env: ANSIBLE_HOST_KEY_CHECKING: "false" VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }} - Step 15
Use cases and examples
Ansible is used across industries for diverse automation needs:
Configuration Management:
- Standardize server configurations across environments
- Apply security patches and compliance controls
- Manage software packages and dependencies
Application Deployment:
- Zero-downtime deployments with load balancer integration
- Blue-green deployments
- Database migrations with rollback
- Environment-specific configurations
Multi-tier Orchestrations:
- Full-stack deployments across multiple hosts
- Complex workflows with dependencies
- Service discovery and integration
Infrastructure as Code:
- Provision and configure cloud infrastructure
- Immutable infrastructure patterns
- Disaster recovery automation
Security and Compliance:
- Automated security hardening
- Compliance audits
- Secret rotation and management
Database Management:
- Automated backups and restores
- Database configuration management
- Schema migrations
# Example: Zero-downtime deployment --- - name: Blue-Green Deployment hosts: webservers vars: blue_weight: 100 green_weight: 0 new_version: "1.2.3" tasks: - name: Deploy new version to green block: - name: Stop green service service: name: myapp state: stopped when: inventory_hostname in groups['green'] - name: Deploy new version copy: src: app-{{ new_version }}/ dest: /var/www/myapp/ - name: Start green service service: name: myapp state: started when: inventory_hostname in groups['green'] - name: Run smoke tests uri: url: "http://localhost:{{ green_port }}/health" return_content: yes register: smoke_result until: smoke_result.status == 200 retries: 5 delay: 10 rescue: - name: Rollback on failure debug: msg: "Deployment failed, rolling back" - name: Update load balancer weights debug: msg: "Switch traffic to green (healthy)" - name: Remove old version (cleanup) debug: msg: "Cleanup old blue version" - Step 16
Learning resources
Official documentation:
- Ansible Documentation: https://docs.ansible.com/
- Playbook Examples: https://github.com/ansible/ansible/tree/devel/examples
- User Guide: https://docs.ansible.com/ansible/latest/user_guide/
Playbooks and roles:
- Ansible Galaxy: https://galaxy.ansible.com/ (community roles and collections)
- Awesome Ansible: https://github.com/nickgillham/awesome-ansible (curated resources)
Learning paths:
- Red Hat Ansible Training: https://www.redhat.com/en/topics/ansible/red-hat-ansible-training
- freeCodeCamp Ansible: Video tutorials on YouTube
Community:
- Ansible Slack: https://ansible-slack.herokuapp.com/
- Ansible Forum: https://forum.ansible.com/
- Stack Overflow: tag: ansible
Documentation: - Official: https://docs.ansible.com/ - User Guide: https://docs.ansible.com/ansible/latest/user_guide/ - Examples: https://github.com/ansible/ansible/tree/devel/examples Community: - Galaxy (roles/collections): https://galaxy.ansible.com/ - Forum: https://forum.ansible.com/ - Slack: https://ansible-slack.herokuapp.com/ - Stack Overflow: tag "ansible" Awesome Ansible: https://github.com/nickgillham/awesome-ansible Installation examples: https://docs.ansible.com/ansible/latest/installation_guide/
Feature requests
Sign in to suggest features or vote on existing ones.
No feature requests yet.
Discussion
Sign in to join the discussion.
No comments yet.