# container_isolation Ansible role Creates per-app service accounts (UID/GID 2000+) on every host, so each Docker container can run as its own dedicated UID instead of root or a shared user. `jerick` is added as a secondary member of every app group (and the shared `mediapipeline` group), so jerick retains access everywhere regardless of whatever folder permissions you set up separately on the NFS server. **Scope:** this role only manages accounts (groups + users). NFS folder creation, ownership, and permission bits are handled outside Ansible, by you, on the NFS server. ## Layout ``` ansible/ ├── site.yml # top-level playbook, hosts: all └── roles/container_isolation/ ├── tasks/ │ ├── main.yml # entry point, includes the others │ ├── sync_users.yml # creates groups + users on every host │ └── jerick_access.yml # adds jerick to every group, every host ├── vars/main.yml # source of truth: app list, uids, shared groups └── files/ ├── passwd.containers # reference copy, human-readable └── group.containers # reference copy, human-readable ``` `vars/main.yml` is what Ansible actually reads. The `files/*.containers` files are a human-readable reference / diff-friendly changelog — not consumed directly by any task, since the built-in `group`/`user` modules create accounts idempotently rather than appending raw lines to `/etc/passwd`. ## Before running 1. Point this at your dynamic inventory however you normally do, e.g.: ```bash ansible-playbook -i your_dynamic_inventory.py site.yml ``` No inventory group targeting is needed — `site.yml` runs against `hosts: all`, and the role applies the same logic everywhere. 2. Confirm `jerick` already exists as a real user on every host. The role does **not** create jerick's account (treated as a pre-existing human user) — it only adds jerick to the app groups. If jerick is missing on a host, the role prints a warning and skips the group-membership tasks for that host rather than failing the whole run. ## Running ```bash ansible-playbook -i your_dynamic_inventory.py site.yml --check --diff # dry run first ansible-playbook -i your_dynamic_inventory.py site.yml ``` Safe to re-run any time — every task uses Ansible's built-in idempotent modules (`group`, `user`), so a second run produces no changes. ## Adding a new app later 1. Add a line to `roles/container_isolation/vars/main.yml` under `container_apps`, with the next free UID (currently up to 2026 — use 2027 next). **Never reuse or renumber an existing UID** once real folders have been chowned to it on the NFS server. 2. If it needs shared access to another app's data, add it to the relevant `shared_groups[].members` list (or create a new shared group, GID 3001+). 3. Update `files/passwd.containers` and `files/group.containers` to match, for the human-readable record. 4. Re-run the playbook. ## What you still need to do yourself - **NFS folder creation/ownership/permissions** on the NFS server — `chown :` and `chmod` each app's folder using the UIDs/GIDs from `vars/main.yml`. With jerick in every app's group, `770` (owner+group rw, others none) gives jerick read-write access everywhere while keeping apps isolated from each other; `750` would make jerick read-only. - **`/etc/exports`** on the NFS server — not touched by this role. - **`docker-compose.yml` edits** — add `user: "UID:GID"` (and `group_add:` for apps in `mediapipeline`) to each service, using the UIDs from `vars/main.yml`. Happy to generate these once you share your compose files. - **NFS protocol version / idmapping verification** — confirm with `nfsstat -m` on a client before relying on numeric UID/GID matching across hosts; NFSv4 idmapping misconfiguration is the most common cause of permissions silently not working as expected.