Ephemeral Envs with Backstage & Crossplane: A Guide

Ephemeral Envs with Backstage & Crossplane: A Guide

Orchestrating Ephemeral Developer Environments via Backstage and Crossplane

In the modern cloud-native landscape, the “inner loop” of software development often hits a significant bottleneck: environment contention. Traditional static staging environments are frequently “snowflakes”—brittle, inconsistently configured, and prone to drift. As organizations scale, the manual provisioning of cloud resources becomes a ticket-driven nightmare for Platform Engineers and a source of frustration for developers.

The solution lies in Ephemeral Developer Environments (EDEs). These are on-demand, short-lived, and isolated environments that mirror production. However, building these requires more than just a script; it requires a robust Internal Developer Portal (IDP) and a powerful Control Plane. This article explores the technical orchestration of EDEs using Backstage as the interface and Crossplane as the infrastructure execution engine.


Technical Overview: The Brain and the Body

To build a seamless self-service experience, we must decouple the intent (what the developer wants) from the implementation (how the cloud is configured).

Backstage: The Interface (The Brain)

Backstage serves as the entry point. It provides Software Templates (Scaffolding) that abstract away the complexity of YAML manifests. Developers interact with a UI to request an environment, providing only high-level parameters like region, database_size, or expiration_ttl.

Crossplane: The Control Plane (The Body)

Crossplane extends Kubernetes into a Universal Control Plane. Unlike traditional IaC tools (like Terraform) which are execution-based and state-file dependent, Crossplane is API-driven and continuously reconciled. It uses Custom Resource Definitions (CRDs) to represent cloud resources (RDS, S3, EKS).

The Architecture: A GitOps-Mediated Flow

  1. Request: Developer fills out a Backstage Template.
  2. Scaffold: Backstage generates a Kubernetes manifest representing a high-level “Composite Resource” (XR).
  3. Commit: Backstage pushes this manifest to a Git repository.
  4. Sync: A GitOps controller (ArgoCD or Flux) pulls the manifest into a Kubernetes cluster where Crossplane is running.
  5. Provision: Crossplane detects the new object, looks up the defined Composition, and calls the Cloud APIs (AWS/GCP/Azure) to provision resources.
  6. Reconcile: Crossplane continuously monitors the cloud resources, fixing any manual drift automatically.

Implementation Details

1. Defining the Infrastructure Abstraction (Crossplane)

First, the Platform Team defines a CompositeResourceDefinition (XRD). This acts as the “API” for the environment.

# composite-resource-definition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xdeveloperenvironments.internal.platform.io
spec:
  group: internal.platform.io
  names:
    kind: XDeveloperEnvironment
    plural: xdeveloperenvironments
  versions:
  - name: v1alpha1
    served: true
    referenceable: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              dbSize:
                type: string
                enum: [small, medium, large]
              region:
                type: string
              ttl:
                type: integer
                description: "Hours until environment is destroyed"
            required: [dbSize, region]

2. The Composition (The Blueprint)

The Platform Team then maps this abstract request to actual cloud resources using a Composition.

# composition.yaml
apiVersion: path.crossplane.io/v1
kind: Composition
metadata:
  name: aws-dev-env-standard
spec:
  compositeTypeRef:
    apiVersion: internal.platform.io/v1alpha1
    kind: XDeveloperEnvironment
  resources:
    - name: ephemeral-database
      base:
        apiVersion: database.aws.upbound.io/v1beta1
        kind: Instance
        spec:
          forProvider:
            engine: postgres
            instanceClass: db.t3.micro # Map 'small' from XRD here
            publiclyAccessible: false
    - name: ephemeral-bucket
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-1

3. Backstage Software Template

The Backstage template provides the UI form that generates the manifest for the XDeveloperEnvironment.

# backstage-template.yaml
apiVersion: scaffold.backstage.io/v1beta3
kind: Template
metadata:
  name: create-ephemeral-env
  title: New Ephemeral Environment
spec:
  parameters:
    - title: Environment Details
      properties:
        envName:
          type: string
          title: Environment Name
        dbSize:
          type: string
          enum: [small, medium, large]
        region:
          type: string
          default: us-east-1
  steps:
    - id: fetch-base
      name: Fetch Template
      action: fetch:template
      input:
        url: ./content
        values:
          envName: ${{ parameters.envName }}
          dbSize: ${{ parameters.dbSize }}
    - id: publish
      name: Publish to Git
      action: publish:github
      input:
        allowedHosts: ['github.com']
        repoUrl: 'github.com/org/ephemeral-envs'
        repoContentsUrl: ${{ steps['fetch-base'].output.remoteUrl }}

Best Practices and Considerations

Time-To-Live (TTL) and Auto-Cleanup

The “ephemeral” nature is key to cost control.
* Implementation: Use a specialized controller or a Kubernetes CronJob that monitors the XDeveloperEnvironment objects. If the creationTimestamp + ttl exceeds the current time, the job deletes the manifest from Git or directly from the cluster.
* Crossplane Deletion Policy: Ensure deletionPolicy: Delete is set in your compositions so that deleting the Kubernetes object triggers the immediate destruction of cloud resources.

Drift Detection and Reconciliation

Unlike Terraform, Crossplane checks the state of the cloud every ~60 seconds. If a developer manually changes an RDS instance size via the AWS Console, Crossplane will revert it to the state defined in the Backstage-generated manifest. This ensures environment consistency.

Security and Governance

  • OIDC and ProviderConfigs: Use IAM Roles for Service Accounts (IRSA) in EKS to grant Crossplane permissions. Never hardcode access keys.
  • Policy as Code: Use Kyverno or OPA (Open Policy Agent) to validate the XDeveloperEnvironment manifests. For example, you can block any environment request that specifies a large database if the user is not in the senior-dev group.
  • Secret Management: Use External Secrets Operator to sync credentials created by Crossplane (like DB passwords) into the application’s namespace.

Real-World Use Cases

1. AI/ML Experimentation

ML Engineers often need heavy-duty GPU instances (e.g., NVIDIA A100s) for short training bursts. By using Backstage, they can spin up a dedicated EKS node group with specialized hardware, run their training job, and have Crossplane tear it down an hour later, saving thousands in idle cloud costs.

2. Pull Request Previews

Integrate the Backstage API into your CI pipeline. When a PR is opened, the CI triggers the creation of an XDeveloperEnvironment. The resulting cloud URL is posted back to the PR as a comment, allowing reviewers to interact with the live code changes.

Performance Metrics

Organizations adopting this IDP + Control Plane pattern typically see:
* Lead Time Reduction: Environment provisioning time drops from days (ticket-based) to < 10 minutes (self-service).
* Cost Savings: 30–50% reduction in non-production cloud spend due to aggressive TTL enforcement.
* Developer Satisfaction: Significant reduction in cognitive load; developers no longer need to learn HCL (HashiCorp Configuration Language) or navigate cloud consoles.


Conclusion

Orchestrating ephemeral environments via Backstage and Crossplane transforms infrastructure from a static constraint into a dynamic, versioned, and self-healing resource. By shifting to Infrastructure as Data, platform teams can provide “Golden Paths” that empower developers while maintaining strict governance and cost control.

Key Takeaways:
* Backstage is the UI for developer intent.
* Crossplane is the engine that reconciles that intent with reality.
* Abstraction (XRDs) allows platform teams to hide cloud complexity.
* TTL Management is non-negotiable for cost efficiency in ephemeral setups.

By treating the cloud as a programmable extension of the Kubernetes API, organizations can finally realize the promise of true developer self-service.


Discover more from Zechariah's Tech Journal

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply