Expert guidance for developing, organizing, and maintaining Ansible playbooks with best practices for multi-platform infrastructure automation and configuration management.
This skill provides comprehensive guidance for working with Ansible playbooks following infrastructure automation best practices. It covers repository organization, standardized structures, quality standards, security practices, and multi-platform support.
When working with Ansible repositories, expect this standard organization:
```
repository/
├── CLAUDE.md # Repository-level guidance
├── README.md # User documentation
├── SECURITY.md # Security policy
├── PRE_COMMIT_CHECKLIST.md # Security checklist
├── verify-security.sh # Automated security checks
├── .gitignore # Repository-wide ignore patterns
└── ProjectName/ # Self-contained playbook projects
├── CLAUDE.md # Project-specific documentation
├── main.yml # Main playbook entry point
├── ansible.cfg # Ansible configuration
├── .gitignore # Project-level protections
├── inventory/
│ ├── hosts.yml # Actual inventory (SENSITIVE - not in git)
│ └── hosts.yml.example # Sanitized example (REQUIRED in git)
├── group_vars/
│ ├── all.yml # Actual config (SENSITIVE - not in git)
│ └── all.yml.example # Sanitized example (REQUIRED in git)
├── roles/ # Modular role directories
└── templates/ # Shared Jinja2 templates
```
Every playbook project follows this template structure:
1. **main.yml** - Main playbook entry point
2. **ansible.cfg** - Ansible configuration (inventory path, logging, connection settings)
3. **inventory/hosts.yml** - Actual inventory with real IPs/credentials (gitignored)
4. **inventory/hosts.yml.example** - Sanitized example inventory (REQUIRED in git)
5. **group_vars/all.yml** - Actual centralized configuration (gitignored)
6. **group_vars/all.yml.example** - Sanitized example configuration (REQUIRED in git)
7. **.gitignore** - Protect sensitive data (REQUIRED)
8. **CLAUDE.md** - Project-specific documentation
Each role follows Ansible best practices:
```
roles/role_name/
├── meta/main.yml # Role metadata and dependencies
├── defaults/main.yml # Default variables (lower precedence)
├── vars/main.yml # Role variables (higher precedence)
├── tasks/main.yml # Main task definitions
├── handlers/main.yml # Event handlers
└── templates/ # Role-specific templates
```
**CRITICAL**: All playbooks use centralized configuration in `group_vars/all.yml` as a single source of truth:
```yaml
role_enabled:
role_name: true/false
software_versions:
package_name: "version_number"
mqtt_config:
host: "ip_address"
port: 1883
username: "user"
password: "password" # TODO: Use ansible-vault
paths:
bin_dir: "/usr/local/bin"
data_dir: "/data"
opt_dir: "/opt"
config_dir: "/etc"
systemd_dir: "/etc/systemd/system"
repositories:
package_name:
base_url: "https://github.com/..."
architecture: "linux-arm64"
architecture_mapping:
"x86_64":
package_name: "linux-amd64"
"aarch64":
package_name: "linux-arm64"
```
All playbooks and roles MUST adhere to these standards:
- Use `ansible.builtin.module_name` instead of `module_name`
- Use `ansible.posix.authorized_key` instead of `authorized_key`
Use a multi-dimensional inventory where hosts belong to multiple groups simultaneously:
#### 1. OS Family Groups (Distribution-based)
```yaml
all:
children:
debian_based:
children:
raspberry_pi: # All Raspberry Pi hosts
ubuntu_baremetal: # Ubuntu bare-metal servers
ubuntu_vm: # Ubuntu virtual machines
redhat_based:
children:
centos_baremetal: # CentOS/Rocky Linux servers
arch_based:
children:
arch_baremetal: # Arch Linux systems
```
#### 2. Purpose Groups (Function-based)
```yaml
ntp: # NTP servers
pihole: # Pi-hole DNS servers
k3s: # Kubernetes cluster
children:
control: # K3s control plane
worker: # K3s worker nodes
```
#### 3. Feature Groups (Capability-based)
```yaml
vm_hardware: # All virtual machines
uctronics: # Hosts with specific hardware features
```
A single host can target based on relevant characteristics:
```yaml
when: "'raspberry_pi' in group_names"
when: "'vm_hardware' in group_names"
```
Support multiple architectures and distributions:
```yaml
ansible.builtin.apt:
# ...
when: ansible_os_family == "Debian"
ansible.builtin.get_url:
url: "{{ repositories.package.base_url }}/{{ architecture_mapping[ansible_architecture].package }}"
```
When creating a new playbook project:
```bash
mkdir NewProject
cd NewProject
mkdir -p inventory group_vars roles templates
```
```bash
cp ../ExistingProject/ansible.cfg .
cp ../ExistingProject/.gitignore .
cp ../ExistingProject/inventory/hosts.yml.example inventory/
cp ../ExistingProject/group_vars/all.yml.example group_vars/
cp inventory/hosts.yml.example inventory/hosts.yml
cp group_vars/all.yml.example group_vars/all.yml
```
Create `main.yml`:
```yaml
hosts: target_group
gather_facts: true
become: true
tasks:
- name: Task description
ansible.builtin.import_role:
name: role_name
when: role_enabled.role_name | default(true)
```
Document the project-specific architecture, roles, and commands.
Edit `group_vars/all.yml` with role enablement, versions, configurations, paths, and repositories.
**CRITICAL**: Always create and maintain sanitized example files:
```bash
cp inventory/hosts.yml inventory/hosts.yml.example
cp group_vars/all.yml group_vars/all.yml.example
```
**Maintenance Rule**: Whenever you modify `inventory/hosts.yml` or `group_vars/all.yml`, you MUST immediately update the corresponding `.example` files with sanitized versions.
Protect sensitive data with proper `.gitignore`.
```bash
cd ProjectName/
ansible-playbook -i inventory/hosts.yml main.yml
ansible-playbook -i inventory/hosts.yml main.yml --limit groupname
ansible-playbook -i inventory/hosts.yml main.yml --check
ansible-playbook -i inventory/hosts.yml main.yml --tags "docker,monitoring"
```
```bash
ansible-playbook -i inventory/hosts.yml main.yml --syntax-check
ansible-lint main.yml
ansible-lint roles/role_name/
ansible-inventory -i inventory/hosts.yml --list
ansible-inventory -i inventory/hosts.yml --graph groupname
```
```bash
./verify-security.sh
```
```bash
echo 'password123' | ansible-vault encrypt_string --stdin-name 'variable_name'
ansible-vault edit group_vars/all.yml
ansible-playbook -i inventory/hosts.yml main.yml --ask-vault-pass
```
When working with Ansible playbooks in this environment, always follow these principles:
1. **Centralization**: Single source of truth in `group_vars/all.yml`
2. **Reusability**: Generic templates and roles
3. **Standards Compliance**: ansible-lint passing, FQCN, proper naming
4. **Multi-Platform**: Support multiple architectures and distributions
5. **Security**: Vault-encrypted credentials, SSH keys, no hardcoded secrets
6. **Documentation**: Comprehensive CLAUDE.md files at repository and project levels
7. **Example Files**: Always maintain sanitized `.example` files for sensitive configurations
8. **DRY Principle**: Eliminate duplication through centralized configuration
When modifying existing playbooks:
1. Read the project-specific `CLAUDE.md` first
2. Review `group_vars/all.yml` for centralized configuration
3. Check inventory structure in `inventory/hosts.yml`
4. Run `ansible-lint` before and after changes
5. Test with `--check` mode first
6. Update `.example` files if sensitive files were modified
7. Run security verification before committing
When implementing user management:
```yaml
users_list:
- name: username
groups: "sudo,docker,..."
ssh_public_key: "ssh-rsa AAAAB3..."
sudo_access: true
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/ansible-playbook-development/raw