Ein internes Developer Portal mit Backstage auf Azure aufbauen: Ein praktischer Leitfaden
Ein praktischer Leitfaden zur Bereitstellung von Spotify Backstage auf Azure, einschließlich AKS- und Container Apps-Hosting, Catalog-Setup, Software Templates, TechDocs, Azure DevOps-Integration, Entra ID-Authentifizierung und Custom Plugins.
Der durchschnittliche Enterprise-Entwickler verbringt 60 Minuten pro Tag mit der Suche nach Informationen: Welches Team ist für einen Service verantwortlich, wo liegt die API-Dokumentation, wie erstellt man einen neuen Microservice, der die Compliance-Anforderungen erfüllt. Multipliziert man das über 200 Ingenieure, verliert man 200 Stunden Engineering-Produktivität jeden einzelnen Tag.
Backstage, das von Spotify entwickelte Open-Source Developer Portal, löst dieses Problem durch eine einheitliche Oberfläche für das gesamte Software-Ökosystem. Die Bereitstellung auf Azure in einem Enterprise-Kontext erfordert jedoch mehr als npx @backstage/create-app auszuführen. Dieser Leitfaden behandelt die Architekturentscheidungen, Deployment-Patterns und Integrationspunkte, die in der Produktion wichtig sind.
Backstage Architekturübersicht
Bevor Sie irgendetwas bereitstellen, müssen Sie verstehen, was Backstage unter der Haube tatsächlich ist.
Backstage besteht aus drei Schichten:
Core — Die App-Shell, das Plugin-System und die integrierten Features (Catalog, Scaffolder, TechDocs). Das bekommen Sie direkt nach der Installation.
Plugins — Community- und Custom Plugins, die die Funktionalität erweitern. Von Kubernetes-Dashboards bis hin zu Kostenmanagement-Ansichten. Plugins haben Frontend-Komponenten (React) und optionale Backend-Komponenten (Express).
App — Ihre spezifische Backstage-Instanz mit Konfiguration, Theming und der Auswahl installierter Plugins.
Das Backend läuft als Node.js-Anwendung mit einer PostgreSQL-Datenbank. Das Frontend ist eine React Single-Page-Application, die entweder vom Backend oder über ein CDN ausgeliefert wird. In der Produktion deployen Sie beides zusammen als einen einzelnen Container oder trennen sie für unabhängige Skalierung.
Azure Hosting wählen: AKS vs. Container Apps
Dies ist die erste Entscheidung, die alles Weitere bestimmt.
Azure Kubernetes Service (AKS)
Verwenden Sie AKS, wenn:
- Sie bereits AKS-Cluster betreiben und ein Platform Team haben, das mit Kubernetes vertraut ist
- Sie feingranulare Kontrolle über das Netzwerk benötigen (Private Clusters, Custom DNS, Service Mesh)
- Ihre Backstage Plugins Persistent Volumes oder komplexe Sidecar-Patterns benötigen
- Sie umfangreiche Plugin-Anpassungen mit mehreren Backend-Services planen
# backstage-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backstage
namespace: backstage
spec:
replicas: 2
selector:
matchLabels:
app: backstage
template:
metadata:
labels:
app: backstage
spec:
serviceAccountName: backstage-sa
containers:
- name: backstage
image: myacr.azurecr.io/backstage:1.24.0
ports:
- containerPort: 7007
envFrom:
- secretRef:
name: backstage-secrets
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
readinessProbe:
httpGet:
path: /healthcheck
port: 7007
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthcheck
port: 7007
initialDelaySeconds: 60
periodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: backstage
namespace: backstage
spec:
selector:
app: backstage
ports:
- port: 80
targetPort: 7007
type: ClusterIPKombinieren Sie dies mit einem NGINX Ingress Controller oder Azure Application Gateway Ingress Controller für TLS-Terminierung und externen Zugriff.
Azure Container Apps
Verwenden Sie Container Apps, wenn:
- Sie minimalen operativen Aufwand wünschen und Ihr Team kein Kubernetes verwaltet
- Ihre Backstage-Instanz weniger als 500 Entwickler bedient
- Sie ein schnelles Setup mit integriertem TLS, Skalierung und Revision Management benötigen
resource backstageApp 'Microsoft.App/containerApps@2023-05-01' = {
name: 'backstage'
location: location
properties: {
managedEnvironmentId: containerAppEnv.id
configuration: {
ingress: {
external: true
targetPort: 7007
transport: 'http'
}
secrets: [
{
name: 'postgres-connection'
value: postgresConnectionString
}
{
name: 'azure-client-secret'
value: entraIdClientSecret
}
]
}
template: {
containers: [
{
name: 'backstage'
image: '${acrName}.azurecr.io/backstage:1.24.0'
resources: {
cpu: json('1.0')
memory: '2Gi'
}
env: [
{ name: 'POSTGRES_HOST', value: postgresHost }
{ name: 'POSTGRES_PORT', value: '5432' }
{ name: 'POSTGRES_USER', value: postgresUser }
{
name: 'POSTGRES_PASSWORD'
secretRef: 'postgres-connection'
}
]
}
]
scale: {
minReplicas: 1
maxReplicas: 3
rules: [
{
name: 'http-scaling'
http: { metadata: { concurrentRequests: '50' } }
}
]
}
}
}
}Verwenden Sie für beide Optionen Azure Database for PostgreSQL Flexible Server als Backend-Datenbank. Aktivieren Sie Private Endpoint-Zugriff und deaktivieren Sie den öffentlichen Netzwerkzugang.
Den Software Catalog einrichten
Der Catalog ist das Herzstück von Backstage. Ohne einen gut gepflegten Catalog haben Sie eine teure leere Hülle.
Catalog-Struktur
Backstage-Entities folgen einem Standard-YAML-Format. Jedes Repository sollte eine catalog-info.yaml im Root-Verzeichnis enthalten:
# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Verarbeitet Zahlungen und Transaktionsmanagement
annotations:
dev.azure.com/project-repo: MyOrg/payment-service
backstage.io/techdocs-ref: dir:.
sonarqube.org/project-key: payment-service
tags:
- dotnet
- payments
- tier-1
links:
- url: https://dev.azure.com/MyOrg/Payments/_dashboards
title: Azure DevOps Dashboard
icon: dashboard
spec:
type: service
lifecycle: production
owner: team-payments
system: payment-platform
providesApis:
- payment-api
consumesApis:
- customer-api
- notification-api
dependsOn:
- resource:payment-database
- resource:payment-servicebusAuto-Discovery mit Azure DevOps
Anstatt jedes Repository manuell zu registrieren, konfigurieren Sie den Azure DevOps Provider für die automatische Erkennung von catalog-info.yaml-Dateien:
# app-config.production.yaml
catalog:
providers:
azureDevOps:
yourOrgName:
organization: https://dev.azure.com/YourOrg
project: '*'
repository: '*'
path: /catalog-info.yaml
schedule:
frequency: { minutes: 30 }
timeout: { minutes: 3 }
rules:
- allow:
- Component
- System
- API
- Resource
- Group
- UserDies scannt alle Projekte und Repositories alle 30 Minuten. Neue Services erscheinen automatisch in Backstage, sobald sie eine catalog-info.yaml hinzufügen.
Software Templates: Scaffolding das Standards durchsetzt
Software Templates sind der Bereich, in dem sich Backstage amortisiert. Anstatt dass Entwickler ein altes Projekt kopieren und die Geschäftslogik entfernen, füllen sie ein Formular aus und erhalten ein neues Repository, das vom ersten Tag an alle organisatorischen Standards erfüllt.
# templates/dotnet-microservice/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: dotnet-microservice
title: .NET Microservice
description: Erstellt einen neuen .NET 9 Microservice mit CI/CD, SonarQube und Infrastruktur
tags:
- dotnet
- microservice
- recommended
spec:
owner: team-platform
type: service
parameters:
- title: Service-Informationen
required: [name, description, owner]
properties:
name:
title: Service Name
type: string
pattern: '^[a-z][a-z0-9-]*$'
ui:help: 'Kleinbuchstaben mit Bindestrichen. Beispiel: payment-processor'
description:
title: Beschreibung
type: string
maxLength: 200
owner:
title: Verantwortliches Team
type: string
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Technische Optionen
properties:
database:
title: Datenbank
type: string
enum: ['none', 'postgresql', 'cosmos-db']
default: 'none'
messaging:
title: Messaging
type: string
enum: ['none', 'servicebus', 'eventhub']
default: 'none'
steps:
- id: fetch
name: Skeleton abrufen
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
database: ${{ parameters.database }}
messaging: ${{ parameters.messaging }}
- id: publish
name: Repository erstellen
action: publish:azure
input:
allowedHosts: ['dev.azure.com']
repoUrl: >-
dev.azure.com?organization=YourOrg&project=Services&repo=${{ parameters.name }}
description: ${{ parameters.description }}
- id: register
name: Im Catalog registrieren
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
output:
links:
- title: Repository
url: ${{ steps['publish'].output.remoteUrl }}
- title: In Backstage öffnen
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }}Das Skeleton-Verzeichnis enthält ein vollständiges Projekttemplate mit Dockerfile, CI/CD-Pipeline, Terraform-Modulen und vorkonfigurierter SonarQube-Analyse. Jeder neue Service startet korrekt.
TechDocs-Integration
TechDocs wandelt Markdown-Dateien in Ihren Repositories in eine durchsuchbare Dokumentationsseite innerhalb von Backstage um. Keine separate Dokumentationsplattform erforderlich.
Konfiguration für Azure Blob Storage
Verwenden Sie in der Produktion das "recommended" Deployment, bei dem TechDocs in CI/CD erstellt und in Azure Blob Storage veröffentlicht werden:
# app-config.production.yaml
techdocs:
builder: 'external'
generator:
runIn: 'local'
publisher:
type: 'azureBlobStorage'
azureBlobStorage:
containerName: 'techdocs'
credentials:
accountName: ${TECHDOCS_STORAGE_ACCOUNT}
accountKey: ${TECHDOCS_STORAGE_KEY}CI/CD-Pipeline für TechDocs
Fügen Sie dies der Pipeline jedes Repositories hinzu, um Dokumentation beim Merge zu veröffentlichen:
# azure-pipelines.yml (TechDocs-Stage)
- stage: PublishDocs
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- job: TechDocs
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.11'
- script: |
pip install mkdocs-techdocs-core
npx @techdocs/cli generate --no-docker
npx @techdocs/cli publish \
--publisher-type azureBlobStorage \
--storage-name $(TECHDOCS_STORAGE_ACCOUNT) \
--azureAccountKey $(TECHDOCS_STORAGE_KEY) \
--entity default/component/$(SERVICE_NAME)
displayName: 'TechDocs generieren und veröffentlichen'Authentifizierung mit Microsoft Entra ID
Enterprise Backstage muss sich mit Ihrem Identity Provider integrieren. Für Azure-Umgebungen bedeutet das Entra ID (ehemals Azure AD).
# app-config.production.yaml
auth:
environment: production
providers:
microsoft:
production:
clientId: ${AZURE_CLIENT_ID}
clientSecret: ${AZURE_CLIENT_SECRET}
tenantId: ${AZURE_TENANT_ID}
domainHint: yourcompany.com
additionalScopes:
- Mail.ReadKonfigurieren Sie die Anmeldeseite so, dass Microsoft der einzige Provider ist:
// packages/app/src/App.tsx
import { microsoftAuthApiRef } from '@backstage/core-plugin-api';
const app = createApp({
// ...
components: {
SignInPage: props => (
<SignInPage
{...props}
auto
provider={{
id: 'microsoft',
title: 'Microsoft',
message: 'Mit Ihrem Unternehmenskonto anmelden',
apiRef: microsoftAuthApiRef,
}}
/>
),
},
});Mappen Sie Entra ID-Gruppen auf Backstage-Teams über den Microsoft Graph Org Provider:
catalog:
providers:
microsoftGraphOrg:
default:
tenantId: ${AZURE_TENANT_ID}
clientId: ${AZURE_CLIENT_ID}
clientSecret: ${AZURE_CLIENT_SECRET}
groupFilter: startswith(displayName, 'team-')
userFilter: accountEnabled eq true
schedule:
frequency: { hours: 1 }
timeout: { minutes: 5 }Custom Plugins: Backstage für Ihre Anforderungen erweitern
Standardmäßig enthaltene Plugins decken viele Anwendungsfälle ab, aber Enterprise-Umgebungen haben immer individuelle Anforderungen. Hier ist die Struktur eines einfachen Plugins, das Azure-Kostendaten für jeden Service anzeigt:
// plugins/azure-costs/src/components/CostOverview.tsx
import React from 'react';
import { useEntity } from '@backstage/plugin-catalog-react';
import { useApi, configApiRef } from '@backstage/core-plugin-api';
import {
InfoCard,
Progress,
ResponseErrorPanel,
} from '@backstage/core-components';
export const CostOverview = () => {
const { entity } = useEntity();
const config = useApi(configApiRef);
const resourceGroup =
entity.metadata.annotations?.['azure.com/resource-group'];
const { data, loading, error } = useCostData(resourceGroup);
if (loading) return <Progress />;
if (error) return <ResponseErrorPanel error={error} />;
return (
<InfoCard title="Azure-Kosten (Letzte 30 Tage)">
<Typography variant="h4">
{data.currency} {data.totalCost.toFixed(2)}
</Typography>
<CostBreakdownChart data={data.breakdown} />
</InfoCard>
);
};Registrieren Sie es als Entity Tab, damit es auf jeder Service-Seite erscheint, die die azure.com/resource-group Annotation hat.
Adoptionsstrategie: Backstage nachhaltig verankern
Die Bereitstellung von Backstage ist der einfache Teil. 200 Entwickler dazu zu bringen, es tatsächlich zu nutzen, ist schwer.
Phase 1: Catalog befüllen (Wochen 1-4) — Verwenden Sie Auto-Discovery, um den Catalog mit jedem Repository zu füllen. Selbst ohne catalog-info.yaml-Dateien importieren Sie Repositories als nicht zugeordnete Components. Allein die Sichtbarkeit bietet bereits Mehrwert.
Phase 2: Software Templates (Wochen 4-8) — Erstellen Sie Templates für Ihre zwei oder drei häufigsten Projekttypen. Jeder neue Service muss über Backstage erstellt werden. Dies schafft einen Adoptionszwang.
Phase 3: TechDocs-Migration (Wochen 8-12) — Migrieren Sie Dokumentation von Confluence oder SharePoint in TechDocs. Entwickler suchen zuerst in Backstage, finden Antworten und entwickeln die Gewohnheit.
Phase 4: Custom Plugins (Wochen 12-20) — Bauen Sie Plugins, die Daten anzeigen, die Entwickler bereits benötigen: Deployment-Status, Kosten-Dashboards, Security-Findings. Machen Sie Backstage zur zentralen Anlaufstelle.
Phase 5: Alternativen abschaffen (Wochen 20+) — Entfernen Sie eigenständige Dashboards, Wikis und Portale, die Backstage ersetzt. Wenn die alten Tools noch existieren, werden Entwickler sie aus Gewohnheit weiternutzen.
Wann Backstage überdimensioniert ist
Backstage ist nicht immer die richtige Antwort.
Kleine Organisationen (weniger als 50 Ingenieure) — Der Aufwand für die Wartung einer Backstage-Instanz, das Schreiben von Plugins und die Pflege des Catalogs übersteigt die Navigationskosten, die es eliminiert. Ein gut organisiertes Wiki und ein CI/CD-Dashboard decken die meisten Bedürfnisse ab.
Single-Product-Teams — Wenn alle am selben Produkt mit demselben Tech Stack arbeiten, existiert das "Discovery"-Problem, das Backstage löst, nicht. Man weiß bereits, was vorhanden ist.
Kein Platform Team — Backstage erfordert laufende Wartung. Plugin-Updates, Backstage-Versionsupgrades, Catalog-Pflege. Ohne ein dediziertes Platform Team (auch nur 1-2 Ingenieure) wird Backstage veraltet und aufgegeben.
Compliance-lastige Umgebungen ohne Anpassungsbudget — Backstage erfüllt standardmäßig die meisten Enterprise-Compliance-Anforderungen nicht. Custom Auth, Audit Logging und Access Control Plugins erfordern Entwicklungsaufwand.
Produktions-Checkliste
Vor dem Go-Live überprüfen:
- PostgreSQL verwendet Private Endpoints mit erzwungenem TLS
- Backstage läuft hinter Azure Application Gateway oder Front Door mit WAF
- Entra ID-Authentifizierung ist die einzige Anmeldemethode
- Container Images werden gescannt und aus einer privaten ACR gezogen
- TechDocs-Speicher verwendet Managed Identity für den Zugriff (keine Storage Keys)
- Catalog Auto-Discovery läuft planmäßig und erkennt neue Repositories
- Mindestens drei Software Templates stehen für Entwickler bereit
- Monitoring ist konfiguriert (Application Insights für das Node.js-Backend)
- Backup-Strategie für die PostgreSQL-Datenbank ist getestet
Fazit
Backstage transformiert die Developer Experience, wenn es durchdacht bereitgestellt und aktiv gewartet wird. Auf Azure bietet die Kombination aus AKS oder Container Apps, PostgreSQL Flexible Server, Blob Storage für TechDocs und Entra ID für die Authentifizierung eine solide Grundlage. Die eigentliche Arbeit liegt in der Catalog-Pflege, der Template-Erstellung und der Förderung der Adoption.
Beginnen Sie mit dem Catalog. Machen Sie die Auffindbarkeit einfach. Fügen Sie dann Templates, TechDocs und Custom Plugins hinzu, während die Nutzung wächst.
Wenn Sie Backstage für Ihre Organisation evaluieren oder Hilfe bei der Bereitstellung auf Azure mit Enterprise-gerechter Sicherheit und Governance benötigen, kontaktieren Sie uns unter mbrahim@conceptualise.de. Wir helfen Enterprise-Teams beim Aufbau interner Developer Platforms, die Entwickler tatsächlich nutzen.
Themen