Merge pull request #5337 from backstage/timbonicus/deployment-docs

Move deployment documentation to its own section
This commit is contained in:
Tim
2021-04-15 10:25:28 -06:00
committed by GitHub
8 changed files with 623 additions and 71 deletions
-238
View File
@@ -1,238 +0,0 @@
---
id: deployment-docker
title: Docker
description: Documentation on how to deploy Backstage as a Docker image
---
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 its speed and more efficient and often simpler caching.
The second section covers a full multi-stage Docker build, and the last section
covers how to split frontend content into a separate image.
Something that goes for all of these docker deployment strategies is that they
are stateless, so for a production deployment you will want to set up and
connect to an external PostgreSQL instance where the backend plugins can store
their state, rather than using SQLite.
By default, in an app created with `@backstage/create-app`, the frontend is
bundled and served from the backend. This is done using the
`@backstage/plugin-app-backend` plugin, which also injects the frontend
configuration into the app. This means you that you only need to build and
deploy a single container in a minimal setup of Backstage. If you wish to
separate the serving of the frontend out from the backend, see
[the section on that topic below](#separate-frontend).
### Host Build
This section describes how to build a Docker image from a Backstage repo with
most of the build happening outside of Docker. This is almost always the faster
approach, as the build steps tend to execute faster, and it's possible to have
more efficient caching of dependencies on the host, where a single change won't
bust the entire cache.
The required steps in the host build are to install dependencies with
`yarn install`, generate type definitions using `yarn tsc`, and build all
packages with `yarn build`.
> NOTE: If you created your app prior to 2021-02-18, follow the
> [migration step](https://github.com/backstage/backstage/releases/tag/release-2021-02-18)
> to move from `backend:build` to `backend:bundle`.
In a CI workflow it might look something like this:
```bash
yarn install --frozen-lockfile
# tsc outputs type definitions to dist-types/ in the repo root, which are then consumed by the build
yarn tsc
# Build all packages and in the end bundle them all up into the packages/backend/dist folder.
yarn build
```
Once the host build is complete, we are ready to build our image. The following
`Dockerfile` is included when creating a new app with `@backstage/create-app`:
```Dockerfile
FROM node:14-buster-slim
WORKDIR /app
# 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.
ADD yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)"
# Then copy the rest of the backend bundle, along with any other files we might want.
ADD packages/backend/dist/bundle.tar.gz app-config.yaml ./
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
```
For more details on how the `backend:bundle` command and the `skeleton.tar.gz`
file works, see the
[`backend:bundle` command docs](../cli/commands.md#backendbundle).
The `Dockerfile` is located at `packages/backend/Dockerfile`, but needs to be
executed with the root of the repo as the build context, in order to get access
to the root `yarn.lock` and `package.json`, along with any other files that
might be needed, such as `.npmrc`.
The `@backstage/create-app` command adds the following `.dockerignore` in the
root of the repo to speed up the build by reducing build context size:
```text
.git
node_modules
packages
!packages/backend/dist
plugins
```
With the project built and the `.dockerignore` and `Dockerfile` in place, we are
now ready to build the final image. From the root of the repo, execute the
build:
```bash
docker image build . -f packages/backend/Dockerfile --tag backstage
```
To try out the image locally you can run the following:
```sh
docker run -it -p 7000:7000 backstage
```
You should then start to get logs in your terminal, and then you can open your
browser at `http://localhost:7000`
### Multistage Build
This section describes how to set up a multi-stage Docker build that builds the
entire project within Docker. This is typically slower than a host build, but is
sometimes desired because Docker in Docker is not available in the build
environment, or due to other requirements.
The build is split into three different stages, where the first stage finds all
of the `package.json`s that are relevant for the initial install step enabling
us to cache the initial `yarn install` that installs all dependencies. The
second stage executes the build itself, and is similar to the steps we execute
on the host in the host build. The third and final stage then packages it all
together into the final image, and is similar to the `Dockerfile` of the host
build.
The following `Dockerfile` executes the multi-stage build and should be added to
the repo root:
```Dockerfile
# Stage 1 - Create yarn install skeleton layer
FROM node:14-buster-slim AS packages
WORKDIR /app
COPY package.json yarn.lock ./
COPY packages packages
COPY plugins plugins
RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -exec rm -rf {} \+
# Stage 2 - Install dependencies and build packages
FROM node:14-buster-slim AS build
WORKDIR /app
COPY --from=packages /app .
RUN yarn install --frozen-lockfile --network-timeout 600000 && rm -rf "$(yarn cache dir)"
COPY . .
RUN yarn tsc
RUN yarn --cwd packages/backend backstage-cli backend:bundle --build-dependencies
# Stage 3 - Build the actual backend image and install production dependencies
FROM node:14-buster-slim
WORKDIR /app
# Copy the install dependencies from the build stage and context
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 yarn install --frozen-lockfile --production --network-timeout 600000 && rm -rf "$(yarn cache dir)"
# Copy the built packages from the build stage
COPY --from=build /app/packages/backend/dist/bundle.tar.gz .
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
# Copy any other files that we need at runtime
COPY app-config.yaml ./
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
```
Note that a newly created Backstage app will typically not have a `plugins/`
folder, so you will want to comment that line out. This build also does not work
in the main repo, since the `backstage-cli` which is used for the build doesn't
end up being properly installed.
To speed up the build when not running in a fresh clone of the repo you should
set up a `.dockerignore`. This one is different than the host build one, because
we want to have access to the source code of all packages for the build, but can
ignore any existing build output or dependencies:
```text
node_modules
packages/*/dist
packages/*/node_modules
plugins/*/dist
plugins/*/node_modules
```
Once you have added both the `Dockerfile` and `.dockerignore` to the root of
your project, run the following to build the container under a specified tag.
```sh
docker image build -t backstage .
```
To try out the image locally you can run the following:
```sh
docker run -it -p 7000:7000 backstage
```
You should then start to get logs in your terminal, and then you can open your
browser at `http://localhost:7000`
### Separate Frontend
It is sometimes desirable to serve the frontend separately from the backend,
either from a separate image or for example a static file serving provider. The
first step in doing so is to remove the `app-backend` plugin from the backend
package, which is done as follows:
1. Delete `packages/backend/src/plugins/app.ts`
2. Remove the following lines from `packages/backend/src/index.ts`:
```tsx
import app from './plugins/app';
// ...
const appEnv = useHotMemoize(module, () => createEnv('app'));
// ...
.addRouter('', await app(appEnv));
```
3. Remove the `@backstage/plugin-app-backend` and the app package dependency
(e.g. `app`) from `packages/backend/packages.json`. If you don't remove the
app package dependency the app will still be built and bundled with the
backend.
Once the `app-backend` is removed from the backend, you can use your favorite
static file serving method for serving the frontend. An example of how to set up
an NGINX image is available in the
[contrib folder in the main repo](https://github.com/backstage/backstage/blob/master/contrib/docker/frontend-with-nginx/Dockerfile)
Note that if you're building a separate docker build of the frontend you
probably need to adjust `.dockerignore` appropriately. Most likely by making
sure `packages/app/dist` is not ignored.
-64
View File
@@ -1,64 +0,0 @@
---
id: deployment-helm
title: Helm
description: Documentation on Kubernetes and Helm Deployment
sidebar_label: Kubernetes and Helm
---
# Helm charts
An example Backstage app can be deployed in Kubernetes using the
[Backstage Helm charts](https://github.com/backstage/backstage/tree/master/contrib/chart/backstage).
First, choose a DNS name where Backstage will be hosted, and create a YAML file
for your custom configuration.
```yaml
appConfig:
app:
baseUrl: https://backstage.mydomain.com
title: Backstage
backend:
baseUrl: https://backstage.mydomain.com
cors:
origin: https://backstage.mydomain.com
lighthouse:
baseUrl: https://backstage.mydomain.com/lighthouse-api
techdocs:
storageUrl: https://backstage.mydomain.com/api/techdocs/static/docs
requestUrl: https://backstage.mydomain.com/api/techdocs
```
Then use it to run:
```bash
git clone https://github.com/backstage/backstage.git
cd backstage/contrib/chart/backstage
helm dependency update
helm install -f backstage-mydomain.yaml backstage .
```
This command will deploy the following pieces:
- Backstage frontend
- Backstage backend with scaffolder and auth plugins
- (optional) a PostgreSQL instance
- lighthouse plugin
- ingress
After a few minutes Backstage should be up and running in your cluster under the
DNS specified earlier.
Make sure to create the appropriate DNS entry in your infrastructure. To find
the public IP address run:
```bash
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
backstage-ingress * 123.1.2.3 80 17m
```
> **NOTE**: this is not a production ready deployment.
For more information on how to customize the deployment check the
[README](https://github.com/backstage/backstage/tree/master/contrib/chart/backstage/README.md).
-13
View File
@@ -1,13 +0,0 @@
---
id: deployment-k8s
title: Kubernetes
description: Documentation on Kubernetes and K8s Deployment
---
Backstage itself provides tooling up to the point of building Docker images.
Beyond that point we do not have an opinionated way to deploy Backstage within
Kubernetes, as each cluster has its own unique set of tooling and patterns.
We do provide examples to help you get started though. Check out
[this example](https://github.com/backstage/backstage/tree/master/contrib/kubernetes/plain_single_backend_deployment/)
for a basic single-deployment setup.
-35
View File
@@ -1,35 +0,0 @@
---
id: deployment-other
title: Other
description: Documentation on different ways of Deployment
---
## Heroku
Deploying to Heroku is relatively easy following these steps.
First, make sure you have the
[Heroku CLI installed](https://devcenter.heroku.com/articles/heroku-cli) and log
into it as well as login into Heroku's
[container registry](https://devcenter.heroku.com/articles/container-registry-and-runtime).
```bash
$ heroku login
$ heroku container:login
```
You _might_ also need to set your Heroku app's stack to `container`.
```bash
$ heroku stack:set container -a <your-app>
```
We can now build/push the Docker image to Heroku's container registry and
release it to the `web` worker.
```bash
$ heroku container:push web -a <your-app>
$ heroku container:release web -a <your-app>
```
With that, you should have Backstage up and running!