Comprehensive Ansible
This guide will show you how to use Ansible, starting from a single, simple playbook and progressing to a professional, role-based structure. We'll deploy common infrastructure, including Docker, WordPress, and n8n.
Prerequisites
- A control node (your machine) with Ansible installed (
sudo apt install ansibleorpip install ansible). - One or more target nodes (e.g., Ubuntu Linux VMs) with SSH access configured (key-based authentication recommended).
- Basic understanding of YAML syntax.
Part 1: The Basics - Inventory and Ad-Hoc Commands
Before writing playbooks, Ansible needs to know where to run them. This is defined in an inventory file.
1. Create an Inventory
Create a file named inventory.ini:
[webservers]
# Replace with your actual server IP or hostname
192.168.1.100
[webservers:vars]
# Tell Ansible which user to connect as
ansible_user=ubuntu
# Tell Ansible to use python3
ansible_python_interpreter=/usr/bin/python3
2. The ansible CLI (Ad-Hoc Commands)
Use the ansible command for quick tasks without writing a full playbook.
Ping the servers to test connectivity:
ansible webservers -i inventory.ini -m ping
-i inventory.ini: Specifies the inventory file.-m ping: Uses thepingmodule (verifies Python connectivity, not ICMP ping).
Check system uptime:
ansible webservers -i inventory.ini -a "uptime"
-a: Passes arguments (a raw command in this case) to the defaultcommandmodule.
Part 2: The Single Playbook (ansible-playbook)
Ad-hoc commands are great for quick checks, but playbooks (.yml files) are the core of Ansible, allowing for repeatable, complex automation.
1. Write the Playbook
Create a file named setup_docker.yml. We will install Docker, a common requirement for modern deployments.
---
- name: Install and Configure Docker
# Target the group from our inventory
hosts: webservers
# Run commands with sudo
become: yes
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600 # Don't update if updated in last hour
- name: Install required system packages
ansible.builtin.apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- python3-pip
state: latest
- name: Add Docker GPG apt Key
ansible.builtin.apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
ansible.builtin.apt_repository:
repo: deb https://download.docker.com/linux/ubuntu focal stable
state: present
- name: Install Docker CE
ansible.builtin.apt:
name: docker-ce
state: latest
- name: Ensure Docker service is running and enabled
ansible.builtin.systemd:
name: docker
state: started
enabled: yes
- name: Install Docker module for Python (required for Ansible docker modules)
ansible.builtin.pip:
name: docker
2. Run the Playbook
Use the ansible-playbook command:
ansible-playbook -i inventory.ini setup_docker.yml
Ansible will connect to 192.168.1.100, run through the tasks sequentially, and report the status (ok, changed, or failed).
Part 3: Structuring with Roles
As playbooks grow, putting everything in one file becomes messy. Roles allow you to break complex playbooks into reusable components (vars, tasks, handlers).
Let's restructure our project to deploy Docker, WordPress, and n8n using roles.
1. Create the Directory Structure
Ansible has a built-in tool to generate role skeletons: ansible-galaxy.
mkdir my-ansible-project
cd my-ansible-project
# Initialize the roles directory
mkdir roles
cd roles
# Create roles
ansible-galaxy init docker
ansible-galaxy init wordpress
ansible-galaxy init n8n
cd ..
Your structure will look roughly like this:
my-ansible-project/
├── inventory.ini
├── site.yml <-- Our main playbook
└── roles/
├── docker/
│ ├── tasks/
│ │ └── main.yml
│ └── ...
├── wordpress/
│ ├── tasks/
│ │ └── main.yml
│ └── ...
└── n8n/
├── tasks/
│ └── main.yml
└── ...
2. The docker Role
Move the tasks from our previous single playbook into roles/docker/tasks/main.yml.
# roles/docker/tasks/main.yml
---
# (Paste the tasks from setup_docker.yml here, removing the top-level playbook structure)
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
# ... (rest of the Docker tasks) ...
3. The wordpress Role (using Docker Compose)
Instead of installing PHP/Nginx manually, let's deploy WordPress using Docker.
# roles/wordpress/tasks/main.yml
---
- name: Create WordPress directory
ansible.builtin.file:
path: /opt/wordpress
state: directory
mode: '0755'
- name: Create docker-compose.yml for WordPress
ansible.builtin.copy:
dest: /opt/wordpress/docker-compose.yml
content: |
version: '3.1'
services:
wordpress:
image: wordpress:latest
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- ./wp-data:/var/www/html
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- ./db-data:/var/lib/mysql
- name: Start WordPress containers
community.docker.docker_compose:
project_src: /opt/wordpress
state: present
4. The n8n Role (using Docker Compose)
n8n is a popular workflow automation tool.
# roles/n8n/tasks/main.yml
---
- name: Create n8n directory
ansible.builtin.file:
path: /opt/n8n
state: directory
mode: '0755'
- name: Create docker-compose.yml for n8n
ansible.builtin.copy:
dest: /opt/n8n/docker-compose.yml
content: |
version: "3"
services:
n8n:
image: docker.n8n.io/n8nio/n8n
restart: always
ports:
- "5678:5678"
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
- name: Start n8n container
community.docker.docker_compose:
project_src: /opt/n8n
state: present
5. The Master Playbook (site.yml)
Now, tie it all together in site.yml in the root of your project:
# site.yml
---
- name: Provision Production Server
hosts: webservers
become: yes
roles:
- docker
- wordpress
- n8n
6. Run the Full Stack
Execute the master playbook:
ansible-playbook -i inventory.ini site.yml
Ansible will now sequentially apply the docker role, then the wordpress role, and finally the n8n role, ensuring your server has all components installed and running via Docker Compose.
Summary of Progression
- Ad-Hoc (
ansible): Good for one-off commands (checking uptime, restarting a service). - Single Playbook (
ansible-playbook): Good for simple, linear setups (installing a few packages). - Roles (
ansible-playbookwith Roles): The standard for production. It promotes code reuse, cleaner file structures, and easier maintenance as your infrastructure grows.