Ansible automates configuration of servers over SSH with no agent to install. You describe the desired state in YAML playbooks and Ansible makes each host match. In the IaC picture (Infrastructure as Code), Terraform creates the servers and Ansible configures what runs on them.
Parts at a glance
| Part | Meaning |
|---|---|
| Control node | The machine you run Ansible from |
| Managed nodes | Servers it configures (need SSH and Python) |
| Inventory | The list of hosts and groups |
| Playbook | YAML file of plays: which hosts, which tasks |
| Task | One call to a module (apt, copy, service...) |
| Module | A unit of work that is idempotent |
| Role | Reusable bundle of tasks, files, templates and defaults |
| Handler | Task that runs only when notified (e.g. restart a service) |
| Facts | Information gathered about each host |
| Vault | Encrypted storage for secrets |
Inventory
# inventory.yml
all:
children:
webservers:
hosts:
web01:
ansible_host: 192.168.1.10
web02:
ansible_host: 192.168.1.11
vars:
ansible_user: administrator
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
Check connectivity first:
$ ansible -i inventory.yml all -m ping
$ ansible -i inventory.yml webservers -m command -a "uptime"
A First Playbook
# install_software.yml
---
- hosts: webservers
become: true # escalate to root with sudo
tasks:
- name: Install software
ansible.builtin.apt:
name:
- wget
- curl
- mc
state: present # absent would uninstall
- name: Ensure nginx is running
ansible.builtin.service:
name: nginx
state: started
enabled: true
$ ansible-playbook -i inventory.yml install_software.yml
$ ansible-playbook -i inventory.yml install_software.yml --check --diff # dry run
The output reports ok (already correct), changed (it made a change) or failed. Running it twice should show no changes the second time: that is idempotency.
Handlers, Variables and Templates
- hosts: webservers
become: true
vars:
http_port: 8080
tasks:
- name: Deploy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/conf.d/app.conf
notify: Reload nginx
handlers:
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
# nginx.conf.j2
server {
listen {{ http_port }};
server_name {{ inventory_hostname }};
}
Useful keywords: when (conditions), loop, register, tags, block / rescue, delegate_to.
Roles and Collections
roles/
└── webserver/
├── tasks/main.yml
├── handlers/main.yml
├── templates/
├── files/
├── defaults/main.yml
└── vars/main.yml
- hosts: webservers
roles:
- webserver
$ ansible-galaxy init roles/webserver
$ ansible-galaxy collection install community.general
Secrets with Ansible Vault
$ ansible-vault create secrets.yml
$ ansible-vault edit secrets.yml
$ ansible-playbook site.yml --ask-vault-pass
Never commit plain-text passwords or private keys in an inventory file.
Ansible and Other Tools
| Task | Tool |
|---|---|
| Create servers, networks, databases | Terraform / Bicep / CloudFormation |
| Configure OS packages, users, files, services | Ansible |
| Build application images | Docker (3. Container Images and Build Tools) |
| Run applications at scale | Kubernetes (Orchestration Platforms) |
| Run ordered automation in a pipeline | Jenkins / GitHub Actions (Jenkins, GitHub Actions) |
In the cloud, cloud-init or an image pipeline often replaces Ansible for first boot, but Ansible stays useful for fleets of long-lived servers and for network devices.
Worked Example: Baseline for Three EC2 Servers
sharifndlovu123/ansible-server-baseline creates three EC2 instances with CloudFormation (two "leaf" nodes and one "spine") and configures them with Ansible.
aws/ CloudFormation: 1.network.yaml (VPC, subnet, IGW, security group with SSH limited to your IP),
2.launch-template.yaml (launch template, key pair, Auto Scaling Group of 3), deploy.sh,
get-key.sh (pulls the generated key pair from SSM Parameter Store), connect.sh
ansible/ ini.yaml (YAML inventory with leafs and spines groups), int.ini (flat inventory), ansible.cfg,
test.sh (validate inventory, ping, run both playbooks)
books/ playbook.yaml (connectivity smoke test), playbook2.yaml (installs curl, git, nginx, apache2)
Lessons: CloudFormation builds the servers and Ansible configures them (see CloudFormation, Bicep and ARM Templates); fetch generated keys from SSM Parameter Store instead of committing them; restrict SSH to your own IP in the security group; validate the inventory and ping before running playbooks.