Ansible Conventions¶
Conventions for writing, organizing, and running Ansible playbooks in the CWIQ infrastructure. Consistent structure prevents drift and makes multi-environment deployments safe.
Multi-Environment Inventory Structure¶
All service playbooks use the inventory directory pattern recommended by the Ansible documentation. Each environment gets its own directory with completely separate hosts and variables. This means all environments coexist on disk — there is no file swapping.
{service-playbook}/
├── inventory/
│ ├── shared/
│ │ ├── hosts.yml ← hosts + connection settings for shared env
│ │ └── group_vars/
│ │ └── all.yml ← shared env variables (NOT in git)
│ ├── dev/
│ │ ├── hosts.yml ← hosts + connection settings for dev env
│ │ └── group_vars/
│ │ └── all.yml ← dev env variables (NOT in git)
│ └── demo/
│ ├── hosts.yml
│ └── group_vars/
│ └── all.yml
├── group_vars/
│ ├── all.yml.template ← shared defaults template (IN git)
│ ├── all-dev.yml.template ← dev template (IN git)
│ └── all-demo.yml.template ← demo template (IN git)
├── roles/
├── setup.yml
└── deploy-service.yml
Run with: ansible-playbook -i inventory/dev/ setup.yml
This is safer than single-file group_vars because environment configs never overlap.
Template File Convention¶
CRITICAL: Never create actual group_vars files in the repo
The inventory/{env}/group_vars/all.yml files on the ansible server contain real credentials. Creating them in the repo would overwrite production configuration on git pull.
| File type | Location | Status in git |
|---|---|---|
| Template (defaults, no secrets) | group_vars/all.yml.template |
Tracked |
| Template (env-specific defaults) | group_vars/all-{env}.yml.template |
Tracked |
| Actual group_vars (real values) | inventory/{env}/group_vars/all.yml |
Gitignored |
| Actual inventory | inventory/{env}/hosts.yml |
Gitignored |
On the ansible server, operators create actual files from templates once:
mkdir -p inventory/dev/group_vars
cp group_vars/all-dev.yml.template inventory/dev/group_vars/all.yml
# Edit inventory/dev/group_vars/all.yml with real credentials
Ansible Server Rules¶
CRITICAL: Ansible Server is Always on main
The ansible server at /data/ansible/cwiq-ansible-playbooks/ MUST always be on the main branch. Never checkout a feature branch on the ansible server.
Correct Workflow¶
Work on feature branches locally, merge to main, then pull on the ansible server:
# 1. Make changes on feature branch locally
git checkout -b feature/ansible-new-playbook main
# ... edit files ...
git push origin feature/ansible-new-playbook
# 2. Create MR in GitLab, merge to main
# 3. Only after merge — pull on ansible server
ssh ansible@ansible-shared-cwiq-io
ansible-helper # cd + venv + vault auth
git pull origin main
# 4. Run playbook from main
ansible-playbook -i inventory/dev/ deploy-service.yml
Never:
- git checkout feature/* on the ansible server
- git pull origin feature/* on the ansible server
- Run playbooks from a feature branch on the ansible server
ansible-helper Function¶
ansible-helper is a bash alias in the ansible user's shell that automates the three setup steps:
# What ansible-helper does (equivalent):
cd /data/ansible/cwiq-ansible-playbooks
source .venv/bin/activate
# Logs into Vault with AppRole and exports ROLE_ID + SECRET_ID
Always use ansible-helper before running any playbook. Running ansible-playbook without it means Vault credentials are not set, causing playbooks that read secrets to fail.
Role Structure¶
Each role follows the standard Ansible directory layout:
roles/{role_name}/
├── defaults/
│ └── main.yml ← default variable values (overridable)
├── tasks/
│ └── main.yml ← task definitions
├── handlers/
│ └── main.yml ← handlers (e.g., restart service)
├── templates/
│ └── *.j2 ← Jinja2 templates
├── files/
│ └── * ← static files to copy
├── vars/
│ └── main.yml ← role-internal variables (not overridable)
└── meta/
└── main.yml ← role dependencies
Key conventions:
- defaults/main.yml contains variables that callers may override
- vars/main.yml contains internal constants that should not be overridden
- Templates use .j2 extension
- Tasks are broken into multiple files and included from main.yml for long roles
Variable Precedence¶
Variables applied in this order (last wins):
defaults/main.yml— role defaultsgroup_vars/all.yml.template— shared defaults templateinventory/{env}/group_vars/all.yml— environment-specific values (real secrets here)- Per-host variables in
inventory/{env}/hosts.yml - Extra vars on command line (
-e "key=value")
Playbook Naming Conventions¶
| Type | Pattern | Example |
|---|---|---|
| Full deployment | setup.yml or deploy-{service}.yml |
deploy-prometheus.yml |
| Config-only deployment | deploy-config.yml |
deploy-config.yml --tags dev |
| Health check | healthcheck.yml |
healthcheck.yml |
| Restart | restart.yml |
restart.yml |
| Stop | stop.yml |
stop.yml |
| SSL-specific | ssl-deploy-{service}.yml |
ssl-deploy-vault.yml |
| SSO setup | provision-sso-users.yml |
provision-sso-users.yml |