Skip to content
ย 
ย 

Latest commit

ย 

History

109 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Platform Engineering | BACK Stack

A ready-to-use environment for modern platform engineering experimentation, combining (B)ackstage, (A)rgoCD, (C)rossplane, and (K)yverno! ๐Ÿš€

Interfaces and Capabilities of a Development Platform
Interfaces and Capabilities of a Development Platform. Source: CLOUD NATIVE COMPUTING FOUNDATION. Platforms whitepaper. Available at: https://tag-app-delivery.cncf.io/whitepapers/platforms/#capabilities-of-platforms.

๐Ÿšง Under construction ๐Ÿšง

Summary

Motivation โœจ

Platform Engineering requires integrating multiple tools to provide developers with a seamless and efficient experience. Building an Internal Developer Platform (IDP) involves solutions for automation, infrastructure provisioning, access control, observability, and continuous delivery workflows, which makes it challenging for both beginners and experienced teams.

Tools like Backstage, Crossplane, and ArgoCD are commonly used to create a unified developer experience, but experimenting with and understanding how they work together can be hard without a properly configured environment. Each technology brings its own concepts and abstraction layers, making the learning and implementation process fragmented.

This project was created to meet the need for an easy-to-run local environment, enabling quick experimentation with the core technologies involved in platform engineering. The goal is to provide a functional and reproducible stack, reducing initial complexity and enabling hands-on exploration before deploying these solutions in a production setting.

With this stack, you can:

  • โœ… Quickly test integration between Backstage, Crossplane, and ArgoCD.
  • โœ… Simulate an IDP experience in a local setup.
  • โœ… Understand the challenges and benefits of each tool.
  • โœ… Create and modify infrastructure compositions using GitOps.

If you're interested in platform engineering and want to explore how these tools fit together, this repository is a great place to start! ๐Ÿš€

Stack

This repository brings together essential tools to build and experiment with a local Internal Developer Platform (IDP). Below is a brief description of each component:

  • Backstage: An open-source developer portal created by Spotify, designed to unify tools, services, and documentation into a single interface. It provides a service catalog, allowing teams to organize and discover APIs, infrastructure, and documentation centrally, promoting standardization and development efficiency.

  • ArgoCD: A GitOps continuous delivery controller for Kubernetes, responsible for managing and syncing applications defined via Git-based manifests.

  • Crossplane: A Kubernetes-native infrastructure provisioning tool that enables declarative cloud and on-prem resource management via Compositions.

  • Kyverno: A policy engine for Kubernetes that enables enforcement and validation of compliance and security rules in clusters.

  • LocalStack: A fully functional local AWS cloud emulator that enables developers to test and build applications interacting with AWS services without needing a real AWS account.

  • Crossview: A web-based UI for visualizing and managing Crossplane resources. It provides an intuitive interface to explore XRDs, Compositions, and composite resources, helping users understand the control plane structure and accelerate troubleshooting.

  • Helm: A package manager for Kubernetes that simplifies deploying complex applications using reusable charts.

  • kind (Kubernetes in Docker): A tool for running local Kubernetes clusters using Docker containers, ideal for testing and development.

  • kubectl: The official Kubernetes command-line tool (CLI) for interacting with clusters, applying configurations, and managing resources.

Prerequisites

Make sure the following dependencies are installed before running any commands:

  • kind (version v0.27.0 or higher);
  • kubectl (version v1.32.2 or higher);
  • argocd (version v2.14.2 or higher);
  • helm (version v3.17.1 or higher);
  • yq (version v4.45.1 or higher);
  • Docker (version 27.4.0 or higher);
  • skaffold (version v2.24.0 or higher) โ€” optional, only needed for the Backstage dev loop described below.

โš ๏ธ Installation of these basic tools is not covered here as it varies by operating system. The following scripts assume you have each one properly set up.

Before proceeding, make sure you have also completed the following steps:

  1. Fork this repository to your GitHub account.
  2. Clone your fork locally:
    git clone https://github.com/<your-username>/<repository-name>.git
    cd <repository-name>
  3. Create a .env file at the root of the project based on the provided .env.example:
    cp .env.example .env
  4. Generate a GitHub Personal Access Token with full repo permissions by visiting https://github.com/settings/tokens/new. https://github.com/settings/tokens/new
  5. Update the .env file with your generated token, replacing the "placeholder" value.

๐Ÿ’ก The GitHub token will be used to open pull requests in the repository and to read the catalog file for loading into Backstage.

Up & Running

This project uses a Makefile to simplify environment setup and teardown. Follow the steps below to get started.

If you don't have the make command in your environment, install it according to your operating system:

Ubuntu/Debian
sudo apt update && sudo apt install -y make

Verify installation:

make --version

Install build tools if needed:

sudo apt update && sudo apt install -y build-essential
Fedora
sudo dnf install -y make

Verify installation:

make --version

Install build tools if needed:

sudo dnf groupinstall -y "Development Tools"
Arch Linux
sudo pacman -Syu make

Verify installation:

make --version

Install build tools if needed:

sudo pacman -Syu base-devel
macOS (via Homebrew)
brew install make

Verify installation:

make --version

Install Xcode development tools if needed:

xcode-select --install
Windows (via MSYS2)
  1. Download and install MSYS2.
  2. Open the MSYS2 terminal and run:
pacman -S make

Verify installation:

make --version

For a complete development environment:

pacman -S base-devel

To set up the environment, run:

make up

This command will:

  • Check if required dependencies are installed.
  • Create a Kubernetes cluster named platform (if it does not already exist).
  • Run bootstrap scripts for LocalStack, Crossplane, Crossview, and ArgoCD.

To tear down the environment, run:

make down

This command will:

  • Check if required dependencies are installed.
  • Delete the Kubernetes platform cluster if it exists.

Backstage Dev Loop (optional)

make up builds the Backstage image once and then leaves it alone. If you are editing Backstage itself โ€” plugins, app-config.yaml, the catalog โ€” skaffold gives you a rebuild-and-redeploy loop against the same cluster:

make dev-backstage

It watches backstage/, rebuilds the image on every change, side-loads it into the platform kind cluster, rolls the pod, streams the container logs, and holds the port-forward on http://localhost:3000. Ctrl-C stops the loop and leaves the last build running.

Two things to know before the first run:

  • Commit and push argocd/apps/backstage/app.yaml first. Skaffold deploys the Deployment with a content-addressed image tag, which diffs against the backstage:latest recorded in Git. The ignoreDifferences rule in that file tells Argo CD to leave that one field alone; without it selfHeal reverts every redeploy within seconds. Argo CD reads Application objects from Git, so editing the file locally is not enough.
  • A real sync resets the image. backstage-app syncs with Replace=true, so anything you later push under .bootstrap/backstage/manifests/ replaces the Deployment wholesale and restores backstage:latest. Just re-run make dev-backstage.

The Skaffold config (skaffold.yaml) deliberately covers Backstage only. Cluster creation, the argocd CLI bootstrap, secret templating from .env, and the Crossplane/Kyverno readiness polling have no Skaffold equivalent and stay in make up and .bootstrap/*/up.sh.

Progressive Delivery (Kargo)

Kargo watches the podinfo image and walks each new tag through nine zones โ€” three environments spread over three availability zones each, one namespace standing in for each cluster:

warehouse (new podinfo tag)
    โ”‚
    โ–ผ
  dev1-0  canary โ”€โ”€โ”ฌโ”€โ”€โ–บ dev1-1
                   โ””โ”€โ”€โ–บ dev1-2
    โ‹ฎ  all three dev zones verified
    โ–ผ
  test1-0 canary โ”€โ”€โ”ฌโ”€โ”€โ–บ test1-1
                   โ””โ”€โ”€โ–บ test1-2
    โ‹ฎ  all three test zones verified
    โ–ผ
  prod1-0 canary โ”€โ”€โ”ฌโ”€โ”€โ–บ prod1-1
                   โ””โ”€โ”€โ–บ prod1-2

Zone 0 of each environment is its canary: Freight lands there first and the two sibling zones promote in parallel only after it verifies. The next environment opens only once all three zones of the previous one have verified โ€” that is sources.availabilityStrategy: All on the canary Stage; Kargo's default would let a single verified zone open the gate.

Verification is a real check, not a formality: after each promotion an Argo Rollouts AnalysisTemplate curls podinfo's /healthz through the Service that Crossplane composed, three times, in the zone that was just promoted. A failure stops the rollout there instead of reporting it afterwards.

Rendered manifests, not templated ones

A promotion does not edit a manifest in main. It renders one and commits the result to that zone's own branch:

Branch Holds
main The Helm chart and the values chain โ€” the source.
stage/<zone> (ร—9) manifests.yaml, fully rendered โ€” the desired state.

Each Argo CD Application tracks stage/<zone> rather than a path in main, so nothing re-renders at sync time and git show stage/prod1-0:manifests.yaml is an honest answer to "what is running in that zone?". The promotion steps are in kargo/stages/<zone>.yaml: clone main and the stage branch, git-clear the branch, helm-template into it, commit, push, then wait for Argo CD to report the zone healthy before the analysis starts.

The values chain

delivery/ holds the source, and values are layered narrowest-last:

delivery/
โ”œโ”€โ”€ chart/                        # 1. chart defaults โ€” values.yaml
โ””โ”€โ”€ envs/
    โ”œโ”€โ”€ dev/
    โ”‚   โ”œโ”€โ”€ values-dev.yaml       # 2. environment policy (replicas: 1)
    โ”‚   โ”œโ”€โ”€ values-dev1-0.yaml    # 3. one zone only (identity, overrides)
    โ”‚   โ”œโ”€โ”€ values-dev1-1.yaml
    โ”‚   โ””โ”€โ”€ values-dev1-2.yaml
    โ”œโ”€โ”€ test/                     #    values-test.yaml + values-test1-{0,1,2}.yaml
    โ””โ”€โ”€ prod/                     #    values-prod.yaml sets replicas: 2

Each file is named for exactly what it configures, so a -f chain reads as the scope it applies: environment, then zone.

The promoted image tag appears in none of them โ€” it comes from Kargo through setValues at render time, so no file in main can claim a version that is not actually deployed. Render any zone exactly the way the pipeline does with:

helm template podinfo ./delivery/chart --namespace prod1-0 \
  -f ./delivery/envs/prod/values-prod.yaml \
  -f ./delivery/envs/prod/values-prod1-0.yaml

The nine stage/* branches are seeded by .bootstrap/kargo/up.sh on first run, which needs GITHUB_TOKEN in .env to have write access to your fork. Branches that already exist are left alone.

Troubleshooting

If you encounter issues, ensure that:

  • All required binaries are installed and available in your system PATH.
  • The kind clusters are running before applying any kubectl instructions.

For additional help, refer to the documentation links in the prerequisites section.

Accessing Applications

Applications are exposed via nohup + kubectl port-forward.

Application Address Notes
Backstage http://localhost:3000 Enter as a Guest User.
Argo CD http://localhost:8080 Username: admin
Password: 12345678
Crossview http://localhost:3001 -
Kargo https://localhost:3002 Username: admin
Password: admin
Serves TLS with a self-signed cert.
Localstack http://localhost:4566 Manage it via: https://app.localstack.cloud/instances

Architecture

Below is a high-level architecture diagram showing how the components interact:

Architecture

Roadmap ๐Ÿšง

This section outlines upcoming improvements and planned changes for this project:

  • Reduce the responsibility of the .bootstrap/**/up.sh scripts: shift tool installation and configuration to ArgoCD so that it manages not only Crossplane resources but also the cluster setup itself โ€” making the environment closer to real-world GitOps practices.

  • Improve the Kyverno GitHub Action: update the CI pipeline to apply only the policies related to the resources changed in a given Pull Request.

  • Evaluate the use of the TeraSky Kubernetes Ingestor plugin for Backstage (link): adopted at v4.0.0, replacing the hand-written CrossplaneEntityProvider. It understands Crossplane v2 natively โ€” it branches on the XRD's spec.scope, so a Namespaced XRD has its XR ingested directly rather than through the claim v2 no longer has โ€” and it generates a scaffolder template and an API entity per XRD, so neither has to be hand-maintained. No ingestion loop was observed on this version; documentation is still thin, so two behaviours worth recording:

    • kubernetesIngestor.components.enabled: false does not filter workloads. It short-circuits the whole entity provider and removes everything it had already tracked, which silently stops Crossplane XRs being ingested too. Exclude the platform's own namespaces with components.excludedNamespaces instead.
    • The API entities it generates hardcode system: kubernetes-auto-ingested โ€” the value is a string literal in the plugin, not derived from mappings.systemModel โ€” so that System has to exist in the catalog or every generated entity reports a dangling relation.
  • Evaluate the TeraSky Crossplane Resources plugin for Backstage (link): adopted, together with the Kyverno policy-reports plugin and RoadieHQ's Argo CD plugin. Its *Selector components resolve the v1 or v2 implementation from the entity itself, so the resource table and graph work for legacy claims and v2 namespaced XRs alike. The tabs are gated on isCrossplaneAvailable, so they only appear for Crossplane entities. The dependency on the Kubernetes Ingestor is real โ€” the ingestor supplies the annotations these components read โ€” and is satisfied by the item above.

How to Contribute

I welcome contributions! ๐ŸŽ‰

Before starting, please take a moment to review the Contributing Guidelines.

About

A ready-made environment for modern platform engineering experimentation, combining Backstage, ArgoCD, Crossplane and Kyverno with GitOps practices! The BACK Stack! ๐Ÿš€

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages