Document

SUBSCRIBE TO GET FULL ACCESS TO THE E-BOOKS FOR FREE 🎁SUBSCRIBE NOW

Professional Dropdown with Icon

SUBSCRIBE NOW TO GET FREE ACCESS TO EBOOKS

AnsibleLesson 1 / 217 min readUpdated September 11, 2026

Ansible is the simplest way to automate servers at scale: you describe the desired state of your machines in YAML playbooks, and Ansible connects over SSH to make it so, with no agent to install on the targets. It configures Linux and Windows hosts, network devices, cloud resources and containers, and it is the usual companion of Terraform (Terraform creates the servers, Ansible configures them). This page is the hub of our Ansible series: it explains the model, installs Ansible on Ubuntu 24.04, runs your first commands and playbook, and lays out the order of the tutorials up to roles and Vault.

Prerequisites: a control machine with Python 3.10+ (Linux, macOS or WSL on Windows), one or more Linux target hosts reachable over SSH with a user that can sudo, and basic YAML (see Ansible YAML syntax).

How Ansible works

  • Agentless: the control node opens SSH (or WinRM/SSH for Windows) connections, copies small Python modules to the target, runs them, and removes them.
  • Inventory: the list of hosts and groups, static (INI/YAML) or dynamic (AWS, Azure, VMware plugins).
  • Modules: thousands of units of work (apt, copy, service, user, amazon.aws.ec2_instance…), shipped in collections on Ansible Galaxy.
  • Idempotency: modules check the current state and change only what differs, so running a playbook twice is safe and reports “ok” instead of “changed”.
  • Push model: you run Ansible when you want (from a laptop, CI, or AWX/Automation Platform); nothing polls in the background, unlike Puppet or Chef agents.
AnsiblePuppet / ChefTerraform
Agent on targetNoYesNo (API-based)
LanguageYAML + Jinja2Ruby DSLHCL
Main jobConfigure OS and applicationsConfigure OS and applicationsProvision infrastructure
ModelPush, procedural orderPull, declarative catalogDeclarative with state file
Learning curveHoursDaysDays

Step 1 – Install Ansible

Install on the control node only. pipx gives you the latest release isolated from the system Python; the Ubuntu PPA is the alternative.

# Ubuntu 24.04 – recommended
sudo apt update && sudo apt install -y pipx
pipx install --include-deps ansible
pipx inject ansible ansible-lint          # optional linter

# Alternative: official PPA
# sudo apt-add-repository -y ppa:ansible/ansible && sudo apt install -y ansible

ansible --version
# ansible [core 2.18.x] ...

Full details, including macOS and RHEL, in Ansible installation.

Step 2 – Inventory and connectivity

# inventory.ini
[web]
web1 ansible_host=192.168.56.11
web2 ansible_host=192.168.56.12

[db]
db1 ansible_host=192.168.56.21

[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/lab_ed25519
ansible_python_interpreter=/usr/bin/python3
ansible -i inventory.ini all -m ping
# web1 | SUCCESS => { "changed": false, "ping": "pong" }

# Ad-hoc commands: one module, no playbook
ansible -i inventory.ini web -m apt -a "name=nginx state=present" --become
ansible -i inventory.ini all -a "uptime"
ansible -i inventory.ini db -m setup -a "filter=ansible_memtotal_mb"   # gather facts

Deeper dives: inventory files and ad-hoc commands.

Step 3 – Your first playbook

# site.yml
- name: Configure web servers
  hosts: web
  become: true
  vars:
    site_name: devops-lab
    packages:
      - nginx
      - ufw

  tasks:
    - name: Install packages
      ansible.builtin.apt:
        name: "{{ packages }}"
        state: present
        update_cache: true
        cache_valid_time: 3600

    - name: Deploy index page from a template
      ansible.builtin.template:
        src: templates/index.html.j2
        dest: /var/www/html/index.html
        mode: "0644"
      notify: Reload nginx

    - name: Allow HTTP through the firewall
      community.general.ufw:
        rule: allow
        port: "80"
        proto: tcp

    - name: Ensure nginx is running and enabled
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
<!-- templates/index.html.j2 -->
<h1>{{ site_name }} on {{ inventory_hostname }}</h1>
<p>{{ ansible_distribution }} {{ ansible_distribution_version }}, {{ ansible_processor_vcpus }} vCPU</p>
ansible-galaxy collection install community.general
ansible-playbook -i inventory.ini site.yml --check --diff    # dry run: what would change
ansible-playbook -i inventory.ini site.yml
# PLAY RECAP
# web1 : ok=5 changed=4 unreachable=0 failed=0
ansible-playbook -i inventory.ini site.yml                    # second run: changed=0 (idempotent)

curl -s http://192.168.56.11

Notice the pattern: tasks use fully-qualified module names, variables and templates keep content out of the playbook, and a handler restarts the service only when something changed.

The learning path

  1. Ansible introduction – architecture and vocabulary.
  2. Installation on the control node.
  3. YAML syntax for playbooks.
  4. Inventory file – groups, host and group variables.
  5. Ad-hoc commands.
  6. File module and the other essential modules (copy, lineinfile, user, service).
  7. Jinja2 templates – filters, loops, conditionals.
  8. Roles – reusable structure, Galaxy, requirements.yml.
  9. Ansible Vault – encrypt passwords and keys in Git.
  10. Playbook assignment – put it all together.

Where Ansible fits in a DevOps toolchain

  • With Terraform: Terraform creates VMs and outputs their IPs; a dynamic inventory (amazon.aws.aws_ec2) or a generated file feeds Ansible, which installs and configures software. See the Terraform series.
  • In CI/CD: run ansible-playbook from Jenkins, GitHub Actions or Azure Pipelines with the SSH key stored as a secret; use --limit and --tags for targeted runs.
  • Image building: Packer’s Ansible provisioner bakes golden AMIs; Docker images are better served by a Dockerfile.
  • At scale: AWX (open source) or Red Hat Ansible Automation Platform adds a UI, RBAC, scheduling and audit logs.

Good habits

  • Run --check --diff before applying to production and ansible-lint in CI.
  • Prefer specific modules (apt, lineinfile, template) to shell/command; when you must use them, add creates: or changed_when: to keep idempotency.
  • Put secrets in Vault or an external secret manager, never in plain variables.
  • Structure real projects as roles from the start; pin collection versions in requirements.yml.
  • Use serial: and max_fail_percentage: for rolling changes across a fleet.

Troubleshooting the first run

  • “Permission denied (publickey)” – wrong ansible_user or key; test with ssh -i ~/.ssh/lab_ed25519 ubuntu@192.168.56.11 first.
  • “Missing sudo password” – the remote user needs passwordless sudo, or pass --ask-become-pass.
  • “couldn’t resolve module/action ‘community.general.ufw'” – install the collection with ansible-galaxy collection install community.general.
  • Task keeps reporting “changed” – a shell/command task without creates: or changed_when:; replace it with a proper module.

FAQ

Ansible or Terraform? Both. Terraform for infrastructure lifecycle (create/destroy), Ansible for what runs inside the machines. Ansible can create cloud resources too, but has no state file to track drift.

Windows targets? Yes, through WinRM or OpenSSH with the ansible.windows collection; the control node must still be Linux/macOS/WSL.

Is Ansible still relevant with Kubernetes? Yes: nodes, bastions, databases, network gear and legacy apps still need configuration, and Ansible also drives Kubernetes through the kubernetes.core collection.

Project layout to copy

Even small projects benefit from the standard layout, because roles and inventories then work the same way everywhere and CI can find them without configuration.

ansible-lab/
├── ansible.cfg              # inventory path, defaults, callbacks
├── inventories/
│   ├── dev/hosts.yml
│   └── prod/hosts.yml
├── group_vars/
│   ├── all.yml
│   └── web.yml
├── host_vars/
├── roles/
│   ├── common/              # users, packages, hardening
│   └── nginx/               # tasks/ handlers/ templates/ defaults/
├── requirements.yml         # collections and Galaxy roles, pinned
└── site.yml                 # imports the plays per group
# ansible.cfg
[defaults]
inventory = inventories/dev/hosts.yml
roles_path = roles
host_key_checking = False
stdout_callback = yaml
interpreter_python = auto_silent

[privilege_escalation]
become = True

Switch environments with -i inventories/prod/hosts.yml; everything else stays identical, which is exactly the point of configuration management.

Key takeaways

  • Agentless, SSH-based, idempotent, YAML: Ansible is the fastest configuration tool to learn.
  • Inventory + modules + playbooks + roles + Vault are the five concepts to master.
  • Pair it with Terraform for provisioning and run it from CI for repeatability.

Start the series

Begin with the Ansible introduction, then install Ansible. Official docs: Getting started with Ansible.

Parcours liés (Ansible)

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *