Command Palette

Search for a command to run...

GitHubGitHub

Ansible Installation Guide

Install Ansible 14 with ansible-core 2.21 and Python 3.12+, build an inventory, write your first playbook, use Ansible Vault and run tasks in execution environments.

Ansible is a cross-platform, agentless automation tool. It talks to managed nodes over SSH (or WinRM on Windows), so there is nothing to install on the machines you manage.

System Requirements

Control Node

  • Linux, macOS or a WSL2 distribution (Windows is not supported as a control node)
  • Python 3.12 or newer
  • ssh and git available
  • The ability to reach the managed nodes over SSH (port 22) or WinRM (port 5985/5986)

Managed Nodes

  • Linux with Python 3.9+
  • Windows with PowerShell 3.0+ and the WinRM feature enabled
  • SSH key-based authentication (strongly recommended)

Installation Instructions

Ubuntu / Debian (apt)

# Update the package index
sudo apt update
 
# Install the community package (includes ~300 collections)
sudo apt install -y ansible
 
# Verify
ansible --version

To install only the core engine and add the collections you actually need:

sudo apt install -y ansible-core

Project Layout

mkdir -p ~/ansible/{playbooks,roles,inventory,collections}
cd ~/ansible
# Create a requirements file for the collections you need
ansible-galaxy collection init
# requirements.yml
collections:
  - name: community.general
    version: ">=10.0.0"
  - name: ansible.posix
    version: ">=1.5.0"
# Install the collections
ansible-galaxy collection install -r requirements.yml
 
# Update them later
ansible-galaxy collection install -r requirements.yml --upgrade

Inventory

Create 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
 
[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_ed25519

Or use YAML, which is the format to prefer:

# inventory.yaml
all:
  children:
    webservers:
      hosts:
        web1:
          ansible_host: 192.168.1.10
        web2:
          ansible_host: 192.168.1.11
    dbservers:
      hosts:
        db1:
          ansible_host: 192.168.1.20
  vars:
    ansible_user: deploy
    ansible_ssh_private_key_file: ~/.ssh/id_ed25519

Configuration

Create ansible.cfg in the project root:

[defaults]
inventory = ./inventory.yaml
roles_path = ./roles
host_key_checking = True
stdout_callback = yaml
interpreter_python = auto_silent
retry_files_enabled = False
 
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

Your First Playbook

Create playbooks/install-nginx.yml:

---
- name: Install and start Nginx
  hosts: webservers
  become: true
  vars:
    nginx_packages:
      - nginx
      - curl
 
  tasks:
    - name: Update the package cache (Debian/Ubuntu)
      ansible.builtin.apt:
        update_cache: true
      when: ansible_os_family == "Debian"
      changed_when: false
 
    - name: Update the package cache (RHEL/CentOS)
      ansible.builtin.dnf:
        update_cache: true
      when: ansible_os_family == "RedHat"
      changed_when: false
 
    - name: Install the packages
      ansible.builtin.package:
        name: "{{ nginx_packages }}"
        state: present
 
    - name: Ensure Nginx is running and enabled
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true
# Test the connection
ansible webservers -m ping
 
# Validate the syntax
ansible-playbook playbooks/install-nginx.yml --syntax-check
 
# Preview the changes without applying them
ansible-playbook playbooks/install-nginx.yml --check --diff
 
# Run it
ansible-playbook playbooks/install-nginx.yml

Handling Secrets with Ansible Vault

# Create an encrypted variables file
ansible-vault create secrets.yml
 
# Edit it
ansible-vault edit secrets.yml
 
# Encrypt an existing file
ansible-vault encrypt --output secrets.enc.yml vars.yml
 
# Use it in a playbook
ansible-playbook site.yml --ask-vault-pass
# vars/vault.yml (encrypted)
db_password: "super-secret"
api_token: "another-secret"
# Use a password file in CI instead of an interactive prompt
ansible-playbook site.yml --vault-password-file .vault-password

Roles

# Scaffold a role
ansible-galaxy init roles/nginx
 
# Install a role from Galaxy
ansible-galaxy role install geerlingguy.nginx
# Use it in a playbook
- name: Configure Nginx
  hosts: webservers
  become: true
  roles:
    - role: nginx
      vars:
        nginx_port: 8080

Execution Environments

Execution environments are containers that package Ansible and its dependencies, so a pipeline always runs the same stack:

# Install the builder
pip install ansible-builder
 
# Build the image
ansible-builder build --file execution-environment.yml --tag my-ee:latest
 
# Run a playbook inside it
podman run -it --rm -v $(pwd):/z my-ee:latest ansible-playbook site.yml
# execution-environment.yml
version: 3
images:
  base_image:
    name: registry.redhat.io/ubi9/ubi-minimal:latest
dependencies:
  galaxy: requirements.yml
  python: requirements.txt
  system: bindep.txt

Troubleshooting

Best Practices

  1. Use ansible-core and add only the collections you need — it keeps the control node small and the version pinned.
  2. Pin versions in requirements.yml and commit the lock file.
  3. Use YAML inventory and group hosts by role, not by team.
  4. Use FQCN module names and run ansible-lint in CI.
  5. Keep secrets in Ansible Vault, never in plain variables.
  6. Run with --check --diff first on any change that touches a production system.
  7. Prefer idempotent modules (package, service, template) over shell and command.
  8. Use block/rescue/always for error handling instead of ignore_errors.
  9. Set forks and pipelining to keep large fleets fast.
  10. Run in an execution environment in CI for reproducible builds.

Next Steps