Why configuration management
Configuring ten servers by hand over SSH works once, then they slowly drift apart: one has an extra package, another an old config file. Configuration management tools describe the desired state in files kept in Git, so every server can be brought to the same state again and every change is reviewed. Ansible, Puppet, Chef, and Salt all solve this problem.
flowchart LR CN["Control node<br/>ansible installed"] --> INV["Inventory<br/>web, db groups"] INV --> SSH["SSH<br/>no agent needed"] SSH --> W1["web1<br/>managed node"] SSH --> W2["web2<br/>managed node"] W1 --> REC["PLAY RECAP<br/>ok, changed, failed"] W2 --> REC %% step CN: You run Ansible from one control node, often your laptop or a CI runner. %% step INV: The inventory says which hosts exist and how they are grouped. %% step SSH: Ansible connects over SSH and needs only Python on the target. %% step W1: Each module checks the current state and changes only what differs. %% step W2: Hosts are handled in parallel (5 forks by default). %% step REC: The recap shows per host what was already right, what changed and what failed.
Agentless push
Ansible runs automation from a control node toward managed nodes. For Linux, it normally connects over SSH, transfers temporary module code, and uses Python remotely; no persistent Ansible daemon is required. Windows commonly uses WinRM or PSRP and appropriate collections. Puppet and Chef, by contrast, traditionally install an agent that pulls configuration from a central server.
inventory + playbook → control node → SSH/WinRM → managed nodes
The control node needs Ansible; a managed Linux node normally needs SSH, compatible Python, and suitable privileges.
Core concepts
| Concept | Role |
|---|---|
| Module | Work unit such as copy, package, or service |
| Task | One module plus arguments and metadata |
| Play | Tasks applied to a host pattern |
| Playbook | One or more plays |
| Inventory | Hosts, groups, and connection variables |
| Collection | Package of modules, roles, and plugins, such as community.general |
ansible-core contains the engine and built-in modules; the larger ansible package adds many community collections. Install it with pip install ansible or the distribution's package manager.
Ad-hoc commands
Before writing a playbook, you can run one module across hosts:
ansible web -i inventory.ini -m ansible.builtin.ping
ansible all -i inventory.ini -a "uptime"
Ansible ping does not send ICMP echo. The module checks that Ansible can connect, execute Python, and receive pong.
How a run proceeds
By default Ansible first gathers facts (OS, IP addresses, memory) from each host, then runs each task on all targeted hosts before moving to the next task, five hosts at a time unless forks is raised. Settings such as inventory path and forks live in ansible.cfg, read from the current directory first.
Purpose-built modules are usually idempotent: they declare desired state and report no change on a later run when state already matches. shell and command may need changed_when, creates, or another guard to achieve similar behavior.