Custom resources
Two CRDs in the pagifier.io/v1alpha1 group. Developers never touch them —
they are the operator's contract — but platform operators observe them
directly.
Application
Long-lived; one per project per environment. Carries a pointer to the release that should be live.
apiVersion: pagifier.io/v1alpha1
kind: Application
metadata:
name: frontend
namespace: pgf-acme-prod
spec:
tenant: acme
environment: prod
activeRelease: frontend-r20260714-101530-ab12cd34 # set by the API
paused: false
status:
phase: Available # Pending | WaitingForBuild | Deploying | Available | Degraded | Failed | Paused
deployedRelease: frontend-r20260714-101530-ab12cd34
url: https://app.company.com
readyReplicas: 3
canary: # present during a canary rollout
release: frontend-r…
weight: 50
stepStartedAt: "2026-07-14T10:20:00Z"
analysisFailures: 0
lastAnalysis: all 2 gates passing
activeColor: green # blue/green strategy
colorReleases:
blue: frontend-r…
green: frontend-r…
kubectl get applications shows tenant, environment, phase, active
release, canary weight, and URL as columns. Preview applications carry a
pagifier.io/expires-at annotation and are garbage-collected on expiry
(deleting an Application cascades to its Releases and workloads).
Release
Immutable; one per upload. Snapshots the artifact reference and the fully resolved configuration.
apiVersion: pagifier.io/v1alpha1
kind: Release
metadata:
name: frontend-r20260714-101530-ab12cd34
namespace: pgf-acme-prod
labels:
pagifier.io/fingerprint: 4f2a… # build-input identity (enables image reuse)
spec:
application: frontend
artifact:
bucket: pagifier-artifacts
key: artifacts/acme/frontend/prod/r…/app.zip
sha256: 9f86d08…
config: { … } # resolved snapshot (JSON)
status:
phase: Deployed # Pending | Building | Built | Deploying | Deployed | Failed | Superseded
image: registry/acme/frontend:b-4f2a91c02be411aa
buildJob: build-frontend-r…
buildLog: | # tail, on build failure
…
message: image built and pushed
Phase semantics worth knowing:
- Pending with a
queued:message means the cluster-wide build concurrency limit is reached; the build starts when a slot frees. - Built without a build job means the image was reused — an earlier release had an identical build fingerprint.
- Superseded releases are rollback targets; the rollback API re-arms them to Built.
- Finished releases beyond the retention window are pruned in-cluster; full history remains in PostgreSQL.
Labels
| Label | On | Meaning |
|---|---|---|
app.kubernetes.io/name | pods, selectors | Workload/track identity (frontend, frontend-canary, frontend-blue) |
pagifier.io/application | everything | Application identity across all tracks — what NetworkPolicy and PDB select |
pagifier.io/tenant, pagifier.io/environment | everything | Tenancy |
pagifier.io/release | workloads | Which release rendered this |
pagifier.io/fingerprint | releases | Build-input identity |