Ansible Sandbox Documentation
Explore the playbooks, understand the infrastructure, and learn best practices for using the interactive Ansible Sandbox.
Introduction
Welcome to the documentation for the ArgoBox Ansible Sandbox. This interactive environment allows you to safely experiment with Ansible playbooks designed to manage various aspects of a modern infrastructure setup, including web servers, containerized applications, and Kubernetes clusters.
This documentation provides details on the available playbooks, the underlying infrastructure design of the sandbox environment, and best practices for writing and testing your own automation scripts.
Purpose
The primary goal of the sandbox is to provide a hands-on learning experience for Ansible in a pre-configured, safe environment that mirrors real-world scenarios.
Sandbox Overview
The Ansible Sandbox provides you with temporary access to a set of virtual machines (VMs) where you can execute pre-defined Ansible playbooks or even upload and run your own. The environment is reset periodically to ensure a clean state for each session.
Key Features
- Isolated environment with multiple target VMs.
- Pre-loaded collection of common Ansible roles and playbooks.
- Ability to select and run specific playbooks via a web interface.
- Real-time output streaming of playbook execution.
- Network access between sandbox VMs for testing multi-tier applications.
- Environment reset functionality.
Infrastructure Design
The sandbox environment consists of several virtual machines managed by the main ArgoBox infrastructure, typically running on Proxmox VE. These VMs are provisioned specifically for sandbox use and are isolated from the core production services.
Components
| Component | Description | OS | Purpose |
|---|---|---|---|
| Control Node | The VM where Ansible commands are executed from. | Debian 12 | Runs Ansible engine, hosts playbooks. |
| Web Server Node | Target VM for web server playbooks (Nginx/Apache). | Ubuntu 22.04 | Simulates a typical web server. |
| Database Node | Target VM for database playbooks (PostgreSQL/MySQL). | Debian 12 | Simulates a database server. |
| Docker Node | Target VM with Docker installed for container playbooks. | Ubuntu 22.04 | Runs Docker containers via Compose. |
Networking
All sandbox VMs are placed on a dedicated, isolated VLAN with controlled access to simulate a realistic network environment.
Available Playbooks
The following playbooks are available for execution within the sandbox environment. Each playbook demonstrates different Ansible concepts and common infrastructure tasks.
Web Server Deployment (Nginx)
Installs and configures the Nginx web server on the 'Web Server Node'. Includes setting up a basic virtual host and ensuring the service is running.
---
- name: Deploy Nginx Web Server
hosts: web_server_node # Corresponds to inventory group
become: yes # Execute tasks with sudo
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
tags: [install]
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present
tags: [install]
- name: Ensure Nginx service is started and enabled
ansible.builtin.service:
name: nginx
state: started
enabled: yes
tags: [configure]
- name: Deploy basic index page (template example)
ansible.builtin.template:
src: templates/index.html.j2 # Example template path
dest: /var/www/html/index.nginx-debian.html # Default Nginx path
owner: root
group: root
mode: '0644'
tags: [configure] Docker Compose Stack (Example: Portainer)
Deploys a simple Docker Compose application (e.g., Portainer) on the 'Docker Node'. Requires Docker and Docker Compose to be pre-installed on the target.
K3s Kubernetes Cluster (Basic Setup)
Installs a single-node K3s cluster on the 'Control Node'. Note: This is a simplified setup for demonstration.
---
- name: Install K3s Single Node Cluster
hosts: control_node # Install on the control node itself for demo
become: yes
tasks:
- name: Download K3s installation script
ansible.builtin.get_url:
url: https://get.k3s.io
dest: /tmp/k3s-install.sh
mode: '0755'
- name: Execute K3s installation script
ansible.builtin.command:
cmd: /tmp/k3s-install.sh
creates: /usr/local/bin/k3s # Avoid re-running if k3s exists
register: k3s_install_result
changed_when: k3s_install_result.rc == 0
- name: Ensure K3s service is started
ansible.builtin.service:
name: k3s
state: started
enabled: yes
- name: Wait for Kubeconfig to be available
ansible.builtin.wait_for:
path: /etc/rancher/k3s/k3s.yaml
timeout: 60
- name: Read Kubeconfig file
ansible.builtin.slurp:
src: /etc/rancher/k3s/k3s.yaml
register: k3s_kubeconfig
- name: Display Kubeconfig hint (for manual use)
ansible.builtin.debug:
msg: "K3s installed. Use 'sudo k3s kubectl get nodes' or copy Kubeconfig."
Simplified Setup
This playbook installs a basic single-node K3s cluster. Production setups require more complex configuration, multiple nodes, and security considerations.
LAMP Stack Installation
Installs Apache, MySQL (MariaDB), and PHP on the 'Web Server Node'. This playbook sets up a complete web application environment with secure defaults.
---
- name: Deploy LAMP Stack
hosts: web_server_node
become: yes
vars:
mysql_root_password: "{{ vault_mysql_root_password }}"
php_version: "8.2"
document_root: "/var/www/html"
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- name: Install Apache web server
ansible.builtin.apt:
name: [apache2, apache2-utils]
state: present
- name: Install MariaDB server
ansible.builtin.apt:
name: [mariadb-server, mariadb-client, python3-mysqldb]
state: present
- name: Install PHP and modules
ansible.builtin.apt:
name:
- "php{{ php_version }}"
- "php{{ php_version }}-mysql"
- "php{{ php_version }}-curl"
- libapache2-mod-php
state: present
- name: Start and enable Apache
ansible.builtin.service:
name: apache2
state: started
enabled: yes
handlers:
- name: Restart Apache
ansible.builtin.service:
name: apache2
state: restarted Security Note
Store sensitive data like database passwords in Ansible Vault using ansible-vault encrypt_string.
Basic Security Hardening
Applies essential security measures including UFW firewall, fail2ban for intrusion prevention, and SSH hardening.
---
- name: Security Hardening Playbook
hosts: all
become: yes
vars:
ssh_port: 22
allowed_ssh_users: [deploy, admin]
fail2ban_maxretry: 5
tasks:
# UFW Firewall
- name: Install UFW firewall
ansible.builtin.apt:
name: ufw
state: present
- name: Set UFW default policies
community.general.ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
loop:
- { direction: 'incoming', policy: 'deny' }
- { direction: 'outgoing', policy: 'allow' }
- name: Allow SSH through UFW
community.general.ufw:
rule: allow
port: "{{ ssh_port }}"
proto: tcp
- name: Enable UFW
community.general.ufw:
state: enabled
# Fail2ban
- name: Install fail2ban
ansible.builtin.apt:
name: fail2ban
state: present
- name: Configure fail2ban jail
ansible.builtin.template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
notify: Restart fail2ban
# SSH Hardening
- name: Harden SSH configuration
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
notify: Restart SSH
handlers:
- name: Restart fail2ban
ansible.builtin.service:
name: fail2ban
state: restarted
- name: Restart SSH
ansible.builtin.service:
name: sshd
state: restarted Warning
Ensure you have SSH key access configured before disabling password authentication.
Advanced Topics
Using Custom Roles
Ansible Roles provide a way to organize playbooks into reusable components. A role groups related tasks, handlers, templates, and variables into a standard directory structure.
Role Directory Structure
roles/
└── webserver/
├── tasks/
│ └── main.yml # Main task list
├── handlers/
│ └── main.yml # Handler definitions
├── templates/
│ └── vhost.conf.j2 # Jinja2 templates
├── files/
│ └── ssl.crt # Static files
├── vars/
│ └── main.yml # Role variables
├── defaults/
│ └── main.yml # Default variables
└── meta/
└── main.yml # Role metadata & dependencies Example Role Tasks
# roles/webserver/tasks/main.yml
---
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
tags: [install]
- name: Deploy virtual host config
ansible.builtin.template:
src: vhost.conf.j2
dest: "/etc/nginx/sites-available/{{ domain }}.conf"
notify: Reload nginx
tags: [configure]
- name: Enable virtual host
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ domain }}.conf"
dest: "/etc/nginx/sites-enabled/{{ domain }}.conf"
state: link
notify: Reload nginx Using Roles in Playbooks
# site.yml
---
- hosts: webservers
roles:
- role: webserver
vars:
domain: example.com
- role: ssl_certificates
- role: monitoring Variables and Inventory Management
Proper variable and inventory management is crucial for maintaining multiple environments. Here's how to structure your configuration for development, staging, and production.
Directory Layout
inventory/
├── production/
│ ├── hosts.yml
│ └── group_vars/
│ ├── all.yml
│ └── webservers.yml
├── staging/
│ ├── hosts.yml
│ └── group_vars/
│ └── all.yml
└── development/
└── hosts.yml Inventory File Example
# inventory/production/hosts.yml
---
all:
children:
webservers:
hosts:
web1.example.com:
ansible_host: 10.0.1.10
web2.example.com:
ansible_host: 10.0.1.11
databases:
hosts:
db1.example.com:
ansible_host: 10.0.2.10 Group Variables
# inventory/production/group_vars/webservers.yml
---
nginx_worker_processes: 4
nginx_worker_connections: 2048
ssl_certificate_path: /etc/ssl/certs/prod.crt
# Sensitive data - encrypted with ansible-vault
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
63643136356536... Variable Precedence (lowest to highest)
- Role defaults (
defaults/main.yml) - Inventory group_vars
- Inventory host_vars
- Playbook group_vars/host_vars
- Role vars (
vars/main.yml) - Task vars and block vars
- Extra vars (
-e "var=value") - highest priority
Ansible Best Practices
Following these practices ensures your playbooks are maintainable, reliable, and secure.
1. Always Name Your Tasks
# Good - descriptive task names
- name: Install nginx web server
ansible.builtin.apt:
name: nginx
state: present
# Bad - no task name
- apt:
name: nginx 2. Use FQCN (Fully Qualified Collection Names)
# Good - explicit and future-proof
- ansible.builtin.apt:
name: nginx
# Avoid - ambiguous
- apt:
name: nginx 3. Use Handlers for Service Restarts
tasks:
- name: Update nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Reload nginx # Only runs if changed
handlers:
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded 4. Secure Secrets with Ansible Vault
# Encrypt a string
ansible-vault encrypt_string 'supersecret' --name 'db_password'
# Encrypt a file
ansible-vault encrypt secrets.yml
# Run playbook with vault
ansible-playbook site.yml --ask-vault-pass 5. Use Tags for Selective Execution
- name: Install packages
ansible.builtin.apt:
name: "{{ item }}"
loop: "{{ packages }}"
tags: [install, packages]
# Run only install tasks
ansible-playbook site.yml --tags install 6. Ensure Idempotency
Tasks should be safe to run multiple times without changing the result if the desired state is already achieved.
7. Use Block for Error Handling
- name: Handle deployment with rollback
block:
- name: Deploy application
ansible.builtin.copy:
src: app/
dest: /var/www/app/
- name: Restart service
ansible.builtin.service:
name: app
state: restarted
rescue:
- name: Rollback on failure
ansible.builtin.copy:
src: backup/
dest: /var/www/app/ Reference
Common CLI Commands
A quick reference for frequently used Ansible CLI commands.
| Command | Description |
|---|---|
ansible --version | Check Ansible version. |
ansible-inventory --list -i inventory.yml | List inventory hosts and groups. |
ansible all -m ping -i inventory.yml | Ping all hosts in inventory. |
ansible-playbook playbook.yml -i inventory.yml | Run a playbook. |
ansible-playbook playbook.yml --check | Perform a dry run of a playbook. |
ansible-playbook playbook.yml --limit web_servers | Run playbook only on specific hosts/groups. |
ansible-vault create secrets.yml | Create an encrypted vault file. |
ansible-playbook playbook.yml --ask-vault-pass | Run playbook asking for vault password. |
Troubleshooting Tips
Common issues and how to resolve them when working with the sandbox or Ansible in general.
- Connection Errors: Ensure SSH keys are correctly configured and target VMs are reachable. Check firewall rules.
- Permission Denied: Use `become: yes` for tasks requiring root privileges. Verify sudo configuration on target nodes.
- Module Not Found: Ensure required Ansible collections or Python libraries are installed on the control node.
- Idempotency Issues: Review tasks to ensure they only make changes when necessary (e.g., use `creates` argument for command/shell modules).
- Variable Undefined: Check variable definitions, scope (host_vars, group_vars), and precedence. Use `-v` or `-vvv` for verbose output.