Merge branch 'master' into nikolarAutodesk/makeTechDocsCustomizable
Signed-off-by: Reyna Nikolayev <146387693+nikolarAutodesk@users.noreply.github.com>
This commit is contained in:
@@ -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.
|
||||
@@ -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).
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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']);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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}
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 it’s 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.
|
||||
|
||||
@@ -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`:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user