Construindo uma Plataforma Interna para Desenvolvedores: Do Inferno de Tickets ao Self-Service em 30 Minutos
Todo time de plataforma chega ao mesmo ponto de inflexão. A fila de tickets cresce mais rápido do que o time. Engenheiros esperam dias por um namespace, um banco de dados ou uma aplicação ArgoCD — coisas que deveriam levar minutos. A equipe de plataforma se torna o gargalo de cada time que tenta entregar.
Chegamos nesse limite. Este post é sobre como saímos dele.
O problema
Antes do IDP, onboardar um novo serviço tinha essa cara:
- Abrir um ticket no JIRA para criação de namespace
- Esperar de 2 a 5 dias para a equipe de plataforma revisar
- Receber o namespace — com as labels erradas ou sem limites de recursos
- Abrir outro ticket para a aplicação ArgoCD
- Abrir outro ticket para o banco de dados
De oito a quinze etapas manuais em múltiplas ferramentas. Cada etapa exigia uma pessoa da equipe de plataforma. Cada erro exigia mais uma rodada de ida e volta.
A causa raiz não era falta de automação. Tínhamos Terraform, tínhamos Helm, tínhamos ArgoCD. O problema era que nada disso era self-service. A automação só rodava quando a equipe de plataforma a executava.
O que construímos
O IDP é quatro ferramentas trabalhando juntas:
| Pilar | Ferramenta | Função |
|---|---|---|
| Portal do desenvolvedor | Backstage | Templates, catálogo, observabilidade |
| Entrega GitOps | ArgoCD | Entrega contínua do Git para o Kubernetes |
| Runtime de containers | Kubernetes | Agendamento e isolamento de cargas de trabalho |
| IaC em nuvem | Crossplane | Recursos de nuvem como objetos Kubernetes |
O insight fundamental foi que as convenções são o produto. Uma convenção de nomenclatura não é documentação — é o contrato que permite que cada ferramenta fale com todas as outras sem um humano no meio.
A chave semântica
Todo recurso da plataforma — namespace, aplicação ArgoCD, entidade Backstage, claim Crossplane — é endereçado pela mesma chave de três segmentos:
{project}-{env}-{service}
payments-prod-api
│ │ └── Namespace Kubernetes: payments-prod-api
│ │ Component Backstage: gateway-api
│ └── Application ArgoCD: gateway-api-prod
└── AppProject ArgoCD: payments
Domain Backstage: payments
Quando a nomenclatura é consistente, o plugin Kubernetes do Backstage consegue encontrar todos os pods de um serviço em cada cluster com um único label selector. O plugin ArgoCD consegue exibir o status de sync por ambiente. Sem mapeamento manual. Sem planilhas.
Templates Backstage como caminhos dourados
A camada de self-service é um conjunto de templates do Backstage Scaffolder — um por operação da plataforma:
create-domain— cria o limite de propriedade, o repositório GitOps e o AppProject ArgoCDcreate-system— cria um agrupamento de produto, seu ApplicationSet e base para TechDocscreate-service— estrutura um Repositório de Aplicação (com Dockerfile, workflow de CI e base para TechDocs), gera manifestos Kubernetes por ambiente, registra a entrada no catálogo e abre os PRscreate-resource— cria Claims Crossplane para infraestrutura de nuvem (bancos de dados, filas, buckets)create-secret— fornece criptografia segura de segredos via self-service usando Sealed Secretscreate-group/create-user— onboarda times e engenheiros com RBAC correto desde o primeiro dia
Um engenheiro de produto executa create-service, seleciona seu sistema, nomeia o serviço, escolhe um perfil de recursos e clica em Create. Dois PRs são abertos automaticamente. Quando ambos são mesclados, o ArgoCD detecta o novo elemento do ApplicationSet e sincroniza o serviço com o cluster de dev. O serviço está rodando em menos de 30 minutos sem nenhuma intervenção da equipe de plataforma.
Validação de convenção na CI
Os templates garantem a saída correta no momento da criação. A validação da CI mantém os repositórios corretos ao longo do tempo.
Todo repositório GitOps de domínio inclui um workflow do GitHub Actions (validate-conventions.yaml) gerado pelo create-domain. Em cada PR ele roda o validate-namespaces.sh e verifica:
- Nomenclatura de namespace segue
{project}-{env}-{service} - Todas as 9 labels obrigatórias estão presentes
- Todo container tem requests e limits de recursos
- Manifestos Kubernetes passam na validação de schema (kubeconform)
- Dry-run diff do ArgoCD contra o cluster de dev passa
Violações de convenção bloqueam o merge do PR. Não existe caminho de exceção.
Infraestrutura de nuvem como código — sem expertise em Terraform
Recursos de nuvem (bancos de dados, filas, armazenamento) são declarados como Claims do Crossplane commitados no Git. O ArgoCD os sincroniza com o cluster. O Crossplane provisiona o recurso real no GCP, AWS, Azure ou IBM.
Um desenvolvedor solicitando uma instância Cloud SQL não escreve Terraform. Ele executa create-resource, seleciona GCP → Cloud SQL, preenche um formulário e mescla o PR. O Claim cai em crossplane/claims/prod/cloudsql-main.yaml. O Crossplane reconcilia continuamente — o drift é corrigido automaticamente. deletionPolicy: Orphan nos Claims de produção significa que um kubectl delete acidental não pode destruir um banco de dados.
A página de Resource do Backstage para esse banco de dados exibe READY: True e SYNCED: True assim que o provisionamento é concluído. Sem cavar no console da nuvem.
RBAC sem o fardo de manutenção
O acesso é concedido via grupos do provedor de identidade, nunca usuários individuais. Remover alguém do time GitHub ou do grupo Okta revoga imediatamente todo acesso ao Kubernetes — sem limpeza manual de RoleBinding.
O papel developer não tem RoleBinding criado para namespaces de produção. Não por convenção. Não por documentação. Pelo fato de que o binding simplesmente não existe. O acesso a produção exige elevação explícita de papel.
Gerenciamento seguro de segredos
O acesso aos ambientes de produção é estritamente controlado, e a plataforma impõe uma regra rigorosa de "nenhum segredo em texto claro".
Em vez de abrir tickets para gerenciar segredos, os desenvolvedores usam o template create-secret do Backstage. Eles criptografam seus segredos localmente usando kubeseal e preenchem o template. A plataforma abre automaticamente um PR com o manifesto SealedSecret diretamente no repositório GitOps do seu domínio. O serviço de plataforma sealed-secrets roda no cluster e lida com a descriptografia, garantindo que o gerenciamento seguro de segredos permaneça totalmente self-service.
Resultados até agora
Estamos na Fase 1 do rollout. O primeiro time de domínio é totalmente autossuficiente:
- Criação de serviço: < 30 minutos (eram 2–5 dias)
- Tickets para a equipe de plataforma: em queda
- Namespaces com todas as labels obrigatórias: 100% (para novos serviços)
- Tempo de onboarding do engenheiro: < 2 horas (eram 1–3 dias)
A Fase 2 estenderá o self-service para todos os times de produto e trará observabilidade full-stack do Backstage para cada serviço. A Fase 3 migrará serviços e recursos de nuvem existentes para o catálogo.
O que aprendemos
Convenções primeiro. Nenhuma integração de ferramenta funciona sem nomenclatura consistente. Investimos tempo na convenção antes de construir templates, e cada hora ali economizou dez horas de depuração de integrações de ferramentas.
Templates como mecanismo de aplicação. Documentação é ignorada. Templates tornam o caminho correto o único caminho. Se você pode executar create-service e obter um serviço funcionando, você não tem razão para fazer manualmente.
GitOps escala. Geradores de matriz ApplicationSet significam que adicionar um novo serviço a um novo cluster é uma linha em um arquivo YAML. O ArgoCD cuida do resto. Não criamos Applications manualmente.
Crossplane para IaC de nuvem pertence ao Kubernetes. Manter recursos de nuvem no mesmo loop de reconciliação que as cargas de trabalho de aplicação significa um lugar para olhar drift, um lugar para olhar status, um modelo RBAC para acesso.
Os requisitos completos, arquitetura e roadmap estão documentados no PRD da Plataforma. A convenção de nomenclatura e os padrões operacionais estão na Convenção da Plataforma.