Compositions & Environments¶
Source of truth
hns-platform/playbooks/services.yml (guards), init-composition-db.yml, teardown-composition-db.yml, seed-composition.yml, and roles/hns-service/tasks/main.yml (image tag). Update this page when those change.
One cluster hosts multiple parallel stacks: the baseline plus N preview compositions (per-branch or per-PR). A composition is a self-contained stack with its own namespace, its own backend database, and its own domain.
The four knobs¶
Set per Nebion environment (see Environment configuration):
| Knob | Baseline | Preview example (pr-34) |
|---|---|---|
K8S_NAMESPACE |
hns |
hns-pr34 |
DB_NAME |
hns_ticketing |
hns_ticketing_pr34 |
DOMAIN |
portal.hnst.dev3.wsagency.io |
pr34.portal.hnst.dev3.wsagency.io |
<SERVICE>_VERSION |
dev |
per-branch override, e.g. BACKEND_VERSION=HNSTIK-42 |
Convention: DB_NAME = hns_ticketing_<slug>, where <slug> is the namespace minus the hns- prefix with dashes turned into underscores (Postgres dislikes dashes).
What is isolated¶
| Dimension | Mechanism |
|---|---|
| Compute | Kubernetes namespace — pods, Services, Ingresses all namespaced |
| Backend data | A separate database on db-01 (DB_NAME) |
| Keycloak data | In-cluster hns-idp-db is per-namespace automatically |
| URLs | All ingress hosts derive from DOMAIN |
| Images | Tag carries the namespace (<sha7>-<namespace>) |
Why image tags carry the namespace
A service that bakes composition-specific values at build time — e.g. the mobile-web SPA compiling VITE_* from {{ domain }} — would, on a bare-SHA tag, collide with another composition's cached image on the single node (imagePullPolicy: IfNotPresent). The namespace suffix gives each composition its own tag. Code-only images still share every layer (the registry dedupes by digest), so the cost is negligible. See Deployment model.
Lifecycle of a preview composition¶
1. Nebion env: set K8S_NAMESPACE, DB_NAME (non-baseline), DOMAIN, optional *_VERSION
2. Action: init-composition-db → creates the DB on db-01
3. Deploy (playbooks/services.yml) → stack lands in the namespace
└─ seed-composition runs last → users + reference content (below)
…
4. Teardown: Destroy (deletes namespace) + action teardown-composition-db (drops the DB)
init-composition-db.yml is idempotent — it creates DB_NAME (owner vault_db_user, UTF-8, from template0) and grants privileges; re-running is a no-op. It refuses to run without an explicit DB_NAME.
The seed invariant¶
seed-composition.yml runs as the last step of every deploy (and as a standalone action), converging the namespace to a known baseline. Every task is idempotent. It creates:
- Keycloak users
admin@hns.hr(promoted toSUPER_ADMIN) andfan@hns.test, viakcadminside the idp pod. - Their backend shadow rows, by obtaining a real password-grant token and calling
GET /api/v1/users/me— exercising the same JIT-provisioning path a real login takes. (The long retry window here absorbs JWKS/cert readiness on a virgin deploy.) - Reference + test content: stadiums, a test match, the Petrol QA dataset.
Set SEED_DISABLE=1 (e.g. a future production environment) to skip seeding entirely. Override the seed passwords with SEED_ADMIN_PASSWORD / SEED_FAN_PASSWORD.
Safety: deleting the right database¶
The two deploy guards (in services.yml) refuse to run without an explicit K8S_NAMESPACE, and refuse a preview namespace that still points at the baseline DB_NAME — see Deployment model.
Teardown drops the database named by DB_NAME
teardown-composition-db.yml drops whatever DB_NAME resolves to. It refuses only the literal baseline names hns_ticketing and keycloak — every other value is dropped without further protection. A wrong DB_NAME during a teardown (or a "from scratch" redeploy that tears down first) will drop that composition's database. Always confirm DB_NAME matches the composition you intend to destroy before running a teardown.
Last Updated: June 2026