# Ansible ## Inventory and Execution - Always pass `-i inventory.yml` explicitly or run from the directory containing `ansible.cfg` - Playbooks that can't find inventory skip silently with no error — a common source of "it ran but nothing happened" confusion - Variables that need customisation go in `inventory.yml` files, not scattered across role defaults ## Role Structure - Roles follow standard structure: `tasks/main.yml`, `templates/*.j2`, `handlers/main.yml` - Jinja2 templates have `.j2` extension and include a "managed by Ansible" header comment ## Template Safety - **Never use placeholder values with `-e` for vars that template config files.** Using `-e "var=dummy"` will overwrite live configs with garbage. Either read real values, use `--skip-tags` to skip templating tasks, or restructure roles so sensitive templates are in a separate tag. ## Credential Safety - Pass secrets via `@file` not `-e` on the command line — `-e "key=value"` exposes secrets in `ps` output - Use temp files with `trap rm` cleanup: `-e "@${tmpfile}"` ## Module Gotchas - `docker_compose_v2` doesn't support `state: restarted` — use `recreate: always` instead - `ansible.builtin.unarchive` with `remote_src` and `extra_opts: --strip-components` is unreliable — use `get_url` + `command: tar` separately - `get_url` won't re-download when the URL changes but the destination filename stays the same — use a version marker file to detect changes ## Service Restarts - Some services (dnsmasq, etc.) need container restarts for config changes to take effect - Ansible handlers handle this, but always verify the change took effect (e.g., `dig @ +short`) ## Docker Compose - `network_mode: host` ignores `ports:` mappings — remove `ports:` to avoid warnings