Skip to content

Ansible Playbooks

Ansible’s superpower is imperative-looking playbooks with declarative-looking outcomes — as long as your modules are idempotent. Where that promise breaks is where the interesting bugs live.

  • Directoryansible/
    • Directoryinventory/
      • prod.yml
      • staging.yml
    • Directorygroup_vars/
      • all.yml
      • webservers.yml
    • Directoryroles/
      • Directorycommon/
        • tasks/main.yml
        • handlers/main.yml
        • Directorytemplates/
      • Directorynginx/
      • Directorypostgres/
    • Directoryplaybooks/
      • site.yml
      • patching.yml
    • ansible.cfg
roles/nginx/tasks/main.yml
- name: Install nginx
ansible.builtin.package:
name: nginx
state: present
notify: reload nginx
- name: Render main config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: "0644"
validate: "nginx -t -c %s"
notify: reload nginx
- name: Ensure nginx enabled and started
ansible.builtin.service:
name: nginx
state: started
enabled: true

Handlers, notifications, and the run order

Section titled “Handlers, notifications, and the run order”
Type of taskIdempotent?
package, service, file✅ Built-in check-then-act
template, copy✅ Content-diff before write
command, shellYou must guard with creates: / changed_when:
uri, get_urlDepends — check force, checksum
Guarding a shell task
- name: Bootstrap a one-shot script
ansible.builtin.shell: /opt/init/bootstrap.sh
args:
creates: /var/lib/reetwiz/.bootstrapped
inventory/azure_rm.yml
plugin: azure.azcollection.azure_rm
include_vm_resource_groups:
- core-rg
- workloads-rg
keyed_groups:
- prefix: tag
key: tags['role']
auth_source: cli
Terminal window
# lint
ansible-lint playbooks/site.yml
# check mode + diff (dry run)
ansible-playbook -i inventory/staging.yml playbooks/site.yml --check --diff
# molecule (per-role tests in ephemeral containers)
cd roles/nginx && molecule test