Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLVI · Deployment EnvironmentsEnvironments

Environments and promotion — the model and the boundaries between environments

Intermediate⏱ ~20 mingit

What you'll learn

  • Define an environment as a named deployment target with its own identity, configuration, and blast radius
  • Distinguish what crosses an environment boundary from what stays inside one
  • State the promotion invariant: the same digest runs in every environment
  • Recognise that environments are not servers; they are policy boundaries

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

An environment is a named deployment target with its own identity, its own configuration, its own observability, and its own blast radius. The name — development, staging, production — is not a label for a group of servers; it is a policy boundary. Crossing the boundary changes who can approve a deploy, what credentials are used, what data the workload sees, and what monitoring applies. The discipline of this part of the course is that the boundary is a discipline, not a hostname.

What an environment is

Four properties define an environment in this course:

  • Identity. A distinct OIDC identity, IAM role, or service account. The credentials that deploy to development are not the credentials that deploy to production.
  • Configuration. A distinct configuration surface. The database URL, the feature-flag set, the log level, the replica count — all may differ between environments.
  • Observability. A distinct dashboard, alert route, and log destination. The metrics that page the on-call rotation are not the metrics that pollute a developer’s terminal.
  • Blast radius. A distinct worst-case impact. A bad deploy in development affects one engineer’s laptop; a bad deploy in production affects every customer.
gh environment create production
gh environment create staging
gh environment create development

The commands register three named environments on the repository. Each environment is a separate object in the platform with its own secrets, its own protection rules, and its own deployment history. A workflow can target any of them by name.

flowchart LR
    A["Commit sha"] --> B["Build once"]
    B --> C["Digest sha256:abc"]
    C --> D["Deploy to development"]
    C --> E["Deploy to staging"]
    C --> F["Deploy to production"]
    D --> G["Dev identity"]
    E --> H["Staging identity"]
    F --> I["Production identity"]

The diagram is the model: one build, one digest, three deploys. The bytes never change. The identity, the configuration, and the blast radius change at every boundary.

What crosses the boundary

Two things cross an environment boundary: the artifact and the change record. Everything else stays inside.

  • The artifact crosses. The same container image, the same Terraform plan, the same Ansible playbook bytes go from one environment to the next. The digest is the identity of the artifact and is preserved.
  • The change record crosses. The commit, the pull request, the reviewer, the CI run, the artifact digest — all are recorded in a single chain that links the production deploy back to the commit that produced it.
  • Configuration does not cross. Database URLs, feature-flag values, secrets, replica counts, log levels — all are environment-specific. They are injected at deploy time by the orchestrator, not baked into the artifact.
  • Data does not cross. Production data does not appear in development. Staging data does not appear in production. The data boundary is enforced by identity, by network policy, and by discipline.

The promotion invariant

Promotion is the practice of moving the same artifact from one environment to the next without rebuilding it. The invariant is: the digest that survives staging is the digest that runs in production. If the digest changes between environments, the invariant is broken, and the auditor can no longer answer “what is running in production?” by reading “what ran in staging”.

Three properties make the invariant possible:

  • Build once at the commit. A single pipeline produces a single artifact. Per-environment rebuild pipelines produce per-environment digests; the audit chain fragments into four independent identities.
  • Reference by digest, not by tag. A workflow that references image: app:v3.2.7 references a mutable contract. A workflow that references image: app@sha256:abc... references a content identity. The digest does not change; the tag can.
  • Inject environment config at runtime. The artifact is environment-agnostic; the orchestrator supplies the configuration at deploy time. A build that bakes the production database URL into a layer cannot be promoted to staging without a rebuild.

Production discipline

  1. Environments are named in the platform, not in the workflow. Register every environment with the platform tool (gh environment create) before the first workflow targets it.
  2. The digest is the only identity that crosses boundaries. Tags cross; tags are mutable. Digests cross; digests are not.
  3. Configuration is injected at deploy time. The artifact is environment-agnostic; the orchestrator supplies the configuration per environment.
  4. Data does not cross. Production data does not appear in lower environments. The boundary is enforced by identity, by network policy, and by audit.

Cross-course references

  • This course, Part XLV-03 (Promotion) establishes the digest-crosses-boundaries invariant this lesson extends across environments.
  • This course, Part XLVIII-06 (Environment protection rules) describes the platform-side rules that environments enforce.
  • Terraform for Production Sysadmins — Part XXVIII covers the canonical promotion pattern through Terraform-protected environments.
  • Kubernetes for Production Sysadmins — Part XXXV covers the same model applied to cluster namespaces and GitOps controllers.

Quiz

Knowledge check · 4 questions

  1. Q1. A team runs four pipelines, one per environment, each rebuilding the artifact from the same source commit. The integration tests pass against the staging artifact; production deploys a different artifact with a different digest. What boundary has been broken?

  2. Q2. An environment is a label for a group of servers with similar configuration.

  3. Q3. Name the four properties that define an environment in this course, and identify the property that determines the worst-case impact of a bad deploy.

  4. Q4. Diagnose why a development mistake caused a production outage, and propose the boundary that should have prevented it.

    An engineer pushes a feature-flag change to the development environment. The workflow targets `environment: development`, but the IAM role attached to that environment has cross-environment permissions and can write to the production feature-flag store. The change flips a flag in production. Production traffic changes behaviour within minutes. The audit trail shows the deploy was 'to development', but the production flag store was modified.

Passing score: 75%. Answers are checked in this browser.