Catalogando Nossos Recursos
Já temos acesso aos repositórios utilizando as contas usadas através da integração do GitHub e GitLab feitas no momento da instalação.
O Catalog no Backstage é um dos principais componentes da plataforma. Ele serve como um inventário centralizado de todos os recursos e serviços da sua infraestrutura, ajudando as equipes a organizar, documentar e gerenciar o ecossistema de aplicações e serviços de maneira eficiente.
O catálogo forma um hub de tipos, onde entidades são ingeridas de várias fontes autorizadas e mantidas em um banco de dados, sujeitas a processamento automatizado e, em seguida, apresentadas por meio de uma API para acesso rápido e fácil pelo Backstage e outros.
-
Ingestão. Os provedores de identidade buscam os dados de fontes externas e guardam no banco de dados. A fonte mais comum são arquivos YAML que estão em algum repositório.
-
Processamento: Após a ingestão os dados são processados para verificação de erros, relações com outras entidades, etc.
-
Costura: Os dados processados
Component
Se você é um engenheiro e trabalha em uma companhia com vários desenvolvedores provavelmente terá vários serviços, vários componentes de software como:
bibliotecas, toolkits, website interno, pipelines, etc. Qualquer coisa desse tipo é o que chamamos de componentes. São as partes, as peças, que formam o software.
No Backstage criamos modelos em arquivos YAML para definir as coisas, assim como no Kubernetes. O kind é o tipo, o modelo daquela entidade e quando é component temos o kind: Component.
Um exemplo da própria documentação.
apiVersion: backstage.io/v1alpha1
kind: Component # Nosso tipo
metadata:
name: artist-web # Neste caso precisa ser um ÚNICO.
description: The place to be, for great artists
labels:
example.com/custom: custom_label_value
annotations:
example.com/service-discovery: artistweb
circleci.com/project-slug: github/example-org/artist-website
tags:
- java
links:
- url: https://admin.example-org.com
title: Admin Dashboard
icon: dashboard
type: admin-dashboard
spec:
type: website # Não existe tipos específicos, isso é só uma string. Você pode colocar o type que você quiser.
lifecycle: production
owner: artist-relations-team
system: public-websites
Já vamos aproveitar e fazer o seguinte; Crie um repositório que o Backstage possa acessar e coloque isso dentro. Eu criei na minha conta o repositório backstage-things-1 e este YAML acima chamando component-website.yaml. Veremos mais para frente o que vamos fazer com isso.
API
Esse é o tipo que irá definir interfaces que são expostas por algum component. Sabe aquele momento que você precisa conhecer a API de algum dos serviços e não precisa procurar a documentação dela? Usando esse podemos expressar uma API de diferentes formatos, como OpenAPI, AsyncAPI, GraphQL, gRPC, etc.
Os manifestos são praticamente a mesma coisa do component.
Inicialmente existe um sidebar só para esse tipo de componente.
Resource
Um recurso descreve algo na infraestrutura, algo físico, como um banco de dados, cache, instâncias, VPC, VPN, etc.
O repositório que criamos poderia ser o repositório de qualquer coisa e definimos um YAML dentro, mas precisamos avisar o catalog onde ele precisa procurar.
A primeira maneira de fazer isso é criar manualmente o recurso. Em catalog podemos em CREATE, no canto superior direito em REGISTER EXISTING COMPONENT, passar a URL do arquivo YAML desejado no repositório e fazer um ANALYZE.

E logo recebemos isso.

Essa mensagem aconteceu por causa desta linha
spec:
...
owner: artist-relations-team
Definimos o owner do projeto, mas ele não existe no sistema. Ele espera um grupo, então vamos criar um grupo no próprio repositorio.
Group
Um grupo descreve uma entidade organizacional, como por exemplo uma equipe, uma unidade de negócios ou uma coleção solta de pessoas em um grupo de interesse.
-
Um grupo pode ou não pertencer a outro grupo. Nesse caso declaramos o parent. Um grupo somente pode ter um pai.
-
Um grupo pode ou não ter subgrupos sendo que cada subgrupo também é um grupo. Nesse caso declaramos a lista de children, os grupos
-
Um grupo pode ou não conter membros do grupo que no caso são user.
Um user descreve uma pessoa, como um funcionário, um contratado ou similar. Usuários pertencem a Group entidades no catálogo.
Vamos criar o grupo, um arquivo YAML chamado group.yaml no mesmo repositório.
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
name: artist-relations-team
description: Artist Relation Team Unit
spec:
type: business-unit
profile:
displayName: Artist Relation Team
email: [email protected]
picture: https://sbm.wpenginepowered.com/wp-content/uploads/2017/02/feature-image-12-1024x535.jpg
parent: ops
children: [backstage, other]
members: [davidpuziol] #Ja me adicionei como membro
Agora vamos fazer o mesmo processo e importar manualmente.

O que aconteceu foi que é necessário permissão registrar grupos nos sistema.
Em app-config.yaml temos o seguinte.
catalog:
#...
rules:
# Somente esses components podem ser registrados
- allow: [Component, System, API, Resource, Location]
Os grupos de uma empresa poderiam ser administrados pelo time de platform engineers com algum tipo de sincronização pois eles definem permissões sobre recursos. Não é comum que qualquer um crie grupos ou users.
Vamos adicionar pois estamos estudando, e reinicie novamente o Backstage.
rules:
- allow: [Component, System, API, Resource, Location, Group, User]

A primeira relação foi criada, mas ainda sim continuaremos com algumas falhas, pois precisamos de mais grupos e outras coisas.


Um outro método de fazer isso é criar arquivos yaml dentro do nosso código e apontar, assim como foi feito com o arquivo exemplo. Esquece isso que não vai acontecer na vida real.
Users
Falando um pouco de users:
- Obrigatóriamente um user precisa ser membro de algum grupo.
- Se um user não é membro de nenhum um grupo então ele pertence ao grupo default.
- Um user pode ser membro de mais de um grupo.
- Podemos referenciar um user como membro de um grupo na própria entidade user ou ele pode ser colocado como membro do grupo na definição do próprio grupo.
GitOps Backstage Catalog
Já vimos que podemos criar as coisas manualmente apontando os arquivos no repositório. Se você ainda não reparou, podemos apenas apontar a URL do repositório e ele buscará automaticamente o arquivo catalog-info.yaml, que deverá conter todas as definições dentro, mas não é obrigatório que seja assim.
Podemos colocar direto no código apontando a localização das coisas no app-config.yaml com os exemplos que vem com o Backstage, mas isso é inviável no dia a dia.
catalog:
#...
locations:
- type: file
target: ../../examples/entities.yaml
Ou podemos partir para ter as coisas todas no repositório e fazer o GitOps acontecer!
Definindo um padrão de estudo aqui, a proposta será criar uma pasta chamada na raiz de cada um dos repositórios e todos os arquivos que ali existirem serem varridos e lidos automaticamente pelo catalog.
Vamos padronizar
nossa regra: Todos os manifestos que existerem devem estar dentro da pastabackstagede qualquer um dos repositórios.
Essa não é a abordagem correta, mas somente vamos entender o motivo depois na hora que estudarmos o docs. O que aconteceu foi que na hora de estudar eu quis fazer diferente, criando uma estrutura nova, e só depois entendi por que precisava ser como é então acho que vale a pena deixar aqui para mostrar o erro futuramente.
A maioria das integrações possui um provedor de discovery. No caso do GitHub o discovery registrará as entidades automaticamente de acordo com as configurações que passamos. Por exemplo a documentação de discovery do GitHub.
Seguindo a documentação precisamos configurar no app-config.yaml e no backend.
No caso do Gitlab envolve outro tipo de configuração, não vou fazer agora, em outro momento adiciono aqui pois envolve o uso de webhooks.
No app-config.yaml.
catalog:
#...
providers:
github:
providerId:
organization: davidpuziol
schedule:
frequency: { minutes: 3 }
timeout: { minutes: 3 }
filters:
- repository: /.*/ # Regex para incluir todos os repositórios
catalogPath: '/backstage/**/*.{yaml,yml}' # Busca recursivamente baseado na regra que definimos acima.
Vamos adicionar as dependências necessárias para o GitHub.
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github
Também é necessário adicionar as linhas abaixo.
// catalog plugin
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
backend.add(import('@backstage/plugin-catalog-backend-module-github')); //Essa
Agora vamos começar a brincadeira. Crie um repositório que será a base.
git clone [email protected]:davidpuziol/backstage-base.git
cd backstage-base
mkdir users
mkdir groups
Users X Groups
Para que os relacionamento aconteçam de forma correta é necessário que estas regras sejam mantidas, caso contrário veremos inconsistências.
Vamos criar uma estrutura de grupos e users inicial, tentando simular o que foi mostrado.
- developers
- team-frontend
- dev-1
- dev-2
- team-backend
- dev-3
- team-frontend
- operations
- team-sec
- ops-1
- team-sre
- ops-2
- team-monitoring
- ops-3
- team-cloud
- ops-4
- team-sec
- platform
- team-backstage
tree
.
├── LICENSE
├── README.md
└── backstage
├── groups
│ ├── development
│ │ ├── development-group.yaml
│ │ └── pics
│ │ └── development-group.png
│ ├── operation
│ │ ├── operation-group.yaml
│ │ └── pics
│ │ └── operation-group.png
│ └── platform
│ ├── pics
│ │ └── platform-group.png
│ └── platform-group.yaml
└── users
Criamos os grupos iniciais, que serão os pais dos demais e comitamos no repositório e vamos ver se o backstage faz a varredura automaticamente e cria.
Após algum tempo o catalog faz a sua descoberta e temos o seguinte.

Como previsto, declaramos filhos e não temos eles, logo temos a seguinte mensagem no grupo development.
This entity has relations to other entities, which can't be found in the catalog. Entities not found are: group:default/team-backend, group:default/team-frontend
Vamos declarar os grupos filhos e fazer os ajustes com os parents.
Vamos criar também um user inicial para nossa própria conta!
❯ tree backstage/users
backstage/users
└── default
└── davidpuziol.yaml
apiVersion: backstage.io/v1alpha1
kind: User
metadata:
name: davidpuziol
spec:
profile:
displayName: David Puziol
email: davidpuziol@gmail.com
picture: https://avatars.githubusercontent.com/u/32808515?s=400&u=86f4e3ff19eb20d1b142a3eedadc6c37e5cc3048&v=4
memberOf: [team-idp, operation]
Agora podemos observar que o nosso SSO foi vinculado com um Backstage Identity.

E o user identity davidpuziol mostra como o ownership de um component website que criamos manualmente anteriormente.
Isso aconteceu porque declaramos um grupo manualmente, e dissemos que davidpuziol era um membro deste grupo e este grupo é o owner do website, logo davidpuziol também será owner do website.

//componene
spec:
type: website
lifecycle: production
owner: artist-relations-team
//group
metadata:
name: artist-relations-team
// ...
spec:
// ...
members: [davidpuziol]
os grupos que o user pertence podem ser declarados dentro do próprio user e em outros grupos.
Para que as coisas fiquem mais granularizadas e restritivas é interessante evitar o que fizemos como colocar davidpuziol no grupo de operation, pois automaticamente ele também será owner de todo e qualquer projeto dos times filhos de operation.
// operation
//...
kind: Group
metadata:
name: operation
//...
spec:
//...
children: [team-security, team-sre, team-monitoring, team-cloud]
O diagrama abaixo pode explicar melhor a relação entre elas.

- Os types de qualquer um dos objetos podem ser qualquer um que quisermos, o que foi mostrado é somente uma idéia.
System
Um sistema é uma coleção de recursos, componentes e api. No Backstage, o proprietário de um sistema é a entidade singular (geralmente uma equipe) que tem a responsabilidade final pelo sistema e tem a autoridade e a capacidade de desenvolvê-lo e mantê-lo. É assim mesmo que funcionam as coisas, um monte de tecnologia junta, um monte de treco junto que entregam a função, ou serviço final.
No Backstage, Domains e Systems são conceitos fundamentais para organizar os componentes e serviços de uma infraestrutura complexa, ajudando a estruturar e visualizar melhor os recursos dentro da plataforma e quem é responsável por aquele conjunto.
Domain
Um Domínio agrupa uma coleção de sistemas. Vamos imaginar uma área da qualquer da empresa. Ela é composta por vários sistemas. Nem sempre um sistema entrega uma solução final, um monolitão, quase sempre é necessário um conjunto de sistemas para de fato que a solução funcione. As vezes um sistema.
A divisão das coisas dentro da plataforma depende de como você quer fazer.
Um Domain pode representar uma área de responsabilidade dentro da organização. Vamos imaginar um Domain chamado Payments que poderia incluir todos os sistemas e serviços relacionados ao processamento de pagamentos.
Plugins Complementares Catalog
Erros de catálogo são publicados no plugin de eventos. Para instalar o plugin de eventos.
yarn --cwd packages/backend add @backstage/plugin-events-backend
E devemos adicionar no pacotes/backend/src/index.ts
backend.add(import('@backstage/plugin-events-backend'));
Também podemos registrar eventos com nivel de warn usando um plugin.
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs
E adicionando no backend.
backend.add(import('@backstage/plugin-catalog-backend-module-logs'));