Environments
Environment Ladder
Five environments form a sequential promotion ladder. Every promotion carries the same image digest — no rebuilds, no re-tags.
| Environment | Purpose | Deploys From | Auto? | Data |
|---|---|---|---|---|
| local | Developer inner loop | Docker Compose on laptop | Manual | Throwaway / seed fixtures |
| dev | Integration baseline | Auto from main merge |
Yes (auto-sync) | Seeded synthetic dataset |
| preview / pr-N | Per-PR ephemeral review | Per PR (ArgoCD ApplicationSet) | Yes (on PR open) | Seeded ephemeral, torn down on close |
| staging | Release candidate validation | RC digest, prod-shaped config | PR approval required | Anonymized or fully synthetic |
| prod | Live traffic | Gated canary via Argo Rollouts | PR + manual approval + canary | Real production data |
Config per Environment
The application binary does not change across environments. Only values differ.
| Dimension | local | dev | preview | staging | prod |
|---|---|---|---|---|---|
| Scale | Single replica | 1–2 replicas | 1 replica | Prod-shaped replicas | HPA-managed |
| Dependency tier | lite | standard | lite / standard | full | full |
| Endpoints | localhost:* |
Internal cluster DNS | Ephemeral Ingress | staging.bitvault.io |
bitvault.io |
| Feature flags | All on | All on | PR-specific | RC-gated | Canary-gated |
| Secrets | .env / Compose secrets |
Vault dev namespace | Ephemeral Vault path | Vault staging namespace | Vault prod namespace |
| Rollout aggressiveness | N/A | Immediate | Immediate | Canary (abbreviated) | Full canary + analysis |
:::tip 12-factor parity The application code path must not differ across environments. Only values (config, secrets, scale, endpoints) change. Behavior that differs by environment is a latent production bug. :::
:::warning
The image digest must not differ across environments. The same sha256:… that passed CI runs in staging and then in production — no exceptions, no rebuilds.
:::
Promotion Flow
flowchart LR
ci["CI: build once\nsigned digest D"]
dev["dev\n(auto from main)"]
staging["staging\n(PR approval)"]
prod["prod\n(PR + manual approve\n+ canary analysis)"]
ci -->|"auto-merge\nGitOps PR"| dev
dev -->|"open GitOps PR\n(digest D)"| staging
staging -->|"open GitOps PR\n+ manual approval"| prod
The signed digest D is the artifact that flows through every stage. No stage produces a new image.
Ephemeral Preview Environments
Each pull request automatically receives a preview environment driven by an ArgoCD ApplicationSet PR generator:
- The ApplicationSet watches for open PRs and materializes an
Applicationper PR into thebitvault-preview-pr-Nnamespace. - The environment uses the
liteorstandarddependency tier with synthetic seed data. - On PR merge or close, the
Applicationis deleted and the namespace is torn down automatically. - A TTL-based reaper (CronJob) removes stragglers where the webhook did not fire (e.g., force-pushed branches abandoned without merge).
- Preview environments get a deterministic Ingress hostname:
pr-N.preview.bitvault.dev.
Preview environments are not connected to any persistent data or real secrets. They exist solely for functional review and automated E2E validation against the PR’s image digest.
Data Handling
| Environment | Data policy |
|---|---|
| prod | Real user data; full retention and encryption |
| staging | Synthetic or fully anonymized dataset; never real prod data |
| preview | Seeded fixtures generated at namespace creation; ephemeral, destroyed with env |
| dev | Synthetic seed data applied on cluster bootstrap |
| local | Developer-controlled fixtures; throwaway |
:::warning Never copy production data to staging or preview environments. If real-derived data is ever required for a specific test (e.g., a production data shape edge case), it must be anonymized by an automated pipeline before being loaded, and only into staging — never into preview or shared dev. :::