Its model (push, agentless, desired state per task) explains how every playbook behaves.
Ansible runs from a control node (your laptop or a CI runner) and manages managed nodes over SSH (WinRM or PowerShell remoting for Windows, APIs for network devices and clouds). There's no agent or daemon on the targets; Linux hosts need only SSH and Python.
You describe the state you want in tasks, each calling a module: ansible.builtin.apt to install a package, ansible.builtin.copy to place a file, ansible.builtin.service to start a service. Ansible copies the module to the host, runs it, and gets back JSON saying whether anything changed.
Modules are idempotent: "package nginx present" installs it the first time and does nothing afterwards. Running a playbook twice is safe, and the second run should report changed=0. That makes Ansible good for both setting up and continuously enforcing configuration.
Ansible versus neighbours:
- Terraform creates infrastructure (VMs, networks, managed databases) through cloud APIs; Ansible configures what runs on machines. Many teams use Terraform, then Ansible.
- Puppet/Chef/Salt traditionally use agents that pull configuration; Ansible pushes on demand.
- With containers and Kubernetes, there is less host configuration to manage, but Ansible still handles nodes, VMs, network gear and operational runbooks.
Install with pipx install ansible (the community package with collections) or ansible-core for the minimal engine.
Example
# install on the control node
pipx install --include-deps ansible
ansible --version | head -1
# ansible [core 2.21.x]
# one module run against the local machine
ansible localhost -m ansible.builtin.ping
# localhost | SUCCESS => {"changed": false, "ping": "pong"}
ansible localhost -m ansible.builtin.file -a "path=/tmp/demo state=directory"
# localhost | CHANGED => {... "changed": true ...}
ansible localhost -m ansible.builtin.file -a "path=/tmp/demo state=directory"
# localhost | SUCCESS => {... "changed": false ...} idempotentRemember
- Agentless: SSH plus Python on targets
- Tasks call modules that report changed or ok
- Idempotent: a second run changes nothing
Watch out for
- Writing tasks with shell commands that aren't idempotent, so every run changes things.