Installing Ansible & Your First Playbook

Ansible

Chapter 2 · Installing Ansible & Your First Playbook

ansible1-1 established that Ansible is agentless. This chapter makes that concrete — installing it, running your first commands, and writing the smallest playbook that actually does something.

The Control Node — Where Ansible Actually Runs

Ansible itself is installed on exactly one machine — the control node — not on every host it manages. This is ansible1-1's agentless architecture made literal: there's no Ansible software running on a managed host at all, only on the control node that initiates outbound SSH connections. Installation is typically pip install ansible, and works natively on Linux and macOS; on Windows, the control node itself normally runs inside WSL — Ansible can still manage Windows hosts via WinRM, it just doesn't run natively as a control node on Windows.

Ad-Hoc Commands — Ansible Without a Playbook

ansible all -i inventory -m ping ansible webservers -i inventory -a "systemctl status nginx"

-m specifies a module to run — ping here is a built-in connectivity-check module, worth distinguishing explicitly from ICMP ping: it confirms Ansible can connect over SSH and that Python is reachable and working on the target, not just that the host responds to a network ping. -a passes arguments to the default command module when no -m is given. Ad-hoc commands are genuinely useful for quick, one-off checks or actions — they don't give you repeatability or a record of what changed, which is exactly what a playbook is for.

Your First Playbook

--- - name: Ensure nginx is installed and running hosts: webservers become: true tasks: - name: Install nginx apt: name: nginx state: present - name: Start nginx service: name: nginx state: started

A playbook is a list of plays; each play targets a group of hosts (from the inventory ansible1-3 covers fully) and contains a list of tasks. Each task calls exactly one module — apt, service — with specific arguments describing the desired state, not a literal command to run. become: true is Ansible's privilege-escalation flag, the equivalent of running with sudo.

Running a Playbook

ansible-playbook -i inventory site.yml

Each task reports one of three outcomes per host — ok (already in the desired state, nothing to do), changed (something was actually modified), or failed — followed by a PLAY RECAP summarizing every host's own results at the end of the run.

ansible.cfg — Configuring Ansible's Own Defaults

[defaults] inventory = ./inventory remote_user = deploy host_key_checking = False

ansible.cfg sets defaults — inventory path, default remote user, SSH behavior — so they don't need to be passed as flags on every single command. host_key_checking = False is a common development-convenience setting, worth flagging directly rather than copying blindly (see the warn-box below).

Good forRepeatable?
Ad-hoc commandsQuick one-off checks or actionsNo — not recorded, not version-controlled
PlaybooksAnything meant to run more than once, or to be reviewedYes — a real, repeatable, version-controlled definition
Two commands worth knowing immediately
ansible --version confirms the install and shows the config file actually in use. ansible-doc <module> shows full documentation and real usage examples for any built-in module, directly in the terminal — often faster than searching online once you know it exists.
host_key_checking = False is a real security tradeoff, not a default to copy blindly
SSH host key checking protects against connecting to an unexpected host on first contact — a real, meaningful defense against a man-in-the-middle attack. Disabling it is genuinely convenient in a disposable lab or CI environment where hosts are recreated constantly, but it removes that protection outright. Worth a deliberate decision per environment, not a setting copy-pasted into every ansible.cfg out of habit.

Hands-On Exercises

Exercise 1

Write the ad-hoc command that checks whether every host in a group called "dbservers" is reachable over SSH with Python working, and explain what specifically the ping module confirms that a raw ICMP ping wouldn't.

📄 View solution
Exercise 2

Write a playbook that ensures the package "curl" is installed and the service "cron" is started on hosts in the group "all", using the same structure as the chapter's own nginx example.

📄 View solution
Exercise 3

A colleague sets host_key_checking = False in the ansible.cfg for a production environment "because it was annoying in testing." Explain what's actually being given up by this setting, and suggest a better approach for the testing environment specifically.

📄 View solution

Chapter 2 Quick Reference

  • Ansible installs only on the control node — never on managed hosts
  • Ad-hoc commands (ansible ... -m ... -a ...) — quick, one-off, not repeatable
  • A playbook is a list of plays; each play has hosts and a list of tasks, each task calling one module
  • ansible-playbook -i inventory site.yml runs a playbook; results are ok/changed/failed per host, summarized in the PLAY RECAP
  • ansible.cfg sets defaults (inventory, remote_user, SSH behavior) so flags aren't repeated every run
  • ansible-doc <module> — full docs/examples for any module, without leaving the terminal
  • host_key_checking = False is a real, deliberate security tradeoff — not a blanket default