Ansible Fundamentals
itInfrastructure and operations
Ansible Fundamentals
Ansible automates remote systems from a control node. You describe targets in an inventory and desired work in playbooks. Ansible connects to each managed node, runs modules, and reports whether the node changed.
That model separates Ansible from a shell script copied across a fleet. A shell script usually describes commands to execute. An Ansible task usually describes a state to reach. A package should be present. A service should be running. A configuration file should have specific content.
Most Ansible modules inspect the current state before acting. If the desired state already exists, an idempotent module reports no change. Repeated execution should converge on the same result. Idempotency depends on the module and the way you use it; Ansible does not make every command or playbook idempotent.
The operating model
An Ansible environment has three core parts:
- Control node — the system where you install Ansible and run its command-line tools.
- Inventory — one or more sources that identify managed nodes, groups, and associated variables.
- Managed node — a remote host or device that Ansible controls.
Ansible is normally agentless. You do not install an Ansible daemon on every managed node. The control node uses connection plugins and transports such as SSH or PowerShell remoting. Many POSIX modules require Python on the managed node, while some device-specific modules have different requirements.
You can install either ansible-core or the larger ansible package. ansible-core provides the language, runtime, and a built-in set of modules and plugins. The ansible package adds a community-curated collection set. Choose deliberately, then pin the versions of Ansible and any collections that your automation requires.
Inventory defines scope
Inventory answers two questions: which nodes exist, and how should Ansible address them? Static inventory often uses YAML or INI. Inventory plugins can discover nodes from external systems.
Groups let you target related nodes and assign variables in bulk. One host can belong to several groups. Patterns such as webservers, production:&webservers, or a single host select the execution scope. Always inspect the resolved inventory and matched hosts before a consequential run.
Inventory is not merely a host list. Connection variables can select a remote user, address, port, or connection plugin. Group and host variables can describe environment-specific data. Keep behavior in reusable playbooks and environment data in inventory when that boundary remains clear.
Playbooks map hosts to ordered work
A playbook is an ordered YAML list of plays. Each play maps a host pattern to an ordered task list. Each task invokes a module with arguments.
---
- name: Configure web servers
hosts: webservers
become: true
vars:
web_service: nginx
tasks:
- name: Install the web package
ansible.builtin.package:
name: "{{ web_service }}"
state: present
- name: Deploy the web configuration
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: "0644"
notify: Restart web service
- name: Keep the web service enabled and running
ansible.builtin.service:
name: "{{ web_service }}"
enabled: true
state: started
handlers:
- name: Restart web service
ansible.builtin.service:
name: "{{ web_service }}"
state: restarted
The play targets the webservers group. Tasks run from top to bottom. By default, Ansible applies one task across the matched hosts before moving to the next task.
The example uses fully qualified collection names such as ansible.builtin.template. This identifies the collection and module explicitly. It avoids ambiguity when different collections expose the same short module name.
Modules, plugins, and collections
A module performs a task on a managed node or against an API. Package, file, template, service, user, and cloud-resource modules provide domain-specific state controls. Read a module's documentation before use because arguments, check-mode support, and idempotency vary.
A plugin extends how Ansible operates. Connection plugins transport work. Inventory plugins load targets. Callback plugins format results. Filter plugins transform data. Plugins run within the Ansible process rather than representing one task's remote action.
A collection packages Ansible content under a namespace. It can contain modules, plugins, roles, and playbooks. A fully qualified collection name has the form namespace.collection.resource.
Variables and facts supply data
Variables let one playbook work across different hosts and environments. You can define them in inventory, playbooks, roles, included files, and the command line. Those sources follow detailed precedence rules. Extra variables have especially high precedence, so use them as explicit run inputs rather than an invisible defaulting system.
Facts are variables discovered from managed nodes. The default fact-gathering step can collect operating-system, network, filesystem, and other host data. Use facts when desired behavior genuinely depends on observed host properties. Disable or limit fact gathering when you do not need it.
Templates combine files with variables through Jinja. Treat a template as a configuration interface. Validate its inputs, quote YAML expressions where required, and avoid hiding complex control flow inside it.
Handlers connect change to reaction
A handler is a task that runs only after a changed task notifies it. The common case is restarting a service after deploying a changed configuration.
Handlers normally run after the play's task section. Multiple changed tasks can notify the same handler, and Ansible still runs that handler once at the scheduled point. A notification does not run when the notifying task reports ok.
This behavior makes change reporting operationally significant. If a custom task reports changed incorrectly, it may trigger unnecessary restarts. If it misses a real change, it may suppress a required handler.
Safe execution is a sequence
Treat every run as a scope and change decision:
- Inspect the effective inventory with
ansible-inventory. - Inspect module behavior with
ansible-doc. - Run
ansible-playbook --syntax-check. - List matched hosts and tasks.
- Use check mode and diff mode where the involved modules support them.
- Limit the first real run to a representative host or small batch.
- Review the recap, then widen the scope.
Check mode is a simulation, not proof. Modules without check-mode support may do nothing and report nothing. Tasks that depend on results from earlier simulated tasks may behave differently. Diff mode can expose sensitive file content, so control its output and logs.
Privilege escalation also deserves explicit scope. become: true asks a become plugin to run work as another user. It does not grant privileges by itself. The connection account, remote policy, selected become method, and credentials still determine what succeeds.
Where Ansible fits
Ansible fits configuration management, application deployment, remote administration, network automation, and ordered orchestration across multiple systems. It works well when you need readable automation that can target heterogeneous systems through pluggable connections and modules.
Ansible is not a source of truth by itself. Inventory, variables, playbooks, collection versions, and secrets still need ownership and lifecycle controls. Put automation in version control. Test it in representative environments. Protect sensitive values with an appropriate secret workflow, including Ansible Vault when file-level encryption fits.
Ansible also does not replace application-native controllers that continuously reconcile state. Standard playbook execution is push-oriented and finite. If a system needs continuous reconciliation, event processing, or a service API, pair Ansible with the appropriate control plane.
Your durable mental model is a pipeline: inventory selects nodes, a play maps those nodes to ordered tasks, modules evaluate state, and results drive later actions such as handlers. Variables provide data across that pipeline. Verification constrains risk before you expand scope.
