Ivan Micai
← Voltar para o blog

infra-shelf: um estoque de bancos e filas pro homelab

Publicado em

Todo app novo que eu subo no homelab acaba pedindo a mesma coisa: um banco, às vezes uma fila, de preferência já provisionados antes do primeiro docker compose up. Quando rodei o litellm, precisei de Postgres. O Infisical quis Postgres e Redis. Outros projetos pediram RabbitMQ ou MongoDB. O padrão preguiçoso é cada projeto subir seu próprio Postgres + Redis no compose dele — e aí, três projetos depois, você tem três Postgres, dois Redis, conflito de porta toda hora, zero isolamento de verdade e backup espalhado em pasta que ninguém lembra.

Foi pra matar essa dor que escrevi o infra-shelf, hoje aberto no GitHub: https://github.com/IvanMicai/infra-shelf.


A ideia: uma prateleira compartilhada

Em vez de cada app trazer seu próprio banco, eu rodo uma instância de cada coisa numa rede Docker privada (infra-shelf), e cada aplicativo ganha uma credencial isolada dentro dela. Nada de entregar o superusuário pra um app qualquer.

A separação por app acontece dentro de cada serviço:

ServiçoEndereço na redeIsolamento por app
PostgreSQLpostgres:5432database + user dedicados
Redisredis:6379usuário ACL + prefixo de chave
RabbitMQrabbitmq:5672vhost + user dedicados
MongoDBmongodb:27017database + user dedicados
S3 (MinIO)aistor:9000bucket + access key (opt-in)
SignOzsignoz-otel-collector:4317service.name próprio (opt-in)

O Postgres, o Redis, o RabbitMQ e o Mongo sobem com um make up. S3 e SignOz são overlays opcionais. Tudo na mesma rede, então seus apps conectam por nome de host (postgres, redis…) sem expor porta pra fora.


Como eu uso — o CLI shelf

O coração é um binário Go único, o shelf. Provisionar um app é uma linha:

shelf setup myapp -s postgres,redis,rabbitmq,mongodb

Ele gera uma senha aleatória por serviço, roda os comandos de admin dentro dos containers (psql, redis-cli, rabbitmqctl, mongosh), grava tudo num registry e cospe um bloco .env pronto pra colar no projeto:

# === PostgreSQL ===
DATABASE_URL=postgres://myapp:QzLiMENvUupGDz@postgres:5432/myapp
DB_HOST=postgres
DB_NAME=myapp

# === Redis ===
REDIS_URL=redis://myapp:keS6texnNfjnGr@redis:6379/0
REDIS_PREFIX=myapp:

# === RabbitMQ ===
AMQP_URL=amqp://myapp:j3XwLUjuRrEP11@rabbitmq:5672/myapp
RABBITMQ_VHOST=myapp

# === MongoDB ===
MONGODB_URL=mongodb://myapp:C0jbw2HqXVkuFs@mongodb:27017/myapp?authSource=myapp
MONGODB_DATABASE=myapp

A partir daí o dia a dia é só mais alguns comandos:

shelf credentials myapp          # reimprime o .env quando eu perco
shelf add myapp -s signoz        # pluga um serviço a mais num app existente
shelf list                       # mostra todos os apps provisionados
shelf status                     # saúde dos containers de infra

Tem também uma UI web (shelf-web), e o detalhe importante é que ela não chama o CLI por baixo: as duas pontas importam a mesma biblioteca Go (internal/shelfcore) e chamam as mesmas funções. CLI e web fazem exatamente a mesma coisa, sem parsing de stdout no meio.


A tela de criação de apps

Quando eu não tô a fim de terminal, a UI web faz o mesmo provisionamento por formulário. A tela /apps tem o campo do nome do app (padrão [a-z][a-z0-9-]*), um campo opcional de environments (pra expandir em staging/production), checkboxes dos serviços e um botão Provision. Provisionado, dá pra revelar as credenciais e baixar o .env direto pela interface.

Tela de criação de apps do infra-shelf gerando os bancos

Roda em http://127.0.0.1:8080 com Basic Auth, é HTML renderizado no servidor (sem framework de frontend, SQLite puro-Go por baixo) e é o jeito que eu mais uso quando vou criar um app novo no fim de semana.


Backup — a rede de segurança

Talvez a parte que mais me dá paz. Consolidar tudo numa prateleira só também consolida o backup: é uma estratégia em vez de seis pastas perdidas.

shelf backup myapp               # um app, todos os serviços dele
shelf backup --all               # todos os apps provisionados
shelf restore myapp              # restaura do backup mais recente

Cada serviço é salvo do jeito certo pra ele:

ServiçoMétodo
PostgreSQLpg_dump --clean --if-exists
Redissnapshot das chaves do app (<app>:*)
RabbitMQexport de definitions (vhost/users/policies)
MongoDBmongodump do database do app

E dá pra agendar com retenção, que é como eu deixo rodando:

shelf schedule create myapp --cron "0 3 * * *" -z UTC --retention-days 14

Backup diário às 3h, guardando 14 dias. Em caso de catástrofe — pool que corrompe, volume que some — eu tenho de onde voltar. O registry com os secrets ainda pode ser cifrado em repouso (AES-256-GCM, via INFRA_SHELF_SECRET), então o arquivo de credenciais não fica em texto puro no disco.


”E a performance?”

A pergunta óbvia ao consolidar é se juntar tudo numa instância não piora as coisas. Na prática do homelab, não — e o motivo é meio bobo: aqueles seis containers já rodavam todos no mesmo hardware, competindo pelos mesmos CPU e I/O. Consolidar não criou disputa nova; ela já existia. O que mudou foi cortar o overhead de processo duplicado — cada instância de Postgres carrega seu próprio shared buffer, background workers e processos de WAL, e isso some quando vira uma instância só com vários databases.

Container por projetoInstância compartilhada
Nº de containers de banco1 por app (cresce sempre)1 por serviço (fixo)
Memória (overhead duplicado)altobaixo
Isolamentocontainerdatabase/user + ACL
Backupespalhadocentralizado
Conflito de portacomumnenhum (rede interna)

Tem número concreto pra isso: num caso de consolidação de Postgres no homelab, a memória caiu de ~3.2 GB em seis containers para ~1.8 GB numa instância única (DiyMediaServer). Bate com o que eu vi aqui: menos containers, mesma sensação de uso.

Sendo honesto sobre o trade-off: consolidar faz sentido pra cargas modestas, que é o caso de quase todo homelab. Se algum app tiver escrita pesada de verdade, exigência de isolamento estrito ou precisar de uma versão diferente do banco, aí sim vale uma instância dedicada pra ele. Pro resto, a prateleira compartilhada ganha de longe em simplicidade.


Como subir

Instalação em um comando:

curl -fsSL https://raw.githubusercontent.com/IvanMicai/infra-shelf/main/scripts/install.sh | bash

O script confere os pré-requisitos (git, docker, compose v2), clona o repo, cria o .env, builda os dois binários (usa Go local se tiver, senão builda dentro de um container) e sobe a stack core. Depois:

cd ./infra-shelf
# 1. trocar as senhas padrão no .env
# 2. shelf setup myapp -s postgres,redis,rabbitmq,mongodb
# 3. make app   →   http://127.0.0.1:8080

E pra quem usa Claude Code: o projeto traz uma skill (infra-shelf-install) que automatiza o install e ainda conecta o seu projeto à rede infra-shelf — ela verifica os pré-requisitos, troca as senhas padrão, provisiona o primeiro app e ajusta o compose do seu projeto pra entrar na rede externa.


Fechamento

Tá aberto no GitHub sob MIT: https://github.com/IvanMicai/infra-shelf. Se você também junta projeto self-hosted no homelab e tá cansado de subir um Postgres por app, dá pra trocar essa bagunça por uma prateleira só num fim de semana.

Se curte esse tipo de coisa, tem mais homelab por aqui — o pipeline de upscaling de anime e as 24 horas resgatando meu TrueNAS. Ideias, issues e PRs são bem-vindos. 🦥