Skip to content

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 to SUPER_ADMIN) and fan@hns.test, via kcadm inside 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