diff --git a/docs/golden-path/deployment/001-docker.md b/docs/golden-path/deployment/001-docker.md new file mode 100644 index 0000000000..e93106ecf3 --- /dev/null +++ b/docs/golden-path/deployment/001-docker.md @@ -0,0 +1,87 @@ +--- +id: docker +sidebar_label: 001 - Building the Docker image +title: Building the Docker image +description: How to build your Backstage app into a deployable Docker image +--- + +Audience: Developers and Admins + +## Summary + +Every production deployment of Backstage starts with a Docker image. The image +bundles both the frontend and backend into a single artifact that you can deploy +anywhere containers run. + +By the end of this page, you will have a Docker image ready to push to a +container registry. + +## What is in the Docker image? + +When you created your app with `@backstage/create-app`, a `Dockerfile` was +generated at `packages/backend/Dockerfile`. The build process layers both the +frontend and backend into a single image: + +1. The **backend** is compiled and bundled into `packages/backend/dist/`. +2. The **frontend** is built and served by the + `@backstage/plugin-app-backend` plugin, which is included in the backend + by default. +3. Production dependencies are installed, and the result is packaged into a + slim Node.js image. + +The image runs as a non-root `node` user and sets `NODE_ENV=production`. + +## Building the image + +The recommended approach is a **host build**, where compilation happens on +your machine (or CI runner) and Docker only packages the result. This is faster +and produces better caching behavior. + +From the root of your repository: + +```shell +yarn install +yarn tsc +yarn build:backend +``` + +Then build the Docker image: + +```shell +docker image build . -f packages/backend/Dockerfile --tag backstage +``` + +To verify it works locally: + +```shell +docker run -it -p 7007:7007 backstage +``` + +You should see logs in your terminal and be able to open `http://localhost:7007` +in your browser. + +:::tip Troubleshooting + +If you run into build issues, two Docker flags can help: + +- `--progress=plain` shows verbose output instead of folded log sections. +- `--no-cache` rebuilds all layers from scratch. + +```shell +docker image build . -f packages/backend/Dockerfile --tag backstage --progress=plain --no-cache +``` + +::: + +## Further reading + +For a full multi-stage Docker build (where everything happens inside Docker) +or for deploying the frontend separately, see the +[Building a Docker image](../../deployment/docker.md) reference documentation. + +## Next steps + +Before deploying, you need to set up two production dependencies: a database and +an authentication provider. + +- [Setting up a production database](./002-database.md) diff --git a/docs/golden-path/deployment/002-database.md b/docs/golden-path/deployment/002-database.md new file mode 100644 index 0000000000..db6fd76da1 --- /dev/null +++ b/docs/golden-path/deployment/002-database.md @@ -0,0 +1,103 @@ +--- +id: database +sidebar_label: 002 - Database +title: Setting up a production database +description: How to configure PostgreSQL for your Backstage production deployment +--- + +Audience: Admins + +## Summary + +During local development, Backstage uses SQLite as a fast in-memory database. +SQLite does not persist data across restarts and is not designed for +multi-instance deployments, so you need a dedicated database for production. + +By the end of this page, you will have PostgreSQL configured as your Backstage +database. + +## Why PostgreSQL? + +PostgreSQL is the recommended production database for Backstage. It handles +concurrent connections well, supports the query patterns that Backstage plugins +use, and is available as a managed service from every major cloud provider. + +Some options for running PostgreSQL: + +- **Managed services**: Amazon RDS, Google Cloud SQL, Azure Database for + PostgreSQL, or similar offerings. +- **Self-hosted**: Running PostgreSQL in a container or on a dedicated server. +- **In Kubernetes**: Deploying PostgreSQL alongside Backstage (useful for + getting started, but managed services are preferred for production). + +## Configuring Backstage to use PostgreSQL + +Open your `app-config.production.yaml` and add the database configuration: + +```yaml title="app-config.production.yaml" +backend: + database: + client: pg + connection: + host: ${POSTGRES_HOST} + port: ${POSTGRES_PORT} + user: ${POSTGRES_USER} + password: ${POSTGRES_PASSWORD} +``` + +The `${...}` syntax references environment variables, which keeps secrets out +of your configuration files. Set these variables in your deployment environment. + +:::caution + +Avoid hardcoding database credentials in configuration files. Use environment +variables or a secrets manager provided by your deployment platform. + +::: + +### Optional: SSL connections + +If your database provider requires SSL (most managed services do), add the +SSL configuration: + +```yaml title="app-config.production.yaml" +backend: + database: + client: pg + connection: + host: ${POSTGRES_HOST} + port: ${POSTGRES_PORT} + user: ${POSTGRES_USER} + password: ${POSTGRES_PASSWORD} + ssl: + require: true + rejectUnauthorized: true +``` + +If your provider uses a custom certificate authority, you can reference the +CA certificate file: + +```yaml +ssl: + ca: + $file: /path/to/ca/server.crt +``` + +## How Backstage uses the database + +Each plugin gets its own isolated database schema. Migrations run automatically +when the backend starts, so you do not need to run any manual migration steps. +The database coordinates state and work distribution between instances, which +is what makes horizontal scaling possible later on. + +## Further reading + +For step-by-step PostgreSQL installation instructions and cloud-specific +setup guides, see the [Database configuration guide](../../getting-started/config/database.md). + +## Next steps + +With the database in place, the next step is to replace the guest login with +a real authentication provider. + +- [Configuring authentication](./003-authentication.md) diff --git a/docs/golden-path/deployment/003-authentication.md b/docs/golden-path/deployment/003-authentication.md new file mode 100644 index 0000000000..110e2e914a --- /dev/null +++ b/docs/golden-path/deployment/003-authentication.md @@ -0,0 +1,90 @@ +--- +id: authentication +sidebar_label: 003 - Authentication +title: Configuring authentication +description: How to set up a production authentication provider for Backstage +--- + +Audience: Developers and Admins + +## Summary + +By default, Backstage uses a guest authentication provider that lets anyone +log in without credentials. This is convenient for local development but +creates a security risk when deployed to production. Before deploying, you +should configure a real authentication provider. + +By the end of this page, you will understand what needs to change and where +to find the setup instructions for your chosen provider. + +## Why replace guest authentication? + +The guest provider is explicitly not intended for containerized or production +environments. With guest auth enabled, any user who can reach your Backstage +instance shares the same identity and has the same level of access. Replacing +it is one of the most important steps before going to production. + +:::danger + +Deploying Backstage with the guest authentication provider exposes your +instance to unauthorized access. Configure a real provider before deploying. + +::: + +## Choosing an authentication provider + +Backstage supports a wide range of authentication providers. GitHub is a +common choice since most developers already have accounts, but you should +pick whatever your organization already uses for single sign-on. + +Some popular options: + +| Provider | Good fit when... | +| :------------------- | :------------------------------------------------ | +| GitHub | Your team uses GitHub and you want a quick setup. | +| Microsoft / Azure AD | Your company uses Microsoft Entra ID (Azure AD). | +| Google | Your company uses Google Workspace. | +| Okta | You use Okta as your identity provider. | +| OIDC | You have a generic OpenID Connect provider. | +| OAuth2 Proxy | You already use an authenticating reverse proxy. | + +The full list of providers and their configuration is available in the +[Authentication documentation](../../auth/index.md). + +## What the setup involves + +Regardless of which provider you choose, the setup follows the same pattern: + +1. **Create an OAuth application** (or equivalent) with your identity + provider. You will get a client ID and client secret. +2. **Add the provider configuration** to `app-config.yaml` with the + credentials, typically using environment variables for secrets. +3. **Install the backend auth module** for your chosen provider in + `packages/backend`. +4. **Configure a sign-in resolver** that maps the authenticated user identity + to a Backstage catalog user entity. +5. **Update the frontend** to show the correct sign-in page. + +The [Authentication getting started guide](../../getting-started/config/authentication.md) +walks through this process step by step using GitHub as the example provider. + +## Production configuration + +Once authentication is configured, make sure that the guest provider is +disabled in your production config: + +```yaml title="app-config.production.yaml" +auth: + providers: + guest: null +``` + +This ensures that even if the guest provider is configured in your base +`app-config.yaml` for local development, it is explicitly disabled in +production. + +## Next steps + +With both a database and authentication configured, you are ready to deploy. + +- [Deploying to production](./004-deploying.md) diff --git a/docs/golden-path/deployment/004-deploying.md b/docs/golden-path/deployment/004-deploying.md new file mode 100644 index 0000000000..7ef0f4545a --- /dev/null +++ b/docs/golden-path/deployment/004-deploying.md @@ -0,0 +1,110 @@ +--- +id: deploying +sidebar_label: 004 - Deploying +title: Deploying to production +description: How to deploy your Backstage instance to production +--- + +Audience: Admins + +## Summary + +You have a Docker image, a database, and authentication configured. Now it +is time to deploy. The _best_ way to deploy Backstage is _the same way_ you +deploy other software at your organization. Backstage is designed to run as +a stateless Node.js application backed by an external PostgreSQL database, +so it fits into most existing deployment pipelines without special tooling. + +This page describes what every Backstage deployment needs, regardless of +platform, and points to the reference guides for specific targets. + +## What every deployment needs + +Whichever platform you choose, the deployment will need to take care of the +following concerns: + +- **A container image** built from your repository and pushed to a registry + your runtime can pull from. The image you built in + [Building the Docker image](./001-docker.md) is the artifact that gets + deployed. +- **Configuration and secrets** delivered to the running container as + environment variables or mounted files. This includes database + credentials, auth provider client secrets, and any integration tokens. +- **A reachable PostgreSQL database** that the running instance can connect + to using the credentials from the previous step. See + [Configuring the database](./002-database.md) for details. +- **A network entry point** — typically an ingress, load balancer, or + reverse proxy — that exposes the backend on port `7007` to your users + over HTTPS. +- **A health-checked runtime** that can restart the container if it stops + responding and roll out new versions when you publish a new image. +- **`app.baseUrl` and `backend.baseUrl`** in your + `app-config.production.yaml` set to the public URL where users will + access Backstage. Auth providers and the frontend rely on these matching + the actual entry point: + + ```yaml title="app-config.production.yaml" + app: + baseUrl: https://backstage.example.com + backend: + baseUrl: https://backstage.example.com + listen: + port: 7007 + ``` + +## Choosing a deployment target + +Backstage runs anywhere a Node.js container can run. Pick the option that +matches what your organization already operates — you do not need to adopt +new infrastructure to run Backstage. + +| Target | Good fit when... | +| :----------------------- | :---------------------------------------------------------------------- | +| Kubernetes | Your organization already runs services on Kubernetes. | +| Amazon ECS / Fargate | You are on AWS and prefer managed container scheduling. | +| Google Cloud Run | You want a fully managed, request-driven container runtime on GCP. | +| Azure Container Apps | You are on Azure and want a managed container platform. | +| A traditional VM or PaaS | You prefer running the Node.js process directly behind a reverse proxy. | +| Docker Compose | You are running a small installation or proof of concept. | + +Backstage maintains a reference guide for the Kubernetes path in +[Deploying with Kubernetes](../../deployment/k8s.md), which walks through +namespaces, secrets, the deployment, the service, and connecting to +PostgreSQL inside the cluster. + +For other platforms, the +[community-contributed deployment guides](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/) +in the Backstage repository cover targets such as ECS, Cloud Run, and +Docker Compose, and the [deployment overview](../../deployment/index.md) +explains the underlying model that all of these guides share. + +## Operational concerns + +A few operational details apply to every deployment and are worth getting +right before opening Backstage up to your users: + +- **Run multiple replicas** behind your load balancer. Backstage is + stateless, so multiple instances can serve traffic against the same + PostgreSQL database. We cover this further in + [Scaling Backstage](./007-scaling.md). +- **Store secrets securely.** Container platforms typically offer a + secrets primitive — Kubernetes Secrets, AWS Secrets Manager, GCP Secret + Manager, Azure Key Vault, and so on. Reference these from your + configuration with environment variables rather than committing + credentials. +- **Enable health checks.** Wire your platform's readiness and liveness + probes to the Backstage health endpoints so unhealthy instances are + taken out of rotation and restarted automatically. +- **Run behind HTTPS.** Terminate TLS at your ingress, load balancer, or + reverse proxy and make sure the public URL is what `app.baseUrl` and + `backend.baseUrl` are set to. + +If you need to run Backstage behind a corporate proxy, see the +[corporate proxy guide](../../tutorials/corporate-proxy.md). + +## Next steps + +Your Backstage instance is deployed. Next, let's look at how to manage +configuration effectively across environments. + +- [Config-first development](./005-config-first.md) diff --git a/docs/golden-path/deployment/005-config-first.md b/docs/golden-path/deployment/005-config-first.md new file mode 100644 index 0000000000..1725c3f610 --- /dev/null +++ b/docs/golden-path/deployment/005-config-first.md @@ -0,0 +1,92 @@ +--- +id: config-first +sidebar_label: 005 - Configuration management +title: Config-first development +description: Managing Backstage configuration across environments +--- + +Audience: Developers and Admins + +## Summary + +One of the things that makes Backstage easier to operate over time is treating +configuration as the primary way to control application behavior. Instead of +writing custom code for every change, many behaviors can be toggled, adjusted, +or extended through configuration files. + +By the end of this page, you will understand how Backstage configuration +layering works and how to manage it across environments. + +## How configuration layering works + +Backstage loads configuration from multiple `app-config*.yaml` files and +merges them together. Files loaded later override values from earlier files. +The Docker image built in the [first step](./001-docker.md) starts with this +command: + +``` +node packages/backend --config app-config.yaml --config app-config.production.yaml +``` + +This means `app-config.production.yaml` overrides any values set in +`app-config.yaml`. You can use this pattern to keep your base config for +local development and override only what changes in production. + +### Common configuration split + +| File | Purpose | +| :--------------------------- | :------------------------------------------------- | +| `app-config.yaml` | Base configuration shared across all environments. | +| `app-config.local.yaml` | Local overrides, not committed to source control. | +| `app-config.production.yaml` | Production-specific overrides. | + +## Environment variables in config + +Use the `${VAR_NAME}` syntax to reference environment variables. This is +the recommended approach for secrets and values that differ between +environments: + +```yaml title="app-config.production.yaml" +backend: + database: + client: pg + connection: + host: ${POSTGRES_HOST} + port: ${POSTGRES_PORT} + user: ${POSTGRES_USER} + password: ${POSTGRES_PASSWORD} +``` + +This keeps secrets out of your repository and lets the same Docker image be +used across environments by changing the variables at deploy time. + +## What to configure vs. what to code + +A good rule of thumb: if a change affects _where_ something connects, _how_ +it authenticates, or _which_ features are enabled, it belongs in configuration. +If it changes _what_ a feature does, it belongs in code. + +Examples of config-driven behavior: + +- Database connection details. +- Authentication provider selection and credentials. +- Catalog locations and entity providers. +- Integration tokens (GitHub, GitLab, etc.). +- TechDocs storage backend (local, S3, GCS, Azure). +- Proxy endpoints for external services. + +Making configuration your primary lever for environment differences simplifies +your CI/CD pipeline. You build one Docker image and deploy it everywhere, +varying only the config files and environment variables. + +## Further reading + +For the full configuration reference, see the +[Configuration documentation](../../conf/index.md). + +## Next steps + +With your deployment running and configuration managed, you should set up +monitoring to keep it healthy. + +- [Monitoring your deployment](./006-monitoring.md) diff --git a/docs/golden-path/deployment/006-monitoring.md b/docs/golden-path/deployment/006-monitoring.md new file mode 100644 index 0000000000..d2cd097e60 --- /dev/null +++ b/docs/golden-path/deployment/006-monitoring.md @@ -0,0 +1,85 @@ +--- +id: monitoring +sidebar_label: 006 - Monitoring +title: Monitoring your deployment +description: Setting up OpenTelemetry and frontend analytics for your Backstage deployment +--- + +Audience: Admins + +## Summary + +A production Backstage deployment needs monitoring to track health, diagnose +issues, and understand usage patterns. Backstage provides built-in support +for OpenTelemetry on the backend and an Analytics API on the frontend. + +By the end of this page, you will know how to set up both. + +## Backend monitoring with OpenTelemetry + +Backstage uses [OpenTelemetry](https://opentelemetry.io/) to report metrics +and traces. The setup involves installing a few OpenTelemetry packages, +creating an instrumentation file, and loading it before the backend starts. + +Follow the [Setup OpenTelemetry tutorial](../../tutorials/setup-opentelemetry.md) +for step-by-step instructions on installing dependencies, configuring +exporters (Prometheus for metrics, OTLP for traces), and wiring everything +into your backend. + +### Key metrics to monitor + +Backstage plugins emit metrics that give you insight into system health. +Common examples include: + +- `catalog_entities_count` - Total number of entities in the catalog. +- `catalog.processed.entities.count` - Number of entities processed. +- `catalog.processing.duration` - Time spent processing entities. +- `scaffolder.task.count` - Number of scaffolder tasks run. +- `scaffolder.task.duration` - Time taken by scaffolder tasks. + +The specific metric names may vary depending on which plugins you have +installed and their versions. These examples help you set up alerts for +things like processing backlogs or unusually slow scaffolder runs. + +### Health checks + +Backstage provides built-in health check endpoints that you can use for +liveness and readiness probes in Kubernetes or other orchestrators: + +- `/.backstage/health/v1/readiness` - Returns healthy when the backend is + ready to serve traffic. +- `/.backstage/health/v1/liveness` - Returns healthy when the backend + process is alive. + +## Frontend analytics + +Backstage provides an Analytics API for tracking user behavior on the +frontend. This is useful for understanding which plugins get the most use +and measuring the return on your Backstage investment. + +Several analytics tools are supported through community plugins: + +- Google Analytics 4 +- New Relic Browser +- Matomo + +See the [Analytics documentation](../../frontend-system/building-plugins/08-analytics.md) +for setup instructions. + +For frontend error reporting, consider integrating with a service like +Sentry, CloudWatch RUM, or Cloudflare RUM to catch and diagnose client-side +errors. + +## Logging + +The backend emits structured JSON logs on stdout by default. These logs +include fields like `service`, `plugin`, `level`, and `message` that make +them easy to parse with log aggregation tools (Elasticsearch, Datadog, +Splunk, etc.). + +## Next steps + +As more users adopt your Backstage instance, you may need to scale the +deployment. + +- [Scaling your deployment](./007-scaling.md) diff --git a/docs/golden-path/deployment/007-scaling.md b/docs/golden-path/deployment/007-scaling.md new file mode 100644 index 0000000000..d82321df54 --- /dev/null +++ b/docs/golden-path/deployment/007-scaling.md @@ -0,0 +1,96 @@ +--- +id: scaling +sidebar_label: 007 - Scaling +title: Scaling your deployment +description: How to scale Backstage as usage grows +--- + +Audience: Admins + +## Summary + +A single Backstage instance handles many users well, but as your organization +grows and more plugins are added, you may need to scale. This page covers the +strategies available. + +## Horizontal scaling + +The most straightforward approach is to run multiple identical instances of +Backstage behind a load balancer. All instances share the same external +database (and optional cache or search services). The backend plugins +coordinate through the database to share state and distribute work. + +In Kubernetes, this is as simple as increasing the replica count in your +deployment: + +```yaml +spec: + replicas: 3 +``` + +No additional configuration is needed. The database handles coordination +between instances. + +## Splitting the backend + +For larger installations, you can break the backend into multiple services, +each running a different set of plugins. For example, you might run the +catalog and scaffolder as separate deployments so that heavy catalog +processing does not affect scaffolder performance. + +This is a more advanced approach that requires: + +- Separate backend packages, each importing only the plugins they need. +- A custom `DiscoveryService` implementation that routes requests to the + correct backend based on the plugin ID. +- Routing both external (ingress) and internal (backend-to-backend) traffic + appropriately. + +See the +[backend system documentation](../../backend-system/building-backends/01-index.md#split-into-multiple-backends) +for details on how to set this up. + +## Separating the frontend + +By default, the frontend is served from your backend deployment using the +`@backstage/plugin-app-backend` plugin. If you need to reduce load on the +backend or serve the frontend from a CDN for better performance, you can +deploy the frontend separately. + +This involves: + +1. Removing the `@backstage/plugin-app-backend` plugin from the backend. +2. Building the frontend as a static bundle. +3. Serving it from a separate container (for example, NGINX) or a static + hosting provider. + +An example NGINX setup is available in the +[contrib/docker/frontend-with-nginx](https://github.com/backstage/backstage/blob/master/contrib/docker/frontend-with-nginx) +folder. + +:::note + +When serving the frontend separately, configuration is no longer injected by +the backend at runtime. You need to provide the correct configuration at +frontend build time. + +::: + +## When to scale + +Here are some signals that indicate you should consider scaling: + +- API response times are increasing. +- Catalog processing is falling behind (visible in the + `catalog.processing.duration` metric). +- Scaffolder tasks are queuing for longer than expected. +- Users report slow page loads. + +Start with horizontal scaling (more replicas) before considering backend +splitting. It is simpler and handles most growth scenarios. + +## Further reading + +For more details on scaling strategies, see the +[Scaling Backstage Deployments](../../deployment/scaling.md) reference +documentation. diff --git a/docs/golden-path/deployment/index.md b/docs/golden-path/deployment/index.md index e69de29bb2..417bc4267e 100644 --- a/docs/golden-path/deployment/index.md +++ b/docs/golden-path/deployment/index.md @@ -0,0 +1,38 @@ +--- +id: index +title: Deploying Backstage to production +description: A guided path for deploying your Backstage app to production +--- + +## Prerequisites + +- You have completed the [create-app golden path](../create-app/index.md) and + have a working Backstage app. +- Your code is pushed to a source control management system (GitHub, GitLab, + etc.). +- You have a general understanding of how your company builds and deploys + software. + +## What should I get out of this guide? + +This guide walks through everything you need to get your Backstage instance +running in a production environment. By the end, you will have: + +- A Docker image containing your Backstage app. +- A production database (PostgreSQL) connected to your deployment. +- A real authentication provider replacing the default guest login. +- A running deployment, whether on Kubernetes, ECS, or another platform. +- Monitoring and observability set up with OpenTelemetry. +- An understanding of how to scale your deployment as usage grows. + +## Structure + +We start with the Docker image since that is the foundation of any deployment. +Then we set up the two critical pre-deploy dependencies: a database and +authentication. After that, we walk through deploying to Kubernetes and discuss +other deployment options. Finally, we cover operational topics like +configuration management, monitoring, and scaling. + +## Next steps + +- [Building the Docker image](./001-docker.md)