Merge branch 'master' into nikolarAutodesk/makeTechDocsCustomizable

Signed-off-by: Reyna Nikolayev <146387693+nikolarAutodesk@users.noreply.github.com>
This commit is contained in:
Reyna Nikolayev
2024-12-10 16:40:53 -08:00
committed by GitHub
1425 changed files with 48552 additions and 8946 deletions
@@ -1,10 +1,16 @@
---
id: adrs-adr013
title: 'ADR013: Proper use of HTTP fetching libraries'
title: 'ADR013: [superseded] Proper use of HTTP fetching libraries'
# prettier-ignore
description: Architecture Decision Record (ADR) for the proper use of fetchApiRef, node-fetch, and cross-fetch for data fetching.
---
:::note Superseded
This ADR has been superseded by [ADR014](./adr014-use-fetch.md) and no longer applies.
:::
## Context
Using multiple HTTP packages for data fetching increases the complexity and the
@@ -0,0 +1,80 @@
---
id: adrs-adr014
title: 'ADR014: Proper use of HTTP fetching libraries'
# prettier-ignore
description: Architecture Decision Record (ADR) for the proper use of fetchApiRef, native fetch, and cross-fetch for data fetching.
---
## Context
Until now we have been recommending the use of `node-fetch` in Node.js contexts
through [ADR013](./adr013-use-node-fetch.md). Since then, Backstage has had its
minimum requirements upgraded to Node.js 20 or newer. The Node.js platform has
established a stable, reliable `undici` based native `fetch` in these versions.
Additionally, there are [some issues](https://github.com/backstage/backstage/issues/24590)
with using third party libraries that only appeared in newer versions of
Node.js.
## Decision
All code that is executed in Node.js (including backend and CLIs) should use the
native `fetch` for HTTP data fetching, and `typeof fetch` as the TypeScript type
in code where a `fetch` implementation can be injected or is referred to.
Example:
```ts
import { ResponseError } from '@backstage/errors';
// this is implicitly global.fetch
const response = await fetch('https://example.com/api/v1/users.json');
if (!response.ok) {
throw await ResponseError.fromResponse(response);
}
const users = await response.json();
```
Frontend plugins and packages should prefer to use the
[`fetchApiRef`](https://backstage.io/docs/reference/core-plugin-api.fetchapiref).
```ts
import { useApi } from '@backstage/core-plugin-api';
// Inside some React component...
const { fetch } = useApi(fetchApiRef);
const response = await fetch('https://example.com/api/v1/users.json');
if (!response.ok) {
throw await ResponseError.fromResponse(response);
}
const users = await response.json();
```
Isomorphic packages should have a dependency on the `cross-fetch` package for
mocking and type definitions. Preferably, classes and functions in isomorphic
packages should accept an argument of type `typeof fetch` to let callers supply
their preferred implementation of `fetch`. This lets them adorn the calls with
auth or other information, and track metrics etc, in a cross-platform way.
Example:
```ts
import crossFetch from 'cross-fetch';
export class MyClient {
private readonly fetch: typeof crossFetch;
constructor(options: { fetch?: typeof crossFetch }) {
this.fetch = options.fetch || crossFetch;
}
async users() {
return await this.fetch('https://example.com/api/v1/users.json');
}
}
```
## Consequences
We will gradually transition away from third party `fetch` replacement packages
such as `node-fetch` and others on the Node.js platform.
The `@mswjs/interceptors` library as used by `msw` version 1.x [does not support native fetch properly](https://github.com/mswjs/msw/issues/1563#issuecomment-1694249010) and likely never will. When you switch to using native fetch, you may see `msw` based tests start to fail to both capture and block traffic. Certain tests may need to be rewritten to use `msw` 2.x or newer instead, which uses a newer version of the interceptors.
+1 -1
View File
@@ -89,6 +89,6 @@ backend.add(import('@backstage/plugin-auth-backend-module-google-provider'));
## Adding the provider to the Backstage frontend
To add the provider to the frontend, add the `googleAuthApi` reference and
To add the provider to the frontend, add the `googleAuthApiRef` reference and
`SignInPage` component as shown in
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
+28
View File
@@ -412,3 +412,31 @@ Each entry has one or more of the following fields:
# Also supports the shorthand form:
# action: create, read
```
## Adding custom or logic for validation and issuing of tokens
The `pluginTokenHandlerDecoratorServiceRef` can be used to decorate the existing token handler without having to re-implement the entire `AuthService` implementation.
This is particularly useful when you want to add additional logic to the handler, such as logging or metrics or custom token validation.
The `PluginTokenHandler` interface has two methods:
- `issueToken`: This method is used to issue a token for a plugin. It takes in the `pluginId` and `targetPluginId` as arguments, and an optional `limitedUserToken` object which can be used to issue a token on behalf of another user. The method returns a promise that resolves to an object containing the issued token.
- `verifyToken`: This method is used to verify a token. It takes in the token as an argument and returns a promise that resolves to an object containing the subject of the token and an optional limited user token.
```ts
import {
PluginTokenHandler,
pluginTokenHandlerDecoratorServiceRef,
} from '@backstage/backend-defaults/auth';
import { createServiceFactory } from '@backstage/backend-plugin-api';
const decoratedPluginTokenHandler = createServiceFactory({
service: pluginTokenHandlerDecoratorServiceRef,
deps: {},
async factory() {
return (defaultImplementation: PluginTokenHandler) =>
new CustomTokenHandler(defaultImplementation);
},
});
```
@@ -73,6 +73,29 @@ export default createBackendFeatureLoader({
});
```
### Overriding service factories
Service factories registered by feature loaders have lower priority than ones added directly via `backend.add`. This allows you to use a feature loader for a larger number of service implementations, but still override individual services.
The ordering in which different feature loaders or service factories are added does not matter. There is also no priority between feature loaders, if two different feature loaders add a factory for the same service, the backend will fail to start.
```ts
const backend = createBackend();
backend.add(
createBackendFeatureLoader({
async *loader() {
yield import('./commonDiscoveryService'); // discovery service
yield import('./commonRootLoggerService'); // root logger service
},
}),
);
backend.add(import('./myDiscoveryService')); // discovery service
```
The result of the above example is that the backend starts up with `./myDiscoveryService` as the discovery service implementation, while `./commonDiscoveryService` is ignored. The `./commonRootLoggerService` will still be used.
### Dynamic logic
A feature loader can also be asynchronous, and for example fetch data from an external source to determine which features to load:
@@ -16,7 +16,6 @@ import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { fetch } from 'node-fetch';
createBackendPlugin({
pluginId: 'example',
@@ -102,6 +102,45 @@ or [contribute](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.
:::
### Custom token extraction logic
In some cases, you might want to customize how tokens are extracted from incoming requests. It might be that you want to extract tokens from a different location in the request. To support this you can supply your own slightly modified httpAuth service. The `DefaultHttpAuthService` class is exported from `@backstage/backend-defaults/httpAuth` and it's static `create` method can be used to pass in a custom `getTokenFromRequest` extraction function.
```ts
import { DefaultHttpAuthService } from '@backstage/backend-defaults/httpAuth';
import {
coreServices,
createServiceFactory,
} from '@backstage/backend-plugin-api';
export const customizedAuthServiceFactory = createServiceFactory({
service: coreServices.httpAuth,
deps: {
auth: coreServices.auth,
discovery: coreServices.discovery,
plugin: coreServices.pluginMetadata,
},
async factory({ auth, discovery, plugin }) {
return DefaultHttpAuthService.create({
auth,
discovery,
pluginId: plugin.getId(),
getTokenFromRequest: req => {
let token: string | undefined;
const header = req.headers.some_random_header;
if (typeof header === 'string') {
const parts = header.split(' ');
if (parts.length === 2 && parts[0] === 'Bearer') {
token = parts[1];
}
}
return { token };
},
});
},
});
```
This service has no configuration options, but it abides by the policies you
have set up using [the `httpRouter` service](./http-router.md) for your routes,
if any.
@@ -70,4 +70,67 @@ access the incoming credentials.
## Configuring the service
This service does not have any configuration options.
For more advanced customization, there are several APIs from the `@backstage/backend-defaults/httpRouter` package that allow you to customize the implementation of the config service. The default implementation uses all of the middleware exported from `@backstage/backend-defaults/httpRouter`, including `createLifecycleMiddleware`, `createAuthIntegrationRouter`, `createCredentialsBarrier` and `createCookieAuthRefreshMiddleware`. You can use these to create your own `httpRouter` service implementation, for example - here's how you would add a custom health check route to all plugins:
```ts
import {
createLifecycleMiddleware,
createCookieAuthRefreshMiddleware,
createCredentialsBarrier,
createAuthIntegrationRouter,
} from '@backstage/backend-defaults/httpRouter';
import { createServiceFactory } from '@backstage/backend-plugin-api';
const backend = createBackend();
backend.add(
createServiceFactory({
service: coreServices.httpRouter,
initialization: 'always',
deps: {
plugin: coreServices.pluginMetadata,
config: coreServices.rootConfig,
lifecycle: coreServices.lifecycle,
rootHttpRouter: coreServices.rootHttpRouter,
auth: coreServices.auth,
httpAuth: coreServices.httpAuth,
},
async factory({
auth,
httpAuth,
config,
plugin,
rootHttpRouter,
lifecycle,
}) {
const router = PromiseRouter();
rootHttpRouter.use(`/api/${plugin.getId()}`, router);
const credentialsBarrier = createCredentialsBarrier({
httpAuth,
config,
});
router.use(createAuthIntegrationRouter({ auth }));
router.use(createLifecycleMiddleware({ lifecycle }));
router.use(credentialsBarrier.middleware);
router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth }));
// Add a custom healthcheck endpoint for all plugins.
router.use('/health', (_, res) => {
res.status(200);
});
return {
use(handler: Handler): void {
router.use(handler);
},
addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void {
credentialsBarrier.addAuthPolicy(policy);
},
};
},
}),
);
```
@@ -38,3 +38,29 @@ backend.add(
}),
);
```
### Custom headers in health check responses
While not implemented directly in the root health service, the default implementation of the [RootHttpRouter](./root-http-router.md) service includes a configuration option to set additional headers to include in health check responses. For example, you can add a `service-name` header using the following configuration:
```yaml
backend:
health:
headers:
service-name: my-service
```
It can be a good idea to set a header for your health check responses that
uniquely identifies your service in a multi-service environment. This ensures
that the health check that is configured for your service is actually hitting
your service and not another.
For example, if using Envoy you can use the [`service_name_matcher`](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/health_checking#health-check-identity) configuration and
set the `x-envoy-upstream-healthchecked-cluster` header to a matching value. For example:
```yaml
backend:
health:
headers:
x-envoy-upstream-healthchecked-cluster: my-service
```
@@ -42,6 +42,29 @@ createBackendPlugin({
## Configuring the service
### Via `app-config.yaml`
The `app-config.yaml` file provides configurable options that can be adjusted to meet your `RootHttpRouterService` specific requirements:
```yaml
backend:
lifecycle:
# (Optional) The maximum time that paused requests will wait for the service to start, before returning an error (defaults to 5 seconds).
# Supported formats:
# - A string in the format of '1d', '2 seconds' etc. as supported by the `ms` library.
# - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'.
# - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`.
startupRequestPauseTimeout: { seconds: 10 }
# (Optional) The minimum time that the HTTP server will delay the shutdown of the backend. During this delay health checks will be set to failing, allowing traffic to drain (defaults to 0 seconds).
# Supported formats:
# - A string in the format of '1d', '2 seconds' etc. as supported by the `ms` library.
# - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'.
# - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`.
serverShutdownTimeout: { seconds: 20 }
```
### Via Code
There's additional options that you can pass to configure the root HTTP Router service. These options are passed when you call `createBackend`.
- `indexPath` - optional path to forward all unmatched requests to. Defaults to `/api/app` which is the `app-backend` plugin responsible for serving the frontend application through the backend.
@@ -16,7 +16,6 @@ import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { fetch } from 'node-fetch';
createBackendPlugin({
pluginId: 'example',
-182
View File
@@ -1,182 +0,0 @@
---
id: aws-lightsail
title: Deploying Backstage on AWS Lightsail
sidebar_label: AWS Lightsail
description: How to deploy Backstage on AWS Lightsail
---
> **DISCLAIMER: The `deploy` command is in alpha and still experimental. Do not use the `deploy` command for production deployments.**
Getting started with Backstage often involves setting up an instance on a cloud provider and sharing it with your team so they can experiment. To make this cloud deployment easier, we've built a `deploy` command to stand up a proof-of-concept instance on AWS (using Lightsail).
## What is AWS Lightsail
:::tip
AWS offers a free tier for up to three months on $10 USD/month Container service (Micro -1 node). By default we use the `nano` node, so if you are a new user this approach shouldn't cost you anything. For more information, refer to the [pricing](https://aws.amazon.com/lightsail/pricing/) documentation.
:::
AWS Lightsail offers a simple way to run containers in the cloud. To learn more about AWS Lightsail, please refer to the [official documentation](https://lightsail.aws.amazon.com/ls/docs/en_us/articles/amazon-lightsail-container-services-deployments).
## Creating user in AWS
- Open the AWS console and navigate to the IAM section
- In the left side menu click on `Users` and then click on `Add users`
- Specify a username and then click on `Next`
- Afterwards you can assign permissions, select `Attach policies directly` and then click on `Create policy`.
This should take you to a new window in which you can create a new policy based on `JSON`.
Copy over the following:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ecr:DescribeImageReplicationStatus",
"ecr:ListTagsForResource",
"ecr:UploadLayerPart",
"ecr:BatchGetRepositoryScanningConfiguration",
"ecr:DeleteRepository",
"ecr:GetRegistryScanningConfiguration",
"ecr:CompleteLayerUpload",
"ecr:TagResource",
"ecr:DescribeRepositories",
"ecr:DeleteRepositoryPolicy",
"ecr:BatchCheckLayerAvailability",
"ecr:GetLifecyclePolicy",
"ecr:GetRegistryPolicy",
"ecr:PutLifecyclePolicy",
"ecr:DescribeImageScanFindings",
"ecr:GetLifecyclePolicyPreview",
"ecr:CreateRepository",
"ecr:DescribeRegistry",
"ecr:GetDownloadUrlForLayer",
"ecr:GetAuthorizationToken",
"ecr:DeleteLifecyclePolicy",
"ecr:PutImage",
"ecr:UntagResource",
"ecr:SetRepositoryPolicy",
"ecr:BatchGetImage",
"ecr:InitiateLayerUpload",
"ecr:GetRepositoryPolicy",
"lightsail:CreateContainerService",
"lightsail:GetKeyPair",
"lightsail:GetContainerServiceDeployments",
"lightsail:CreateContainerServiceRegistryLogin",
"lightsail:GetContainerImages",
"lightsail:UntagResource",
"lightsail:RegisterContainerImage",
"lightsail:GetContainerServices",
"lightsail:GetContainerServicePowers",
"lightsail:GetKeyPairs",
"lightsail:CreateContainerServiceDeployment",
"lightsail:GetContainerServiceMetricData",
"lightsail:GetContainerAPIMetadata",
"lightsail:DeleteContainerService",
"lightsail:GetContainerLog",
"lightsail:TagResource"
],
"Resource": "*"
},
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [],
"Resource": []
}
]
}
```
Then click on `Next` and give the policy a name and a description of your liking. Afterwards, click on `Create policy`.
- Navigate back to the user creation window and press on the refresh button and search for the policy you just created. Now, create the user.
- Now you will be redirected to all users, click on the user you just created and click on `Security credentials`
- Scroll below and click on `Create access key`
- Choose `Command Line Interface (CLI)`
- Now export the following values
```bash
$ export AWS_ACCESS_KEY_ID=... (first value)
$ export AWS_SECRET_ACCESS_KEY=.... (second secret value)
```
## Configuring the Pulumi CLI
Second, install the [Pulumi CLI](https://www.pulumi.com/docs/get-started/install/) - `backstage-deploy` uses it to
simplify the management of cloud resources (Pulumi allows us to simply specify the desired "target cloud state", and
Pulumi will intelligently create/modify/delete resources to reach that state. Nice!).
Then we need to execute the following commands, to set Pulumi up:
:::tip
Make sure to store your passphrase somewhere safe as it is used to encrypt/decrypt your Pulumi config.
:::
```bash
$ pulumi login --local
$ export PULUMI_CONFIG_PASSPHRASE="<your-secret>"
```
By using `pulumi login --local` we are making sure that Pulumi stores our state on the local file disk. The environment variable `PULUMI_CONFIG_PASSPHRASE` is used by Pulumi to generate a unique key for your stack
## Deploying your instance on Lightsail
:::tip
Make sure that [Docker](https://docs.docker.com/) is running on your machine before you start this section.
:::
After you have made your changes to your local instance, it's time to deploy it on Lightsail.
First, we need to configure a new `app-config` file and update the `baseUrl`.
```bash
$ touch app-config.deployment.yaml
```
And then update the file with the following yaml:
```yaml
app:
baseUrl: ${BACKSTAGE_HOST}
backend:
baseUrl: ${BACKSTAGE_HOST}
```
The environment variable `BACKSTAGE_HOST` will be set to the endpoint that AWS Lightsail creates.
Now we can deploy our instance!
```bash
$ npx backstage-deploy aws --stack backstage-poc --create-dockerfile
```
In the first part of the command, we are specifying that we want to deploy our instance on AWS. With the [`--stack`](https://www.pulumi.com/docs/reference/cli/pulumi_stack/) option, we are providing Pulumi a reference to our container deployment. Furthermore, with the `--create-dockerfile` option, there will be a `Dockerfile` and `.dockerignore` created in the root of the project.
After running the command, Pulumi will start creating the following resources for you in AWS:
- ECR Repository
- Lightsail Container Service
- Lightsail Container Service Deployment
- Policy that allows Lightsail to pull from ECR
If it's the first time building the Docker image, it might take a while for everything to be fully provisioned. After the command is finished running, your Backstage instance should be up and running on AWS Lightsail! 🎉
### Cleaning up resources
Cleaning up the resources is also done with the deploy command.
```bash
$ npx backstage-deploy aws --stack backstage-poc --destroy
```
This will delete everything that was originally created by the `deploy` command.
+10 -3
View File
@@ -5,6 +5,10 @@ sidebar_label: Docker
description: How to build a Backstage Docker image for deployment
---
:::note Note
Before you start this section, it would be good to have a basic understanding of Docker and how it works. If you are new to Docker, you can start with the [Docker overview](https://docs.docker.com/get-started/overview/) guide.
:::
This section describes how to build a Backstage App into a deployable Docker
image. It is split into three sections, first covering the host build approach,
which is recommended due to its speed and more efficient and often simpler
@@ -46,8 +50,7 @@ yarn install --immutable
yarn tsc
# Build the backend, which bundles it all up into the packages/backend/dist folder.
# The configuration files here should match the one you use inside the Dockerfile below.
yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml
yarn build:backend
```
Once the host build is complete, we are ready to build our image. The following
@@ -85,6 +88,7 @@ WORKDIR /app
# Copy files needed by Yarn
COPY --chown=node:node .yarn ./.yarn
COPY --chown=node:node .yarnrc.yml ./
COPY --chown=node:node backstage.json ./
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV=production
@@ -181,7 +185,7 @@ the repo root:
FROM node:20-bookworm-slim AS packages
WORKDIR /app
COPY package.json yarn.lock ./
COPY backstage.json package.json yarn.lock ./
COPY .yarn ./.yarn
COPY .yarnrc.yml ./
@@ -219,6 +223,7 @@ WORKDIR /app
COPY --from=packages --chown=node:node /app .
COPY --from=packages --chown=node:node /app/.yarn ./.yarn
COPY --from=packages --chown=node:node /app/.yarnrc.yml ./
COPY --from=packages --chown=node:node /app/backstage.json ./
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
yarn install --immutable
@@ -266,7 +271,9 @@ WORKDIR /app
# Copy the install dependencies from the build stage and context
COPY --from=build --chown=node:node /app/.yarn ./.yarn
COPY --from=build --chown=node:node /app/.yarnrc.yml ./
COPY --from=build --chown=node:node /app/backstage.json ./
COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton/ ./
# Note: The skeleton bundle only includes package.json files -- if your app has
# plugins that define a `bin` export, the bin files need to be copied as well to
# be linked in node_modules/.bin during yarn install.
-231
View File
@@ -1,231 +0,0 @@
---
id: flightcontrol
title: Deploying with Flightcontrol
sidebar_label: AWS Fargate via Flightcontrol
description: Deploying Backstage to AWS Fargate via Flightcontrol
---
This guide explains how to deploy Backstage to [Flightcontrol](https://www.flightcontrol.dev?ref=backstage), a platform that fully automates deployments to Amazon Web Services (AWS). Flightcontrol supports git-driven and image registry deployments.
Before you begin, make sure you have a [Flightcontrol account](https://app.flightcontrol.dev/signup?ref=backstage) and a [GitHub account](https://github.com/login) to follow this guide.
# Creating a Dockerfile and .dockerignore
Once your Flightcontrol account is setup, you will need to prepare a `Dockerfile` and `.dockerignore` to deploy Backstage to your target AWS environment. The standard `Dockerfile` included in the Backstage repository assumes that the `skeleton.tar.gz` and `bundle.tar.gz` already exist. When integrating Flightcontrol directly with a GitHub repository, changes to files within this repository will automatically start a Flightcontrol deployment, unless you have configured deployments via a webhook. Regardless of which method you have chosen, when Flightcontrol starts a deployment process it will pull all files directly from the repository, and not from a GitHub runner or other location. As Flightcontrol does not contain CI steps this results in the zip files having to be committed to the repository in order to be available for the `Dockerfile` to copy.
A simple work around for this is to use a `Dockerfile` with a [multi-stage build](https://docs.docker.com/build/building/multi-stage/). Using this approach we can create our zip files in the first build stage, and copy them into the second stage ready for deployment.
The following two code snippets demonstrate this method. The first block of code is an example of a multi-stage build approach and should be added to a file called `Dockerfile.flightcontrol` in the `packages/backend` directory.
```dockerfile filename="Dockerfile.flightcontrol"
# This dockerfile builds an image for the backend package.
# It should be executed with the root of the repo as docker context.
#
# Before building this image, be sure to have run the following commands in the repo root:
#
# yarn install
# yarn tsc
# yarn build:backend
#
# Once the commands have been run, you can build the image using `yarn build-image`
FROM node:20-bookworm-slim as build
USER node
WORKDIR /app
COPY --chown=node:node . .
RUN yarn install --frozen-lockfile
# tsc outputs type definitions to dist-types/ in the repo root, which are then consumed by the build
RUN yarn tsc
# Build the backend, which bundles it all up into the packages/backend/dist folder.
# The configuration files here should match the one you use inside the Dockerfile below.
RUN yarn build:backend --config ../../app-config.yaml
FROM node:20-bookworm-slim
# Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends python3 g++ build-essential && \
yarn config set python /usr/bin/python3
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends libsqlite3-dev
# From here on we use the least-privileged `node` user to run the backend.
USER node
# This should create the app dir as `node`.
# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`.
# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`.
WORKDIR /app
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV=production
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
# The skeleton contains the package.json of each package in the monorepo,
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
COPY --from=build app/yarn.lock app/package.json app/packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
yarn install --frozen-lockfile --production --network-timeout 300000
# Then copy the rest of the backend bundle, along with any other files we might want.
COPY --from=build app/packages/backend/dist/bundle.tar.gz app/app-config*.yaml ./
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"]
```
In order to prevent the default `.dockerignore` file from preventing the copying of the relevant files into the first stage of our build, we need to override it with a custom one. This can also be added to the `packages/backend` directory, it should be called `Dockerfile.flightcontrol.dockerignore` and contain the following.
```ssh filename="Dockerfile.flightcontrol.dockerignore"
.git
.yarn/cache
.yarn/install-state.gz
node_modules
packages/*/node_modules
*.local.yaml
```
With these two new files, you will now have the necessary steps in place to build the zip files, copy them into the second stage of the build, and deploy them via Flightcontrol.
# Creating a custom app-config.production file
Our next steps before switching to the Flightcontrol dashboard is to create a custom app-config.production file. The purposes of this is to update how Backstage will connect to the RDS hosted Postgres DB. The default `app-config.production` file uses the `host`, `port`, `user` and `password` environment variables.
When creating a database via the Flightcontrol dashboard, we are given an environment variable with the single connection string. Therefore we need an `app-config.production` file which uses this variable.
Within your Backstage project create a new file called `app-config.production.flightcontrol.yaml`. Add the following configuration to it:
```yaml filename="app-config.production.flightcontrol.yaml"
app:
# Should be the same as backend.baseUrl when using the `app-backend` plugin.
baseUrl: http://localhost:7007
backend:
# Note that the baseUrl should be the URL that the browser and other clients
# should use when communicating with the backend, i.e. it needs to be
# reachable not just from within the backend host, but from all of your
# callers. When its value is "http://localhost:7007", it's strictly private
# and can't be reached by others.
baseUrl: http://localhost:7007
# The listener can also be expressed as a single <host>:<port> string. In this case we bind to
# all interfaces, the most permissive setting. The right value depends on your specific deployment.
listen: ':7007'
# config options: https://node-postgres.com/apis/client
database:
client: pg
pluginDivisionMode: 'schema'
connection:
connectionString: ${POSTGRES_CON_STRING}
ssl:
require: true
rejectUnauthorized: false
# Flightcontrol provides a single DB connection string
# environment variable which can be renamed to POSTGRES_CON_STRING.
# the following default values are therefore not used:
# host: ${POSTGRES_HOST}
# port: ${POSTGRES_PORT}
# user: ${POSTGRES_USER}
# password: ${POSTGRES_PASSWORD}
# https://node-postgres.com/features/ssl
# you can set the sslmode configuration option via the `PGSSLMODE` environment variable
# see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
# ssl:
# ca: # if you have a CA file and want to verify it you can uncomment this section
# $file: <file-path>/ca/server.crt
catalog:
# Overrides the default list locations from app-config.yaml as these contain example data.
# See https://backstage.io/docs/features/software-catalog/#adding-components-to-the-catalog for more details
# on how to get entities into the catalog.
locations: []
```
Make a note of the environment variable used in the `connectionString`. In our example above this is `POSTGRES_CON_STRING`. You will need this later when you have deployed the database via the Flightcontrol console, and wish to connect to it from Backstage.
# Deployment Via Dashboard
Ensure that custom `Dockerfile.flightcontrol`, `Dockerfile.flightcontrol.dockerignore` and `app-config.production.flightcontrol.yaml` have been committed to your repository before following the next steps.
Login into the Flightcontrol Dashboard and complete each of the following:
1. Create a new project from the Flightcontrol Dashboard
2. Select the GitHub repo for your Backstage project
3. Select `GUI` as the config type:
4. Then, choose `+ Add Web Server (Fargate)` under Services before entering the following server information:
| Field Name | Value |
| ----------------- | ----------------- |
| Build Type | Custom Dockerfile |
| Health Check Path | /catalog |
| Port | 7007 |
5. Click `Create Project` and complete any required steps (like linking your AWS account). Remember to point the project to your custom files.
# Deployment via Code
1. Create a new project from the Flightcontrol Dashboard
2. Select the GitHub repo for your Backstage project
3. Select the `flightcontrol.json` Config Type. Update the example JSON below where applicable to your custom Dockerfile.
```json filename="flightcontrol.json"
{
"$schema": "https://app.flightcontrol.dev/schema.json",
"environments": [
{
"id": "backstage",
"name": "Backstage",
"region": "us-west-2",
"source": {
"branch": "main"
},
"services": [
{
"id": "backstage",
"name": "Backstage",
"type": "fargate",
"buildType": "docker",
"dockerfilePath": "Dockerfile",
"dockerContext": ".",
"healthCheckPath": "/catalog",
"cpu": 0.5,
"memory": 1,
"domain": "backstage.yourapp.com",
"port": 7007,
"minInstances": 1,
"maxInstances": 1
}
]
}
]
}
```
# Databases and Redis
If you need a database or Redis for your Backstage plugins, you can easily add those to your Flightcontrol deployment. For more information, see [the flightcontrol docs](https://www.flightcontrol.dev/docs/guides/flightcontrol/using-code?ref=backstage#redis).
When creating a Postgres RDS database you will need to update the connection string variable name to the one included in the `app-config.production.flightcontrol.yaml`. As noted above in our example we called this `POSTGRES_CON_STRING`.
## Troubleshooting
- [Flightcontrol Documentation](https://www.flightcontrol.dev/docs?ref=backstage)
- [Troubleshooting](https://www.flightcontrol.dev/docs/troubleshooting?ref=backstage)
-140
View File
@@ -1,140 +0,0 @@
---
id: heroku
title: Deploying with Heroku
sidebar_label: Heroku
description: How to deploy Backstage to Heroku
---
Heroku is a Platform as a Service (PaaS) designed to simplify application deployment.
## Create App
Starting with an existing Backstage app or follow the [getting started guide](https://backstage.io/docs/getting-started/) to create a new one.
Install the
[Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) and create a new Heroku app:
```shell
cd your-app/
heroku apps:create <your-app>
```
## Domain
Get Heroku app URL:
```shell
heroku domains -a <your-app>
<your-app-123>.herokuapp.com
```
The core [app-backend plugin](https://www.npmjs.com/package/@backstage/plugin-app-backend) allows a single Heroku app to serve the frontend and backend. To make this work you need to update the `baseUrl` and `port` in `app-config.production.yaml`:
```yaml
app:
baseUrl: https://<your-app-123>.herokuapp.com
backend:
baseUrl: https://<your-app-123>.herokuapp.com
listen:
port:
$env: PORT
# The $PORT environment variable is a feature of Heroku
# https://devcenter.heroku.com/articles/dynos#web-dynos
```
## Build Script
Add a build script in `package.json` to compile frontend during deployment:
```json
"scripts": {
"build": "yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml"
```
## Start Command
Create a [Procfile](https://devcenter.heroku.com/articles/procfile) in the app's root:
```shell
echo "web: yarn workspace backend start --config ../../app-config.yaml --config ../../app-config.production.yaml" > Procfile
```
## Database
Provision a [Heroku Postgres](https://elements.heroku.com/addons/heroku-postgresql) database:
```shell
heroku addons:create heroku-postgresql -a <your-app>
```
Update `database` in `app-config.production.yaml`:
```yaml
backend:
database:
client: pg
pluginDivisionMode: schema
ensureExists: false
ensureSchemaExists: true
connection: ${DATABASE_URL}
```
Allow postgres self-signed certificates:
```shell
heroku config:set PGSSLMODE=no-verify -a <your-app>
```
## Deployment
Commit changes and push to Heroku to build and deploy:
```shell
git add Procfile && git commit -am "configure heroku"
git push heroku main
```
View the app in the browser:
```shell
heroku open -a <your-app>
```
View logs:
```shell
heroku logs -a <your-app>
```
## Docker
As an alternative to git deploys, Heroku also [supports container images](https://devcenter.heroku.com/articles/container-registry-and-runtime).
Login to Heroku's container registry:
```shell
heroku container:login
```
Configure the Heroku app to run a container image:
```shell
heroku stack:set container -a <your-app>
```
Locally run the [host build commands](https://backstage.io/docs/deployment/docker/#host-build), they must be run whenever you are going to publish a new image:
```shell
yarn install --immutable
yarn tsc
yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml
```
Build, push, and release the container image to the `web` dyno:
```shell
docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com/<your-app>/web
docker push registry.heroku.com/<your-app>/web
heroku container:release web -a <your-app>
```
+1 -8
View File
@@ -30,14 +30,7 @@ At Spotify, we deploy software generally by:
This method is covered in [Building a Docker image](docker.md) and
[Deploying with Kubernetes](k8s.md).
There is also an example of deploying on [Heroku](heroku.md), which only
requires the first two steps.
There is also a contrib guide to deploying Backstage with
[AWS Fargate and Aurora PostgreSQL](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/aws-fargate-deployment.md).
Please consider contributing other deployment guides if you get Backstage set up
on common infrastructure, it would be a great benefit to the community.
There are many ways to deploy Backstage! You can find more examples in the community contributed guides found [here](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/).
If you need to run Backstage behind a corporate proxy, this
[contributed guide](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md)
-47
View File
@@ -1,47 +0,0 @@
---
id: koyeb
title: Deploying with Koyeb
sidebar_label: Koyeb
description: How to deploy Backstage to Koyeb
---
This guide explains how to deploy Backstage to [Koyeb](https://www.koyeb.com/), a serverless platform that provides the fastest way to deploy applications globally. Koyeb supports git-driven and container-based deployments.
Before you begin, make sure you have a [Koyeb account](https://app.koyeb.com/) to follow this guide.
## Configuring the CLI
First, install the
[Koyeb CLI](https://www.koyeb.com/docs/quickstart/koyeb-cli) and follow the instructions in the [quickstart guide](https://www.koyeb.com/docs/quickstart/koyeb-cli) to login.
Then, configure your `app-config.yaml` with your `baseUrl`:
```yaml
app:
# Should be the same as backend.baseUrl when using the `app-backend` plugin
baseUrl: https://<your-app>.koyeb.app
backend:
baseUrl: https://<your-app>.koyeb.app
listen:
# The $PORT environment variable is a feature of Koyeb
# https://www.koyeb.com/docs/apps/services
port: ${PORT}
```
## Push and deploy Backstage to Koyeb
Push your Backstage application with its [Dockerfile](docker.md) to Koyeb using the following command:
```bash
koyeb app init example-backstage \
--git github.com/<YOUR_GITHUB_USERNAME>/<YOUR_REPOSITORY_NAME> \
--git-branch main \
--ports 8000:http \
--routes /:8000 \
--env PORT=8000
```
Your application will be built and deployed to Koyeb. Once the build has finished, you will be able to access your application running on Koyeb by clicking the URL ending with `.koyeb.app`.
Congratulations! Now you should have Backstage up and running! 🎉
@@ -0,0 +1,87 @@
---
id: experimental
title: Experimental Features
# prettier-ignore
description: Information on Experimental Features that are currently available in the Scaffolder
---
## Introduction
This section contains information and guides on the experimental features that are currently available in the Scaffolder. Be advised that these features are still in development and may not be fully stable or complete, and are subject to change at any time.
Please leave feedback on these features in the [Backstage Discord](https://discord.com/invite/MUpMjP2) or by [creating an issue](https://github.com/backstage/backstage/issues/new/choose) on the Backstage GitHub repository.
## Retries and Recovery
### TODO
## Form Decorators
Form decorators provide the ability to run arbitrary code before the form is submitted along with secrets to the `scaffolder-backend` plugin. They are provided to the `app` using a Utility API.
#### Installation
To install the Form Decorators, add the following to your `packages/app/src/apis.ts`:
```ts
createApiFactory({
api: formDecoratorsApiRef,
deps: {},
factory: () =>
DefaultScaffolderFormDecoratorsApi.create({
decorators: [
// add decorators here
],
}),
}),
```
And then you'll also need to define which decorators run in each template using the `EXPERIMENTAL_formDecorators` key in the template's `spec`:
```yaml
kind: Template
metadata:
name: my-template
spec:
EXPERIMENTAL_formDecorators:
- id: my-decorator
input:
test: something funky
parameters: ...
steps: ...
```
#### Creating a Decorator
You can create a decorator using the simple helper method `createScaffolderFormDecorator`:
```ts
export const mockDecorator = createScaffolderFormDecorator({
// give the decorator a name
id: 'mock-decorator',
// define the schema for the input that can be proided in `template.yaml`
schema: {
input: {
test: z => z.string(),
},
},
deps: {
// define dependencies here
githubApi: githubAuthApiRef,
},
decorator: async (
// Context has all the things needed to write simple decorators
{ setSecrets, setFormState, input: { test } },
// Depepdencies injected here
{ githubApi },
) => {
// mutate the form state
setFormState(state => ({ ...state, test, mock: 'MOCK' }));
// mutate the form secrets
setSecrets(state => ({ ...state, GITHUB_TOKEN: 'MOCK_TOKEN' }));
},
});
```
@@ -198,6 +198,23 @@ parameters:
ui:widget: checkboxes
```
## Markdown text blocks
```yaml
parameters:
- title: Fill in some steps
properties:
markdown:
type: 'null' # Needs to be quoted
description: |
## Markdown Text Block
Standard markdown formatting is supported including *italics*, **bold** and [links](https://example.com)
* bullet 1
* bullet 2
```
## Use parameters as condition in steps
Conditions use Javascript equality operators.
@@ -250,6 +267,54 @@ parameters:
- lastName
```
### Multiple conditional fields with custom ordering
```yaml
parameters:
- title: Fill in some steps
ui:order:
- includeName
- lastName
- includeAddress
- address
properties:
includeName:
title: Include Name?
type: boolean
default: true
includeAddress:
title: Include Address?
type: boolean
default: true
dependencies:
includeName:
allOf:
- if:
properties:
includeName:
const: true
then:
properties:
lastName:
title: Name
type: string
required:
- lastName
includeAddress:
allOf:
- if:
properties:
includeAddress:
const: true
then:
properties:
address:
title: Address
type: string
required:
- address
```
## Conditionally set parameters
The `if` keyword within the parameter uses [nunjucks templating](https://mozilla.github.io/nunjucks/templating.html#if). The `not` keyword is unavailable; instead, use javascript equality.
@@ -141,6 +141,39 @@ Prefer to use `camelCase` over `snake_case` or `kebab-case` for these actions if
> We're aware that there are some exceptions to this, but try to follow as close as possible. We'll be working on migrating these in the repository over time too.
### Adding a TemplateExample
A TemplateExample is a predefined structure that can be used to create custom actions in your software templates. It serves as a blueprint for users to understand how to use a specific action and its fields as well as to ensure consistency and standardization across different custom actions.
#### Define a TemplateExample and add to your Custom Action
```ts title="With JSON Schema"
import { TemplateExample } from '@backstage/plugin-scaffolder-node';
import yaml from 'yaml';
export const examples: TemplateExample[] = [
{
description: 'Template Example for Creating an Acme file',
example: yaml.stringify({
steps: [
{
action: 'acme:file:create',
name: 'Create an Acme file.',
input: {
contents: 'file contents...',
filename: 'ACME.properties',
},
},
],
}),
},
];
```
Add the example to the `createTemplateAction` under the object property `examples`:
`return createTemplateAction<{ contents: string; filename: string }>({id: 'acme:file:create', description: 'Create an Acme file', examples, ...};`
### The context object
When the action `handler` is called, we provide you a `context` as the only
+1 -1
View File
@@ -186,7 +186,7 @@ import { useShadowRootElements } from '@backstage/plugin-techdocs-react';
// difference is that you'd set `location` to `TechDocsAddonLocations.Content`.
export const MakeAllImagesCatGifsAddon = () => {
// This hook can be used to get references to specific elements. If you need
// access to the whole shadow DOM, use the the underlying useShadowRoot()
// access to the whole shadow DOM, use the underlying useShadowRoot()
// hook instead.
const images = useShadowRootElements<HTMLImageElement>(['img']);
+3 -1
View File
@@ -297,7 +297,9 @@ You can do so by including the following lines right above `USER node` of your
`Dockerfile`:
```Dockerfile
RUN apt-get update && apt-get install -y python3 python3-pip python3-venv
RUN apt-get update && \
apt-get install -y python3 python3-pip python3-venv && \
rm -rf /var/lib/apt/lists/*
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
+16 -5
View File
@@ -639,7 +639,7 @@ Note: To refer external diagram files, we need to include the diagrams directory
## How to add Mermaid support in TechDocs
There are two options for adding Mermaid support in TechDocs: using [Kroki](https://kroki.io) or by using [markdown-inline-mermaid](https://github.com/johanneswuerbach/markdown-inline-mermaid). We currently use `markdown-inline-mermaid` for the [Mermaid example on the Demo site](https://demo.backstage.io/docs/default/component/backstage-demo/examples/mermaid/).
There are a few options for adding Mermaid support in TechDocs: using [Kroki](https://kroki.io) or [markdown-inline-mermaid](https://github.com/johanneswuerbach/markdown-inline-mermaid) to generate the diagrams at build time, or the [`backstage-plugin-techdocs-addon-mermaid`](https://github.com/johanneswuerbach/backstage-plugin-techdocs-addon-mermaid) plugin to generate the diagram in the browser. We currently use `backstage-plugin-techdocs-addon-mermaid` plugin for the [Mermaid example on the Demo site](https://demo.backstage.io/docs/default/component/backstage-demo/examples/mermaid/).
### Using Kroki
@@ -745,16 +745,23 @@ Done! Now you have a support of the following diagrams along with mermaid:
To use `markdown-inline-mermaid` to generate your Mermaid diagrams in TechDocs you'll need to do the following:
1. In your Dockerfile you will need to make sure you install `markdown-inline-mermaid` like this: `RUN pip3 install mkdocs-techdocs-core markdown-inline-mermaid`
2. You will also need to install the `@mermaid-js/mermaid-cli`, to do that add this: `RUN yarn global add @mermaid-js/mermaid-cli`
3. Now in your `mkdocs.yml` file you will need to add the following section (this is at the root level like `plugins` which you should already have):
1. In your Dockerfile you will need to make sure you install `markdown-inline-mermaid` and its dependencies, you will also need to install the `@mermaid-js/mermaid-cli`:
```dockerfile title="Dockerfile"
RUN apt-get install -y chromium
RUN pip3 install mkdocs-techdocs-core markdown-inline-mermaid
RUN npm install -g @mermaid-js/mermaid-cli
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
```
2. Now in your `mkdocs.yml` file you will need to add the following section (this is at the root level like `plugins` which you should already have):
```yaml title="mkdocs.yml"
markdown_extensions:
- markdown_inline_mermaid
```
4. With this in place you can now add Mermaid diagrams in your Markdown files like this:
3. With this in place you can now add Mermaid diagrams in your Markdown files like this:
````md
```mermaid
@@ -765,6 +772,10 @@ To use `markdown-inline-mermaid` to generate your Mermaid diagrams in TechDocs y
```
````
### Using the `backstage-plugin-techdocs-addon-mermaid` plugin
Please follow the [Getting Started](https://github.com/johanneswuerbach/backstage-plugin-techdocs-addon-mermaid?tab=readme-ov-file#getting-started) instructions in the plugin's README.
## How to implement a hybrid build strategy
One limitation of the [Recommended deployment](./architecture.md#recommended-deployment) is that
@@ -58,7 +58,7 @@ The following are the known conversion functions provided by various libraries:
## Putting it all together
Using the plugin converter along with extension converters from various libraries, we can not more fully convert our 3rd-party plugin to be able to install it in an app built with the new frontend system:
Using the plugin converter along with extension converters from various libraries, we can now more fully convert our 3rd-party plugin to be able to install it in an app built with the new frontend system:
```ts
import {
-21
View File
@@ -1,21 +0,0 @@
---
id: concepts
title: Key Concepts
# prettier-ignore
description: High level key concepts used in the Backstage project
---
For users of Backstage, there are certain concepts which are central to its
design and functionality. Being an expert in each of these concepts is not
necessary, however having a base understanding of each will make administering,
configuring, and operating Backstage easier.
- CHANGELOG - https://keepachangelog.com
- Docker - https://www.docker.com/
- Monorepo - https://semaphoreci.com/blog/what-is-monorepo
- Node.js - https://nodejs.org
- React - https://reactjs.org
- Semantic Versioning - https://semver.org
- TypeScript - https://www.typescriptlang.org
- YAML - https://yaml.org
- Yarn - https://www.pluralsight.com/guides/yarn-a-package-manager-for-node-js
+48 -14
View File
@@ -6,13 +6,13 @@ description: How to set up PostgreSQL for your Backstage instance.
Audience: Admins
### Summary
## Summary
This guide walks through how to set up a PostgreSQL database to host your Backstage data. It assumes you've already have a scaffolded Backstage app from following the [Standalone Install](../index.md) guide.
This guide walks through how to set up a PostgreSQL database to host your Backstage data. It assumes you've already have a scaffolded Backstage app from following the [Creating your Backstage App](../index.md) guide.
By the end of this tutorial, you will have a working PostgreSQL database hooked up to your Backstage install.
### Prerequisites
## Prerequisites
This guide assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `apt-get`, `psql`, `yarn`.
@@ -23,7 +23,7 @@ This guide assumes a basic understanding of working on a Linux based operating s
- If the database is not hosted on the same server as the Backstage app, the
PostgreSQL port needs to be accessible (the default is `5432` or `5433`)
### 1. Install and configure PostgreSQL
## 1. Install and Configure PostgreSQL
:::tip Already configured your database?
@@ -68,17 +68,9 @@ That's enough database administration to get started. Type `\q`, followed by
pressing the enter key. Then again type `exit` and press enter. Next, you need
to install and configure the client.
### 2. Configuring Backstage `pg` Client
## 2. Configuring Backstage `pg` Client
Go to the root directory of your freshly installed Backstage
App. Run the following to install the PostgreSQL client into your backend:
```bash title="From your Backstage root directory"
yarn --cwd packages/backend add pg
```
Use your favorite editor to open `app-config.yaml` and add your PostgreSQL
configuration in the root directory of your Backstage app using the credentials from the previous steps.
Use your favorite editor to open `app-config.yaml` and add your PostgreSQL configuration in the root directory of your Backstage app using the credentials from the previous steps.
```yaml title="app-config.yaml"
backend:
@@ -126,6 +118,47 @@ After the Backstage frontend launches, you should notice that nothing has change
We've now made your data persist in your Backstage database.
## Alternatives
You may not want to install Postgres locally, the following sections outline alternatives.
### Docker
You can run Postgres in a Docker container, this is great for local development or getting a Backstage POC up and running quickly, here's how:
First we need to pull down the container image, we'll use Postgres 17, check out the [Postgres Version Policy](../../overview/versioning-policy.md#postgresql-releases) to learn which versions are supported.
```shell
docker pull postgres:17.0-bookworm
```
Then we just need to start up the container.
```shell
docker run -d --name postgres --restart=always -p 5432:5432 -e POSTGRES_PASSWORD=<secret> postgres:17.0-bookworm
```
This will run Postgres in the background for you, but remember to start it up again when you reboot your system.
### Docker Compose
Another way to run Postgres is to use Docker Compose, here's what that would look like:
```yaml title="docker-compose.local.yaml"
version: '4'
services:
postgres:
image: postgres:17.0-bookworm
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: <secret>
ports:
- 5432:5432
```
Then you would just run `docker compose -f docker-compose.local.yaml up` to start Postgres.
## Next Steps
We recommend you read [Setting up authentication](./authentication.md) next.
@@ -136,3 +169,4 @@ If you want to read more about the database configuration, here are some helpful
- [Configuring Plugin Databases](../../tutorials/configuring-plugin-databases.md#privileges)
- [Read more about Knex](http://knexjs.org/), the database wrapper that we use.
- [Install `pgAdmin` 4](https://www.pgadmin.org/), a helpful tool for querying your database.
@@ -4,6 +4,14 @@ title: Configuring App with plugins
description: Documentation on How Configuring App with plugins
---
Audience: Developers
:::note Note
Backstage plugins are primarily written using [TypeScript](https://www.typescriptlang.org), [Node.js](https://nodejs.org) and [React](https://reactjs.org). Having an understanding of these technologies will be beneficial on your journey to customizing Backstage!
:::
## Summary
Backstage plugins customize the app for your needs. There is a
[plugin directory](https://backstage.io/plugins) with plugins for many common
infrastructure needs - CI/CD, monitoring, auditing, and more.
+6 -2
View File
@@ -7,6 +7,10 @@ description: How to install Backstage for your own use.
Audience: Developers and Admins
:::note Note
It is not required, although recommended to have a basic understanding of [Yarn](https://www.pluralsight.com/guides/yarn-a-package-manager-for-node-js) and [npm](https://docs.npmjs.com/about-npm) before starting this guide.
:::
## Summary
This guide walks through how to get started creating your very own Backstage customizable app. This is the first step in evaluating, developing on, or demoing Backstage.
@@ -21,7 +25,7 @@ If you are planning to contribute a new feature or bug fix to the Backstage proj
## Prerequisites
This guide assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `npm`, `yarn`.
This guide also assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `npm`, `yarn`.
- Access to a Unix-based operating system, such as Linux, macOS or
[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/)
@@ -30,7 +34,7 @@ This guide assumes a basic understanding of working on a Linux based operating s
On macOS, you will want to have run `xcode-select --install` to get the XCode command line build tooling in place.
- An account with elevated rights to install the dependencies
- `curl` or `wget` installed
- Node.js [Active LTS Release](https://nodejs.org/en/about/previous-releases) installed using one of these
- Node.js [Active LTS Release](../overview/versioning-policy.md#nodejs-releases) installed using one of these
methods:
- Using `nvm` (recommended)
- [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script)
@@ -4,46 +4,19 @@ title: Keeping Backstage Updated
description: How to keep your Backstage App updated
---
Audience: Developers and Admins
:::note Note
To better understand the concepts in this section, it's recommended to have an understanding of [Monorepos](https://semaphoreci.com/blog/what-is-monorepo), [Semantic Versioning](https://semver.org) and [CHANGELOGs](https://keepachangelog.com).
:::
## Summary
Backstage is always improving, so it's a good idea to stay in sync with the
latest releases. Backstage is more of a library than an application or service;
similar to `create-react-app`, the `@backstage/create-app` tool gives you a
starting point that's meant to be evolved.
## Managing package versions with the Backstage yarn plugin
The Backstage yarn plugin makes it easier to manage Backstage package versions,
by determining the appropriate version for each package based on the overall
Backstage version in backstage.json. This avoids the need to update every
package.json across your Backstage monorepo, and means that when adding new
`@backstage` dependencies, you don't need to worry about figuring out the right
version to use to match the currently-installed release of Backstage.
### Requirements
In order to use the yarn plugin, you'll need to be using yarn 4.1.1 or greater.
### Installation
To install the yarn plugin, run the following command in your Backstage
monorepo:
```bash
yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin
```
The resulting changes in the file system should be committed to your repo.
### Usage
When the yarn plugin is installed, versions for currently-released `@backstage`
packages can be replaced in package.json with the string `"backstage:^"`. This
instructs yarn to resolve the version based on the overall Backstage version in
backstage.json.
The `backstage-cli versions:bump` command documented below will detect the
installation of the yarn plugin, and when it's installed, will automatically
migrate dependencies across the monorepo to use it.
## Updating Backstage versions with backstage-cli
The Backstage CLI has a command to bump all `@backstage` packages and
@@ -57,6 +30,12 @@ yarn backstage-cli versions:bump
The reason for bumping all `@backstage` packages at once is to maintain the
dependencies that they have between each other.
:::tip
To make the version bump process even easier and more streamlined we highly recommend using the [Backstage yarn plugin](#managing-package-versions-with-the-backstage-yarn-plugin)
:::
By default the bump command will upgrade `@backstage` packages to the latest `main` release line which is released monthly. For those in a hurry that want to track the `next` release line which releases weekly can do so using the `--release next` option.
```bash
@@ -87,6 +66,53 @@ for any applicable updates when upgrading packages. As an alternative, the
a consolidated view of all the changes between two versions of Backstage. You
can find the current version of your Backstage installation in `backstage.json`.
## Managing package versions with the Backstage yarn plugin
The Backstage yarn plugin makes it easier to manage Backstage package versions,
by determining the appropriate version for each package based on the overall
Backstage version in `backstage.json`. This avoids the need to update every
package.json across your Backstage monorepo, and means that when adding new
`@backstage` dependencies, you don't need to worry about figuring out the right
version to use to match the currently-installed release of Backstage.
### Requirements
In order to use the yarn plugin, you'll need to be using yarn 4.1.1 or greater.
### Installation
To install the yarn plugin, run the following command in your Backstage
monorepo:
```bash
yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin
```
The resulting changes in the file system should be committed to your repo.
:::tip
For best results it's ideal to add the Backstage Yarn plugin when you are about to do a Backstage upgrade as it will make it easier to confirm everything is working.
:::
### Usage
When the yarn plugin is installed, versions for currently-released `@backstage`
packages can be replaced in package.json with the string `"backstage:^"`. This
instructs yarn to resolve the version based on the overall Backstage version in
`backstage.json`.
:::tip
The `backstage.json` is key for the plugin to work, make sure this file is included in your CI/CD pipelines and/or any Container builds.
:::
The `backstage-cli versions:bump` command documented above will detect the
installation of the yarn plugin, and when it's installed, will automatically
migrate dependencies across the monorepo to use it.
## More information on dependency mismatches
Backstage is structured as a monorepo with
@@ -6,6 +6,10 @@ description: Start populating your Backstage app with your data.
Audience: Developers
:::note Note
Entity files are stored in YAML format, if you are not familiar with YAML, you can learn more about it [here](https://yaml.org).
:::
## Summary
This guide will walk you through how to pull Backstage data from other locations manually. There are integrations that will automatically do this for you.
@@ -0,0 +1,76 @@
---
id: discovery
title: Azure Blob Storage Discovery
sidebar_label: Discovery
# prettier-ignore
description: Automatically discovering catalog entities from an Azure Blob Storage account
---
:::info
This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md).
:::
The Azure Blob Storage account integration has a special entity provider for discovering catalog
entities located in a storage account container. If you have a container that contains multiple
catalog files, and you want to automatically discover them, you can use this
provider. The provider will crawl your Blob Storage account container and register entities
matching the configured path. This can be useful as an alternative to static
locations or manually adding things to the catalog.
To use the entity provider, you'll need an Azure Blob Storage account integration
[set up](locations.md) with `accountName` and either `aadCredential`, `sasToken`, or `accountKey`
At production deployments, you likely manage these with the permissions attached
to your instance.
In your configuration, you add a provider config per bucket:
```yaml
# app-config.yaml
catalog:
providers:
azureBlob:
providerId:
accountName: ${ACCOUNT_NAME}
containerName: ${CONTAINER_NAME}
schedule: # same options as in TaskScheduleDefinition
# supports cron, ISO duration, "human duration" as used in code
frequency: { minutes: 30 }
# supports ISO duration, "human duration" as used in code
timeout: { minutes: 3 }
```
For simple setups, you can omit the provider ID at the config
which has the same effect as using `default` for it.
```yaml
# app-config.yaml
catalog:
providers:
azureBlob:
accountName: ${ACCOUNT_NAME}
containerName: ${CONTAINER_NAME}
schedule: # same options as in TaskScheduleDefinition
# supports cron, ISO duration, "human duration" as used in code
frequency: { minutes: 30 }
# supports ISO duration, "human duration" as used in code
timeout: { minutes: 3 }
```
As this provider is not one of the default providers, you will first need to install
the Azure catalog plugin:
```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure
```
Then updated your backend by adding the following line:
```ts title="packages/backend/src/index.ts"
backend.add(import('@backstage/plugin-catalog-backend'));
/* highlight-add-start */
backend.add(import('@backstage/plugin-catalog-backend-module-azure'));
/* highlight-add-end */
```
@@ -0,0 +1,51 @@
---
id: locations
sidebar_label: Locations
title: Azure Blob Storage account Locations
# prettier-ignore
description: Setting up an integration with Azure Blob Storage account
---
The Azure Blob Storage account integration supports loading catalog entities from an blob storage account container.
Entities can be added to
[static catalog configuration](../../features/software-catalog/configuration.md),
or registered with the
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
plugin.
## Configuration
To use this integration, add configuration to your `app-config.yaml`:
Using Azure active directory credentials:
```yaml
integrations:
azureBlobStorage:
- accountName: ${ACCOUNT_NAME} # required
endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken
aadCredential:
clientId: ${CLIENT_ID}
tenantId: ${TENANT_ID}
clientSecret: ${CLIENT_SECRET}
```
Using Azure storage account SAS token:
```yaml
integrations:
azureBlobStorage:
- accountName: ${ACCOUNT_NAME} # required
endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken
sasToken: ${SAS_TOKEN}
```
Using Azure storage account access key:
```yaml
integrations:
azureBlobStorage:
- accountName: ${ACCOUNT_NAME} # required
endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken
accountKey: ${ACCOUNT_KEY}
```
+2 -2
View File
@@ -170,7 +170,7 @@ catalog:
yourProviderId:
host: gitlab.com
orgEnabled: true
group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped)
group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only this group and groups under the provided path (which will be stripped)
relations: # Optional
- INHERITED # Optional. Members of any ancestor groups will also be considered members of the current group.
- DESCENDANTS # Optional. Members of any descendant groups will also be considered members of the current group.
@@ -240,7 +240,7 @@ catalog:
yourProviderId:
host: gitlab.com ## Could also be self hosted.
orgEnabled: true
group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped)
group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only this group and groups under the provided path (which will be stripped)
restrictUsersToGroup: true # Optional: Backstage will ingest only users directly assigned to org/teams.
includeUsersWithoutSeat: false # Optional: Set to true to include users without paid seat, only applicable for SaaS
```
+1 -1
View File
@@ -385,7 +385,7 @@ Refer to the [service-to-service auth documentation](https://backstage.io/docs/a
An example request for creating a broadcast notification might look like:
```bash
curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_BASE64_SHARED_KEY_TOKEN" -d '{"recipients":{"type":"broadcast"},"payload": {"title": "Title of broadcast message","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}'
curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications/notifications -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_BASE64_SHARED_KEY_TOKEN" -d '{"recipients":{"type":"broadcast"},"payload": {"title": "Title of broadcast message","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}'
```
## Additional info
+8 -8
View File
@@ -94,31 +94,31 @@ Examples of tactics we have used to evangelize Backstage internally:
These are some of the metrics that you can use to verify if Backstage has a
successful impact on your software development process:
- **Onboarding time** Time until new engineers are productive. At Spotify we
- **Onboarding time** - Time until new engineers are productive. At Spotify we
measure this as the time until the employee has merged their 10th PR (this
metric was down 55% two years after deploying Backstage). Even though you may
not be onboarding engineers at a rapid pace, this metric is a great proxy for
the overall complexity of your ecosystem. Reducing it will therefore benefit
your whole engineering organization, not just new joiners.
- **Number of merges per developer/day** Less time spent jumping between
- **Number of merges per developer/day** - Less time spent jumping between
different tools and looking for information means more time to focus on
shipping code. A second level of bottlenecks can be identified if you
categorize contributions by domain (services, web, data, etc).
- **Deploys to production** Cousin to the metric above: How many times does an
- **Deploys to production** - Cousin to the metric above: How many times does an
engineer push changes into production.
- **MTTR** With clear ownership of all the pieces in your microservices
- **MTTR** - With clear ownership of all the pieces in your microservices
ecosystem and all tools integrated into one place, Backstage makes it quicker
for teams to find the root cause of failures, and fix them.
- **Context switching** Reducing context switching can help engineers stay in
- **Context switching** - Reducing context switching can help engineers stay in
the "zone". We measure the number of different tools an engineer has to
interact with in order to get a certain job done (e.g. push a change, follow
it into production and validate it did not break anything).
- **T-shapedness** A
- **T-shapedness** - A
[T-shaped](https://medium.com/@jchyip/why-t-shaped-people-e8706198e437)
engineer is someone that is able to contribute to different domains of
engineering. Teams with T-shaped people have fewer bottlenecks and can
@@ -126,10 +126,10 @@ successful impact on your software development process:
since tools and infrastructure are consistent between domains, and information
is available centrally.
- **eNPS** Surveys asking about how productive people feel, how easy it is to
- **eNPS** - Surveys asking about how productive people feel, how easy it is to
find information and overall satisfaction with internal tools.
- **Fragmentation** _(Experimental)_ Backstage
- **Fragmentation** _(Experimental)_ - Backstage
[Software Templates](../features/software-templates/index.md) help drive
standardization in your software ecosystem. By measuring the variance in
technology between different software components it is possible to get a sense
-3
View File
@@ -323,11 +323,8 @@ backend:
cache:
store: redis
connection: redis://user:pass@cache.example.com:6379
useRedisSets: true
```
The useRedisSets flag is explained [here](https://github.com/jaredwray/keyv/tree/main/packages/redis#useredissets).
Contributions supporting other cache stores are welcome!
## Containerization
+2
View File
@@ -177,6 +177,8 @@ When we say _Supporting_ a Node.js release, that means the following:
- New Backstage projects created with `@backstage/create-app` will have their `engines.node` version set accordingly.
- Dropping compatibility with unsupported releases is not considered a breaking change. This includes using new syntax or APIs, as well as bumping dependencies that drop support for these versions.
Based on the above Backstage supports Node.js 20 and 22 as of the `1.33.0` release.
## TypeScript Releases
The Backstage project uses [TypeScript](https://www.typescriptlang.org/) for type checking within the project, as well as external APIs and documentation. It is important to have a clear policy for which TypeScript versions we support, since we want to be able to adopt new TypeScript features, but at the same time not break existing projects that are using older versions.
@@ -106,15 +106,12 @@ Imagine your FAQs can be retrieved at the URL `https://backstage.example.biz/faq
Below we provide an example implementation of how the FAQ collator factory could look like using our new document type, placed in the `plugins/search-backend-module-faq-snippets-collator/src/factory.ts` file:
```ts
import fetch from 'node-fetch';
import { Readable } from 'stream';
import {
LoggerService,
RootConfigService,
} from '@backstage/backend-plugin-api';
import { DocumentCollatorFactory } from '@backstage/plugin-search-common';
import { FaqSnippetDocument } from './types';
const DEFAULT_BASE_URL = 'https://backstage.example.biz/faq-snippets';
File diff suppressed because it is too large Load Diff
+73
View File
@@ -0,0 +1,73 @@
---
id: v1.33.0
title: v1.33.0
description: Backstage Release v1.33.0
---
These are the release notes for the v1.33.0 release of [Backstage](https://backstage.io/).
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
## Highlights
### Catalog performance improvements and breadcrumbs
Some database improvements and fixes have been made to the catalog. The `refresh_state` table is no longer needed in the read path, and some indices have been dropped. We don't expect this to have any negative impact on end users; rather, performance should increase due to reduced index churn and less used storage.
Entity pages now also by default have a breadcrumb control in the page header, showing the context of the current entity such as what system and domain its in, if any.
### App backend config injection with read-only filesystem
The `app-backend` now stores the templated `index.html` file in memory rather than writing it to disk. This means you no longer need to use the `app.disableConfigInjection` flag when running with a read-only filesystem, allowing you to take advantage of the config injection.
### **BREAKING**: `LEGACY_BACKEND_START` has been removed
The CLI no longer supports the `LEGACY_BACKEND_START` flag, which means that old dev endpoints in `src/run.ts` have to be migrated to the new `dev/index.ts` structure instead.
### Scaffolder now supports Node.js v22
The `isolated-vm` dependency has been upgraded to `v5`, which means the scaffolder now supports Node.js v22. It also means that running Scaffolder with Node.js v16 is no longer possible.
### Scaffolder permissions and actions
A new `scaffolder.template.management` permission has been added. This permission is useful if you want to limit access to the frontend template management features. Contributed by [@stephenglass](https://github.com/stephenglass) in [#26946](https://github.com/backstage/backstage/pull/26946)
A new `fs:readdir` action has been added. This action is useful if you need to retrieve the contents of a specific directory within a workspace. Contributed by [@secustor](https://github.com/secustor) in [#27283](https://github.com/backstage/backstage/pull/27283)
### Catalog service ref for backends
The `@backstage/plugin-catalog-node` package now has a `catalogServiceRef` that backends should move to depending on for their catalog communication needs. If you are currently instantiating a `CatalogService` by hand, you will enjoy using this new service instead. The most important improvement is that it supports a credentials argument directly which gives it support for proper auth toward the catalog without having to make tokens with the `auth` core service.
### New generate-patch cli command
We have added a new `generate-patch` CLI command that can be used to generate patches for current changes in a source workspace, which can then be installed in a target workspace. This allows you to easily and immediately use changes that have been contributed upstream, without needing to wait for a release.
[#27331](https://github.com/backstage/backstage/pull/27331)
### Google LDAP support
Added support for Google LDAP to `@backstage/plugin-catalog-backend-module-ldap`. Contributed by [@megatroom](https://github.com/megatroom) in [#27373](https://github.com/backstage/backstage/pull/27373)
### **BREAKING** AWS ALB authentication
The AWS ALB `fullProfile` will no longer have its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result via `@backstage/plugin-auth-backend-module-aws-alb-provider`.
## Security Fixes
The kubernetes plugin received a bump of the `@kubernetes/client-node` dependency to mitigate CVEs related to the `request` and `tough-cookie` packages. Contributed by [@coreydaley](https://github.com/coreydaley) in [#25385](https://github.com/backstage/backstage/pull/25385)
## Upgrade path
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
## Links and References
Below you can find a list of links and references to help you learn about and start using this new release.
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
- [GitHub repository](https://github.com/backstage/backstage)
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.33.0-changelog.md)
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -57,7 +57,7 @@ After making local changes to a package in an external workspace you might often
For example, if you've made changes to the `@backstage/backend-app-api` package in a local clone of the main `backstage` repository, you can generate a patch for your internal project as follows:
```bash title="Run in the cloned backstage repository"
yarn backstage-repo-tools generate patch @backstage/backend-app-api --target ../our-developer-portal
yarn backstage-repo-tools generate-patch @backstage/backend-app-api --target ../our-developer-portal
```
This will generate a patch file in your `our-developer-portal` workspace. The patch will be based on the most recently released version of the source package, with the additional changes on top.
+6
View File
@@ -4,6 +4,12 @@ title: Migrating from Material UI v4 to v5
description: Additional resources for the Material UI v5 migration guide specifically for Backstage
---
:::info
We are in the process of determining the path forward regarding a New Design System for Backstage, for the time being we recommend pausing any migrations to MUI v5 until this has been settled. More details can be found in ["RFC: New design system for Backstage"](https://github.com/backstage/backstage/issues/27726).
:::
Backstage supports developing new plugins or components using Material UI v5. At the same time, large parts of the application as well as existing plugins will still be using Material UI v4. To support Material UI v4 and v5 at the same time, we have introduced a new concept called the `UnifiedTheme`. The goal of the `UnifiedTheme` is to allow gradual migration by running both versions in parallel, applying theme options similarly & supporting potential future versions of Material UI.
By default, the `UnifiedThemeProvider` is already used. If you add a custom theme in your `createApp` function, you would need to replace the Material UI `ThemeProvider` with the `UnifiedThemeProvider`:
+8
View File
@@ -66,6 +66,14 @@ You can now start your Backstage instance as usual, using `yarn dev`.
## Production Setup
In your `.dockerignore`, add this line:
```
!packages/backend/src/instrumentation.js
```
This ensures that Docker build will not ignore the instrumentation file if you are following the recommended `.dockerignore` setup.
In your `Dockerfile`, copy `instrumentation.js` file into the root of the working directory.
```Dockerfile