These days I have been playing with Backstage to see how it fits into platform engineering. The truth is that it has not been very easy for me to get started and that is why today I want to share with you some of the things that I have been configuring to test the three points that seem to me to be the most important: the creating backstage app, catalogue, and templates.
This article was first published here
Setting up a Dev Container for Backstage
For a long time now, I have been trying to make sure that all the configurations that a specific project needs are not done directly on my local server, but instead I use a Dev Container to configure everything I need. In the case of Backstage, you need version 18 or 20 of Node.js for it to work correctly, as well as a Postgresql database if you want to simulate the same behavior that it will potentially have in a production environment (when you create your Backstage project, it uses an in-memory database). Therefore, before starting to create what is necessary for Backstage, I created an empty directory, which I called backstage-demo, and added the file .devcontainer/devcontainer.json with the following configuration:
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/debian
{
"name": "Spotify Backstage Dev Container",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// "image": "mcr.microsoft.com/devcontainers/base:bullseye",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "18",
"nvmVersion": "latest"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"forwardPorts": [
3000,
7007,
8080
],
"containerEnv": {
"POSTGRES_HOST": "db",
"POSTGRES_PORT": "5432",
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "example"
},
"customizations": {
"vscode": {
"extensions": [
"ms-ossdata.vscode-postgresql"
]
}
}
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
This in turn makes use of a configuration for Docker Compose, stored in the path .devcontainer/docker-compose.yml, which allows us to configure a database along with the workspace of the project that I am going to show you.
version: "3.8"
services:
app:
image: mcr.microsoft.com/devcontainers/base:bullseye
volumes:
- ../..:/workspaces:cached
command: sleep infinity
networks:
- backstage
db:
image: postgres
environment:
POSTGRES_PASSWORD: example
networks:
- backstage
ports:
- 5432:5432
networks:
backstage:
Creating your Backstage App
Backstage is actually a React application that is initially composed of two parts: a front end and a back end. You must create it, maintain it, and host it somewhere, which I will show you in another article later. Once you are inside your Dev Container, run the following command to create it:
npx @backstage/create-app@latest
This process will take several minutes to complete as it has a lot of dependencies to download. Once it finishes, you can run the same with the following:
cd backstage && yarn dev
Congratulations 🎉! You now have your Backstage instance up and running. Now all that’s left is to do the rest Read on to learn how to configure the database, GitHub integration, etc…
Setting up the database for Backstage
When you create your Backstage it uses a SQLite database to store the information, which is fine for a development environment. However, to get as close to production as possible we can make it connect to the Postgres we have started as part of our Dev Container. The Postgres client is already installed, but I recommend updating it with this command:
# From your Backstage root directory
yarn --cwd packages/backend add pg
When it comes to configuration, Backstage makes use of a file called app-config.*.yaml. Ideally, you should not store sensitive information in these, since they will be versioned along with your code, so you should preferably mention environment variables in them. If you don’t want/can’t at this stage, the ideal is to use the file called app-config.local.yaml, which is part of the .gitignore file, and you will be safe from being uploaded as part of your code, and this overwrites the app-config.yaml file… but you will not store the configuration you have made along with your repo and you may forget at some point. For the database, we are going to modify the one called app-config.yaml, so that it is part of my repo, in the database section with the following:
database:
# client: better-sqlite3
# connection: ':memory:'
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
As you can see, I have commented out the two lines above, client and connection, to replace them with the necessary configuration for Postgres. In my example, these values will be taken from the environment variables established in the configuration I made at the beginning for my Dev Container.
Sign in to Backstage with your GitHub account
If you do decide to have an IDP in your company, you will most likely want to integrate it with your identity provider. In this article I will show you how this would be done with GitHub so that you can see what the process would be like. First, you need to modify the backstage/packages/app/src/App.tsx file. You need to add a couple of additional imports, as well as the login configuration for GitHub.
mport {
SignInProviderConfig
} from '@backstage/core-components';
import { githubAuthApiRef } from '@backstage/core-plugin-api';
const githubProvider: SignInProviderConfig = {
id: 'github-auth-provider',
title: 'GitHub',
message: 'Sign in using GitHub',
apiRef: githubAuthApiRef,
};
Once you have it, inside createApp you have a section called components where it is necessary to modify the SigInPage property as follows:
// components: {
// SignInPage: props => <SignInPage {...props} auto providers={['guest']} />,
// },
components: {
SignInPage: props => (
<SignInPage
{...props}
auto
provider={githubProvider}
/>
),
},
Here, as you can see, I have changed the guest provider to the one called githubProvider, which is the configuration you defined above.
Once you have the React part ready, the next step is to create an OAuth App in your GitHub account here: https://github.com/settings/applications/new. In this you must configure the following:
Home URL: http://localhost:3000
Authorization callback URL: http://localhost:7007/api/auth/github
Retrieve the client id and generate a client secret to configure this provider in your Backstage. Again, you can add this configuration in the app-config.yaml file using environment variables or you can use the a file for these tests with the following information:
# Backstage override configuration for your local development environment
auth:
# see https://backstage.io/docs/auth/ to learn about auth providers
environment: development
providers:
guest: {}
github:
development:
clientId: <YOUR_CLIENT_ID>
clientSecret: <YOUR_SECRET_ID>
signIn:
resolvers:
- resolver: usernameMatchingUserEntityName
For this provider to work, you must add the module that corresponds to it in the packages/backend/src/index.ts file in the //auth login section:
// auth plugin
backend.add(import('@backstage/plugin-auth-backend'));
// See https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin
// backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
// See https://github.com/backstage/backstage/blob/master/docs/auth/guest/provider.md
// For github login
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
and then finally, for this example, you need to modify the examples/org.yaml file with your GitHub user. Here is an example of what it would look like with mine:
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user
apiVersion: backstage.io/v1alpha1
kind: User
metadata:
name: guest
spec:
memberOf: [guests]
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user
apiVersion: backstage.io/v1alpha1
kind: User
metadata:
name: 0GiS0
spec:
memberOf: [guests]
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
name: guests
spec:
type: team
children: []
If you now restart the application you will see that you can now log in with your GitHub account in your Backstage portal 🎉 Now let’s see some of the main functionalities of this.
Component catalog
One of the main goals of an IDP is to have an inventory of what the developer has in their ecosystem. A catalog where they can see what components already exist, how they relate to each other, who owns them within the organization, etc. In Backstage we can see them directly in the Home section (which if you look at the path leads to /catalog).
The first thing you need to know is that for a component to be a Backstage component it has to have a file that collects the necessary information about it. This file is called catalog-info.yaml and is usually located in the root of the repositories:
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: xyz-api
description: XYZ API is a RESTful API that provides manages XYZ.
tags:
- dotnet
- data
links:
- url: link to the repo
title: Source Code
icon: github
- url: https://api.xyz.com
title: Production
icon: globe
annotations:
# this could also be `url:<url>` if the documentation isn't in the same location
backstage.io/techdocs-ref: dir:.
spec:
type: service
lifecycle: production
owner: talha101
system: xyz
dependsOn: ['resource:xyz-db']
apiConsumedBy: ['component:www-xyz']
It is in YAML format, so that it is easy to maintain, and it gives the name to the component, as well as other metadata, such as labels, related links, etc. On the other hand, in the spec section we can indicate the type of component it is, in this case a service, the life cycle, the owner, which system (application) it belongs to, among other things.
Now, how do I include this component in my Backstage portal? From the Home section or in the side menu itself, you have the Create option. When you click on it, you will go to a section where you also have an option that says Register Existing Component:
Software templates and integration with GitHub
To finish this extra long article, another of the strong points of an IDP, and often the one that is given the most importance, is that it allows us to use project templates to deploy them directly from these developer portals. In this case I have tested the integration with GitHub so that this is the destination of these templates.
In the latest versions of Backstage they have tried to make it more modular in order to not have to load absolutely everything if you don’t really need it. So the first thing you need to do is modify the backstage/packages/backend/src/index.ts file to register this integration with the following line:
// github integration
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
On the other hand, you need a PAT (using fine-grained personal access tokens) with Read & Write scopes for the Contents, Administration and Workflows sections. Once you have it, you need to modify the app-config.local.yaml file again with this other section:
integrations:
github:
- host: github.com
# This is a Personal Access Token or PAT from GitHub. You can find out how to generate this token, and more information
# about setting up the GitHub integration here: https://backstage.io/docs/integrations/github/locations#configuration
token: github_pat_XXXX
Note: this can also be achieved (and is recommended in a production environment) by using GitHub Apps, but for this first local contact a PAT is more than enough.
And now, so you can test that this works as expected, you can use the example template called Example Node.js Template, which you can find in the Create section. Once you complete the wizard, the result will be something like the following:
and you’ll see that you have a new repository in your GitHub account using the Backstage example template. Until next post. Greetings!