Salta al contenuto principale

04 - Backstage.io: Platform Portal per Developer Self-Service e Service Catalog

Backstage è un framework da compilare e gestire, non un prodotto. Catalogo, TechDocs e Helm validati con strumenti reali, più il rischio MkDocs.

Cosa ne pensi di questo articolo?

04 - Backstage.io: Platform Portal per Developer Self-Service e Service Catalog
Platform EngineeringFoto:SiddePexels

In Breve

Backstage è un framework da compilare e gestire, non un prodotto. Catalogo, TechDocs e Helm validati con strumenti reali, più il rischio MkDocs.

Che cos'è Backstage e che cosa non è

Backstage è un framework open source (licenza Apache-2.0) per costruire portali per sviluppatori, nato in Spotify. Il CNCF lo ha accettato l'8 settembre 2020 e dal 15 marzo 2022 è progetto in incubazione, ancora oggi non graduated (pagina del progetto, consultata il 2026-11-13). Il punto da capire prima di tutto: è un framework, non un prodotto da installare. Si crea un'applicazione con npx @backstage/create-app@latest, si aggiungono i plugin nel codice, si compila e si distribuisce. Chi lo adotta gestisce quindi un'applicazione Node con un proprio ciclo di aggiornamenti: l'ultima release al 2026-11-13 è la 1.56.5 (pagina delle release su GitHub).

Le funzioni centrali sono tre, e coincidono con le pagine di panoramica della documentazione: il Software Catalog, che tiene l'inventario di componenti, API e risorse con i loro proprietari; i Software Templates, che creano nuovi progetti dal portale (li ho trattati con un esempio completo nell'articolo 3); e TechDocs, la documentazione scritta in Markdown accanto al codice e mostrata nel portale. Non ho eseguito create-app: richiede l'installazione di un intero progetto, e qui mi limito a ciò che si verifica senza. In questo articolo ho validato con i pacchetti ufficiali il catalogo e la configurazione, con mkdocs la documentazione e con helm template il rilascio.

Come è fatto: applicazione, backend e plugin

Un'installazione si compone di tre parti:

  • L'applicazione frontend, una pagina React che si personalizza con temi, layout e plugin.
  • Il backend, un processo Node.js che espone le API, parla con il database e ospita i plugin lato server; nel sistema backend attuale i moduli si aggiungono con backend.add(import('...')) nel punto d'ingresso.
  • I plugin, pacchetti con una parte frontend, una backend o entrambe; il catalogo, il generatore di progetti e TechDocs sono essi stessi plugin.

La conseguenza pratica è che il portale non ha un pannello per attivare un'integrazione: ogni plugin è una dipendenza da installare, configurare e aggiornare insieme al resto. Il vantaggio è la componibilità, il costo è che le versioni dei plugin devono restare compatibili con quella del nucleo.

La configurazione sta in app-config.yaml. Il file seguente è un esempio minimo per un'installazione con autenticazione GitHub e database PostgreSQL; i valori riservati sono variabili d'ambiente, con la sintassi ${NOME}. Due dettagli contano. Il blocco signIn.resolvers è indispensabile: la documentazione spiega che ogni provider di autenticazione, per impostazione predefinita, serve solo a delegare l'accesso a sistemi esterni, e che per far entrare gli utenti bisogna abilitare il login e dire come mappare l'identità esterna su un'entità utente del catalogo. E il provider «guest» incluso in create-app condivide un'unica identità fra tutti e non va usato in produzione.

app:
  title: Portale sviluppatori di esempio
  baseUrl: https://backstage.example.com

backend:
  baseUrl: https://backstage.example.com
  listen:
    port: 7007
  database:
    client: pg
    connection:
      host: ${POSTGRES_HOST}
      port: ${POSTGRES_PORT}
      user: ${POSTGRES_USER}
      password: ${POSTGRES_PASSWORD}

integrations:
  github:
    - host: github.com
      token: ${GITHUB_TOKEN}

auth:
  environment: production
  providers:
    github:
      production:
        clientId: ${AUTH_GITHUB_CLIENT_ID}
        clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
        signIn:
          resolvers:
            - resolver: usernameMatchingUserEntityName

catalog:
  rules:
    - allow: [Component, System, API, Resource, Location, Group, User]
  locations:
    - type: url
      target: https://github.com/example-org/catalogo/blob/main/catalog.yaml

Per sapere che cosa succede quando una variabile manca, ho caricato il file con il caricatore di configurazione ufficiale (@backstage/config-loader 1.11.4) e ho letto quattro valori obbligatori, una volta con tutte le variabili impostate e una senza POSTGRES_PASSWORD. Per avere un ambiente pulito ho lanciato lo script con env -i, che passa solo le variabili elencate.

// Carica app-config.yaml con il caricatore di configurazione di Backstage
// e controlla i valori obbligatori, uno per uno.
const path = require("path");
const mod = (n) => require(path.join(__dirname, "node_modules", n));
const { ConfigSources } = mod("@backstage/config-loader");

const OBBLIGATORI = {
  "backend.database.connection.host": (c) => c.getString("backend.database.connection.host"),
  "backend.database.connection.password": (c) => c.getString("backend.database.connection.password"),
  "integrations.github[0].token": (c) => c.getConfigArray("integrations.github")[0].getString("token"),
  "auth.providers.github.production.clientSecret": (c) => c.getString("auth.providers.github.production.clientSecret"),
};

(async () => {
  const sorgente = ConfigSources.default({ argv: ["--config", process.argv[2]], remote: undefined });
  const config = await ConfigSources.toConfig(sorgente);
  for (const [chiave, leggi] of Object.entries(OBBLIGATORI)) {
    try {
      leggi(config);
      console.log(`${chiave}: presente`);
    } catch (e) {
      console.log(`${chiave}: ${e.message}`);
      process.exitCode = 1;
    }
  }
  config.close();
})();

// Output:
// [tutte le variabili impostate]
// backend.database.connection.host: presente
// backend.database.connection.password: presente
// integrations.github[0].token: presente
// auth.providers.github.production.clientSecret: presente
// uscita: 0
// [senza POSTGRES_PASSWORD]
// backend.database.connection.host: presente
// backend.database.connection.password: Missing required config value at 'backend.database.connection.password' in 'app-config.yaml'
// integrations.github[0].token: presente
// auth.providers.github.production.clientSecret: presente
// uscita: 1

Senza la variabile, il caricatore non si ferma all'avvio: sostituisce il segnaposto con un valore assente, e l'errore compare solo quando qualcuno prova a leggere quel valore («Missing required config value»). Un controllo come questo, lanciato nella pipeline prima del rilascio, trasforma un guasto all'avvio in un rifiuto prima del deploy. Il token dell'integrazione GitHub è il modo semplice; per un'organizzazione la documentazione propone anche le GitHub App, con permessi più stretti.

Software Catalog: il descrittore e le relazioni

Ogni voce del catalogo è un file YAML, tipicamente catalog-info.yaml nella radice del repository. I tipi di entità sono nove: Component, API, Resource, System, Domain, Group, User, Location e Template, quest'ultimo per i generatori di progetti. Quelli di uso quotidiano sono:

  • Component: un servizio, un sito, una libreria, un flusso di dati.
  • API: il confine fra componenti, in un formato leggibile da macchina (OpenAPI, gRPC, GraphQL).
  • Resource: l'infrastruttura di cui un componente ha bisogno, per esempio un database.
  • System: un insieme di componenti e risorse che espone una o più API pubbliche, e che permette di nascondere ai consumatori i dettagli interni.
  • Group e User: le persone e i team a cui le altre entità rimandano come proprietari.

Sono le definizioni del modello di sistema della documentazione. La parte che conta di più nel lavoro quotidiano è il «proprietario» e il fatto che il campo spec.owner è «a scopo di visualizzazione»: la documentazione precisa che non va usato per assegnare autorizzazioni nei sistemi in esecuzione. È un'informazione di responsabilità, non un permesso.

Un file di catalogo contiene molti riferimenti fra entità, e ogni riferimento è una stringa nella forma [kind:][namespace/]nome. Se il kind manca, vale un predefinito che dipende dal campo: owner rimanda per impostazione predefinita a un Group, dependsOn a un Component (per una risorsa serve scrivere resource:). L'esempio seguente descrive un piccolo sistema con due team, due componenti, due API e un database. Il checker che lo accompagna usa i validatori ufficiali di @backstage/catalog-model 1.10.2 per lo schema, e poi verifica che ogni riferimento punti a un'entità esistente, cosa che lo schema non controlla.

apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
  name: team-checkout
spec:
  type: team
  children: []
---
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
  name: team-inventario
spec:
  type: team
  children: []
---
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
  name: e-commerce
spec:
  owner: team-checkout
---
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: checkout-service
  description: Gestisce il carrello e il pagamento
  annotations:
    github.com/project-slug: example-org/checkout-service
    backstage.io/techdocs-ref: dir:.
  tags: [typescript, pagamenti]
spec:
  type: service
  lifecycle: production
  owner: team-checkout
  system: e-commerce
  providesApis: [checkout-api]
  consumesApis: [inventario-api]
  dependsOn:
    - resource:checkout-db
    - component:inventario-service
---
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: inventario-service
spec:
  type: service
  lifecycle: production
  owner: team-inventario
  system: e-commerce
  providesApis: [inventario-api]
---
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: checkout-api
spec:
  type: openapi
  lifecycle: production
  owner: team-checkout
  system: e-commerce
  definition: |
    openapi: 3.0.3
    info: {title: Checkout, version: 1.0.0}
    paths: {}
---
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: inventario-api
spec:
  type: openapi
  lifecycle: production
  owner: team-inventario
  system: e-commerce
  definition: |
    openapi: 3.0.3
    info: {title: Inventario, version: 1.0.0}
    paths: {}
---
apiVersion: backstage.io/v1alpha1
kind: Resource
metadata:
  name: checkout-db
spec:
  type: database
  owner: team-checkout
  system: e-commerce

Il file mostra tre convenzioni. Le annotazioni (github.com/project-slug, backstage.io/techdocs-ref) sono chiavi lette dai plugin: lo schema le accetta tutte, quindi un'annotazione scritta male non produce errori ma il plugin corrispondente non trova nulla. Le due dipendenze di checkout-service usano prefissi diversi (resource: e component:) perché il predefinito di dependsOn è Component. E le API portano la definizione dentro la voce, mentre nei progetti reali si preferisce spesso un riferimento a un file.

// Valida un file di catalogo con i validatori ufficiali di Backstage e controlla che ogni
// riferimento fra entità (owner, system, API, dipendenze) punti a un'entità che esiste.
const fs = require("fs");
const path = require("path");
const mod = (n) => require(path.join(__dirname, "node_modules", n));
const YAML = mod("yaml");
const cm = mod("@backstage/catalog-model");

const VALIDATORI = {
  Component: cm.componentEntityV1alpha1Validator, API: cm.apiEntityV1alpha1Validator,
  Resource: cm.resourceEntityV1alpha1Validator, System: cm.systemEntityV1alpha1Validator,
  Group: cm.groupEntityV1alpha1Validator,
};
// campo -> kind predefinito quando il riferimento non lo dichiara (regole della documentazione)
const CAMPI = { owner: "Group", system: "System", providesApis: "API", consumesApis: "API", dependsOn: "Component" };

async function main(file) {
  const entita = YAML.parseAllDocuments(fs.readFileSync(file, "utf8")).map((d) => d.toJS());
  let errori = 0;
  for (const e of entita) {
    try { await VALIDATORI[e.kind].check(e); }
    catch (err) { errori++; console.log(`${e.kind} ${e.metadata.name}: schema non valido (${err.message})`); }
  }
  const esistenti = new Set(entita.map((e) => cm.stringifyEntityRef(e)));
  let riferimenti = 0;
  for (const e of entita) {
    for (const [campo, kind] of Object.entries(CAMPI)) {
      for (const ref of [].concat(e.spec[campo] ?? [])) {
        riferimenti++;
        const completo = cm.stringifyEntityRef(cm.parseEntityRef(ref, { defaultKind: kind, defaultNamespace: "default" }));
        if (!esistenti.has(completo)) { errori++; console.log(`${e.kind} ${e.metadata.name}: ${campo} -> ${completo} non esiste`); }
      }
    }
  }
  console.log(`${entita.length} entità, ${riferimenti} riferimenti, ${errori} problemi`);
  process.exitCode = errori ? 1 : 0;
}
main(process.argv[2]);

// Output:
// [catalog.yaml]
// 8 entità, 16 riferimenti, 0 problemi
// uscita: 0
// [catalog-sbagliato.yaml]
// Component checkout-service: owner -> group:default/team-chekout non esiste
// Component checkout-service: dependsOn -> resource:default/checkout-db non esiste
// 7 entità, 14 riferimenti, 2 problemi
// uscita: 1

Il file corretto passa: 8 entità e 16 riferimenti, nessun problema. Nella seconda esecuzione ho rovinato una copia togliendo il database e scrivendo team-chekout al posto del proprietario. Lo schema non protesta (le due entità sono strutturalmente valide), ed è il controllo dei riferimenti a trovarli entrambi. È il motivo per cui conviene far girare un controllo come questo in una pipeline, sul repository che contiene il catalogo: i riferimenti rotti sono il difetto più silenzioso di un inventario, ed è quello che il catalogo di cui parla l'articolo 6 deve evitare.

TechDocs: documentazione accanto al codice, e un rischio da conoscere

TechDocs prende i file Markdown del repository, li compila con MkDocs e li mostra nella pagina del componente. Il collegamento passa dall'annotazione backstage.io/techdocs-ref: dir:., che dice che la documentazione sta nella stessa cartella del descrittore. Il vantaggio è che i documenti si modificano nella stessa richiesta di modifica del codice. Per la produzione la documentazione di Backstage raccomanda di non farli costruire al backend: un passo della pipeline genera i file statici con techdocs-cli e li pubblica su uno storage in cloud, da cui il backend li legge.

Il file mkdocs.yml qui sotto descrive il sito: un titolo, un menu di navigazione e il plugin techdocs-core, che prepara MkDocs per TechDocs. L'ho costruito con mkdocs 1.6.1 e mkdocs-techdocs-core 1.7.1 in un ambiente virtuale temporaneo, con cinque pagine di prova, in modalità --strict: ogni avviso diventa un errore. Il secondo caso è lo stesso file con una voce di menu che punta a una pagina inesistente.

site_name: Checkout Service
site_description: Documentazione tecnica del servizio checkout

nav:
  - Home: index.md
  - Architettura:
      - Panoramica: architecture/overview.md
  - Sviluppo:
      - Primo avvio: development/getting-started.md
  - Operazioni:
      - Runbook: operations/runbook.md
  - ADR:
      - "001 - Scelta del database": adr/001-database.md

plugins:
  - techdocs-core

# Output:
# [mkdocs.yml]
# uscita: 0
# [mkdocs-rotto.yml]
# WARNING -  A reference to 'operations/runbook-mancante.md' is included in the 'nav' configuration, which is not found in the documentation files.
# Aborted with 1 warnings in strict mode!
# uscita: 1

Senza --strict un riferimento rotto nel menu produce solo un avviso e il sito si genera lo stesso, con un link morto: con l'opzione, la pipeline si ferma. Una precisazione: per generare l'output da pubblicare, la documentazione di TechDocs chiede di usare techdocs-cli (o il contenitore ufficiale), perché aggiunge un file di metadati necessario al lettore. Il mio controllo vale per la struttura del sito, non sostituisce quel passo.

Il rischio riguarda il motore. Il 17 aprile 2026 i maintainer di Backstage hanno aperto una richiesta di commenti (RFC #33990, ancora aperta il 2026-11-13) in cui scrivono che MkDocs non ha rilasci dalla versione 1.6.1 dell'agosto 2024, che la riscrittura 2.0 proposta eliminerebbe il sistema di plugin (compreso mkdocs-techdocs-core) e che il tema Material su cui TechDocs si appoggia è in sola manutenzione; propongono di passare a Zensical, un motore che legge mkdocs.yml. Anche l'avviso che il pacchetto Material stampa a ogni build, e che compare nelle mie esecuzioni, va nella stessa direzione. In pratica: fissa le versioni di MkDocs e del tema, genera la documentazione in pipeline e non usare estensioni esotiche, così il giorno del cambio di motore il lavoro resta contenuto.

Distribuire Backstage su Kubernetes con Helm

La documentazione descrive il metodo che Spotify usa: costruire un'immagine Docker, pubblicarla su un registro, citarla in un Deployment Kubernetes e applicarlo. Esiste anche un chart Helm mantenuto dalla comunità nel repository backstage/charts (versione 2.10.2 al 2026-11-13). Qui il punto non è il chart ma i valori: sono lo schema da adattare, e li ho resi con helm template (helm 3.16.0, nessun cluster), che produce i manifest senza applicarli.

backstage:
  image:
    registry: ghcr.io
    repository: example-org/backstage
    tag: "1.0.0"
  replicas: 2
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: "1"
      memory: 1Gi
  extraEnvVars:
    - name: POSTGRES_HOST
      valueFrom:
        secretKeyRef:
          name: backstage-db
          key: host
    - name: GITHUB_TOKEN
      valueFrom:
        secretKeyRef:
          name: backstage-github
          key: token

ingress:
  enabled: true
  className: nginx
  host: backstage.example.com
  tls:
    enabled: true
    secretName: backstage-tls

postgresql:
  enabled: false

# Output (helm template backstage backstage/backstage --version 2.10.2 -f values-backstage.yaml | grep -E ...):
# kind: Service
# kind: Deployment
#   replicas: 2
#           image: ghcr.io/example-org/backstage:1.0.0
# kind: Ingress
#   ingressClassName: "nginx"
#       secretName: backstage-tls
#     - host: backstage.example.com

Quattro scelte nel file. L'immagine ha un tag fisso e non latest, perché il valore predefinito del chart è proprio latest e un riavvio potrebbe portare una versione diversa da quella provata. Le credenziali arrivano da secretKeyRef, non scritte nel file. Il blocco ingress sta alla radice dei valori e non sotto backstage, e tls è un oggetto con enabled e secretName, non una lista come nell'Ingress di Kubernetes. Infine postgresql.enabled: false: il sottochart PostgreSQL incluso usa per impostazione predefinita l'immagine docker.io/bitnamilegacy/postgresql, e per un portale che conserva il catalogo conviene un database gestito da te, con i backup che ne conseguono.

La terza scelta è anche l'errore più facile da commettere. Con i valori sotto, che mettono l'Ingress dentro backstage, il chart rifiuta il file:

backstage:
  image:
    registry: ghcr.io
    repository: example-org/backstage
    tag: "1.0.0"
  replicas: 2
  ingress:
    enabled: true
    host: backstage.example.com
    tls:
      - secretName: backstage-tls
        hosts:
          - backstage.example.com

# Output (helm template ... -f values-sbagliato.yaml):
# Error: values don't meet the specifications of the schema(s) in the following chart(s):
# backstage:
# - backstage: Additional property ingress is not allowed

Il chart ha uno schema dei valori che respinge le chiavi sconosciute: un errore che con altri chart passerebbe in silenzio e lascerebbe l'applicazione senza Ingress. Il messaggio nomina la chiave sbagliata, non la causa, quindi conviene sapere dove cercare. La validazione dei manifest generati contro lo schema di Kubernetes, con kubeconform, è il passo successivo e l'ho mostrata nell'articolo 2.

Quando non installare Backstage: un catalogo senza portale, e dove ha ceduto

Il repo di questo sito non usa Backstage, e conviene dire perché con un esempio. Ha tre servizi, un solo manutentore e un catalogo da gestire a mano: i documenti in docs/ con un indice per aspetto, un file CLAUDE.md che li mappa, e un registro dei contenuti. Non c'è un portale perché i lettori del catalogo sono uno (l'autore) e gli agenti automatici che lavorano sul repo, e per entrambi un file di testo ben indicizzato è più economico di un'applicazione Node con il suo database.

Il costo di un portale, contato

  • Un servizio in più da far girare e aggiornare. Backstage è un'app Node con un backend, un database e plugin con versioni proprie. Aggiornare un plugin rotto da un aggiornamento del core è lavoro ricorrente.
  • Un modello di dati da mantenere. Ogni componente richiede un catalog-info.yaml e un proprietario. Con tre servizi i descrittori costerebbero più di quanto fa risparmiare la ricerca.
  • Il beneficio cresce con il numero di proprietari. Il valore del catalogo è rispondere a «di chi è questo servizio e come lo uso»: vale quando la risposta non sta nella testa di chi legge.

Le tre voci hanno una cosa in comune: sono costi che si pagano ogni mese e non una volta sola, mentre il beneficio compare solo quando qualcuno cerca davvero qualcosa nel catalogo. Prima di installare un portale conviene stimare quanto spesso, e da quante persone diverse, viene cercata la risposta alla domanda «di chi è questo servizio e come lo uso».

Dove il catalogo manuale ha ceduto: due fonti di verità

Il difetto che un catalogo vero previene si è presentato lo stesso. Il catalogo degli strumenti business è un file JSON in due copie: una canonica nel backend e una nel frontend, ricopiata sopra la seconda a ogni build da uno script di prebuild. Chi modificava solo la copia del frontend vedeva la modifica sovrascritta senza un errore: i nuovi strumenti non comparivano nella pagina del catalogo e nessun test falliva. La regola scritta nel progetto è «aggiungi sempre al file del backend, poi rigenera la copia». È la stessa cosa che Backstage risolve con il principio di una sola origine per l'entità, ottenuto qui con una regola e uno script anziché con un prodotto.

Il discrimine. Un portale si giustifica quando i servizi sono più di quanti una persona tiene a mente e quando almeno tre team hanno bisogno di scoprire gli strumenti degli altri (una soglia indicativa, mia, non misurata). Sotto quella soglia la domanda utile non è «quale portale» ma «dove sta l'unica copia di ogni dato, e che cosa succede se qualcuno modifica quella sbagliata», e la risposta è un test che fallisce, non un portale.

Che cosa installare per primo

Parti con il minimo: catalogo, TechDocs e due o tre plugin che rispondono a una domanda che i tuoi sviluppatori fanno davvero (di solito lo stato della pipeline e dove gira il servizio). Aggiungi un plugin alla volta, in base alle richieste, e dopo ogni aggiunta controlla due cose: quanto costa l'aggiornamento e se qualcuno lo usa. Un portale troppo ricco al lancio confonde invece di aiutare, ed è un giudizio mio, non un risultato di ricerca. Le metriche per capire se il portale sta servendo sono quelle dell'articolo 7.

Che cosa sai fare adesso

Sai che Backstage è un framework da compilare e gestire, e con quali parti (applicazione, backend, plugin). Sai scrivere un catalogo e verificarne schema e riferimenti con i validatori ufficiali, controllare in pipeline che la configurazione sia completa, e proteggere il sito TechDocs da un menu rotto. Sai impostare i valori Helm per un rilascio e riconoscere i due errori tipici (Ingress al posto sbagliato, tag mobile). Il prossimo articolo allarga lo sguardo all'infrastruttura come codice, la parte che il portale chiama quando una richiesta deve creare qualcosa.

Domande frequenti

Backstage è un prodotto da installare?

No, è un framework: si crea un'applicazione Node con @backstage/create-app, si aggiungono i plugin nel codice e si distribuisce. Chi lo adotta ne gestisce gli aggiornamenti e la compatibilità fra plugin e nucleo.

Che cosa fa il Software Catalog?

Tiene l'inventario di componenti, API, risorse, sistemi e team, descritti da file YAML nei repository. Il campo owner indica la responsabilità ed è a scopo di visualizzazione: non assegna permessi nei sistemi in esecuzione.

Come si distribuisce Backstage in produzione?

La documentazione descrive la costruzione di un'immagine Docker, la pubblicazione su un registro e un Deployment Kubernetes; esiste anche un chart Helm della comunità. Servono un database PostgreSQL, un autenticatore con la risoluzione dell'identità e un tag di immagine fisso.

TechDocs è a rischio per il futuro di MkDocs?

È un rischio dichiarato dai maintainer di Backstage: MkDocs non ha rilasci dal 1.6.1 (agosto 2024) e la versione 2.0 proposta toglierebbe i plugin. Un'RFC aperta a aprile 2026 valuta il passaggio a Zensical. Conviene fissare le versioni e generare la documentazione in pipeline.

Nella stessa serie trovi anche l'introduzione alla piattaforma interna, la developer experience e i cicli di feedback, il piano di implementazione di una IDP e il confronto fra AI on-prem e cloud.

Fonti

Gli script sono stati eseguiti due volte con uscita identica (Node 24 con @backstage/catalog-model 1.10.2, @backstage/config-loader 1.11.4 e yaml; mkdocs 1.6.1 con mkdocs-techdocs-core 1.7.1; helm 3.16.0 con helm template, senza cluster). create-app, l'avvio di Backstage e il rilascio su un cluster non sono stati eseguiti: i valori Helm sono uno schema da adattare. I nomi di organizzazione e di dominio sono inventati.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti