Padrões de Infraestrutura SOLID & Docker
Para manter a infraestrutura do Elo Orgânico, as ferramentas de DevOps e as automações do repositório altamente modulares, extensíveis e robustas, aplicamos os princípios de design SOLID diretamente aos layouts de diretórios, scripts shell, orquestração Docker e pipelines de CI/CD.
1. Aplicação Arquitetural do SOLID
Princípio da Responsabilidade Única (SRP)
Cada diretório e arquivo de configuração deve atender a exatamente um propósito operacional.
- Separação de Preocupações: Separamos os ambientes de serviço específicos de tempo de execução (runtime) dos scripts de automação executados no host, modelos de esquemas de configuração e arquivos de orquestração.
- Módulos de CI Reutilizáveis: Os fluxos de trabalho sob
.github/workflows/não devem duplicar a lógica de configuração do ambiente. Comportamentos compartilhados (como execução do node, instalações do PNPM e configurações de cache) são extraídos em GitHub Composite Actions independentes em.github/actions/.
Princípio Aberto/Fechado (OCP)
A infraestrutura deve estar aberta para extensão, mas fechada para modificação.
- Serviços Plugáveis: Os serviços conteinerizados estão localizados sob um namespace unificado
services/. Adicionar uma nova ferramenta ou container downstream exige apenas criar uma pasta independente (por exemplo,services/slack-notifier/) com sua própria configuração de ambiente, deixando os containers existentes do workspace e os scripts de automação intocados.
Princípio de Substituição de Liskov (LSP)
Todos os serviços conteinerizados devem estar em conformidade com um contrato de interface padronizado.
- Contrato de Layout do Serviço: Cada subdiretório de ferramenta deve implementar uma interface uniforme que consiste em um
Dockerfilena raiz, umentrypoint.shimplementando parâmetros padrão de logging e verificação de saúde (healthcheck) e ganchos de volume isolados. - API Unificada: Os scripts executados nos containers devem operar sob sinais de processo e associações de ambiente correspondentes.
Princípio da Segregação de Interface (ISP)
Cada serviço deve receber apenas os inputs e privilégios de sistema necessários para realizar sua tarefa específica.
- Segregação Estrita de Env: Não passe um arquivo
.envmonolítico contendo todos os segredos do sistema para todos os containers. Em vez disso, defina arquivos de ambiente separados (por exemplo,.env.gh-clie.env.git-agent) para que cada container opere dentro de sua superfície de segurança mínima.
Princípio da Inversão de Dependência (DIP)
Scripts de alto nível devem depender de interfaces abstratas de ambiente, e não de representações de caminhos físicos do host.
- Abstração de Caminho: Scripts shell executados dentro de containers nunca devem usar caminhos relativos rígidos (hardcoded) para encontrar configurações na máquina host. Em vez disso, dependem de limites de variáveis de ambiente (como
$SECRETS_DIRe$VARIABLES_FILE). - Injeção de Dependência: A camada de orquestração (
docker-compose.yamlou o executor do container) mapeia volumes físicos do host para os locais abstratos de arquivos esperados dentro do container.
2. Estrutura de Diretórios Padrão
Abaixo está a estrutura de diretórios exigida para workspaces de ferramentas do repositório (como tools/github/):
tools/github/
├── config/ # Esquemas de configuração e modelos de schemas
│ ├── security/
│ │ ├── .env.actions.secrets.example
│ │ └── variables.json
│ └── schemas/
│ └── secrets.schema.json
├── infrastructure/ # Camada de Orquestração
│ ├── docker/
│ │ ├── compose.yaml # Compositor Central Multi-Serviço
│ │ ├── .env.infra
│ │ └── .env.infra.example
│ └── logs/ # Logs de sistema isolados
├── scripts/ # Automação TS Executada no Host
│ ├── generate-changelog.ts
│ └── generate-roadmap.ts
└── services/ # Módulos de Serviço Plugáveis
├── gh-cli/ # Serviço de Sincronização do GitHub CLI
│ ├── Dockerfile
│ ├── entrypoint.sh # Contrato de entrypoint unificado
│ ├── .env.gh-cli.example
│ └── src/
│ └── sync_repo_secrets_variables.sh
└── git-agent/ # Automação de Commit / Assinatura do Git
├── Dockerfile
├── entrypoint.sh
├── .env.git-agent.example
└── src/
3. Modelos de Implementação
Componente de CI Reutilizável: .github/actions/setup-pnpm-env/action.yml (SRP)
Em vez de duplicar configurações de dependências nos workflows do GitHub, extraia-os em uma ação composta:
name: 'Setup PNPM Environment'
description: 'Installs Node, PNPM, and configures dependency caching'
inputs:
node-version:
description: 'Node.js version to use'
required: false
default: '22'
runs:
using: 'composite'
steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
cache: 'pnpm'
- name: Install Dependencies
shell: bash
run: pnpm install
Contrato de Script Desacoplado: sync_repo_secrets_variables.sh (DIP)
Este script depende estritamente de parâmetros injetados pelo ambiente, abstraindo completamente os caminhos físicos de disco na máquina executora:
#!/usr/bin/env bash
set -euo pipefail
log_info() {
echo "[GH-CLI INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_error() {
echo "[GH-CLI ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
}
# Verifica se as dependências foram injetadas via ambiente
if [[ -z "${SECRETS_DIR:-}" ]]; then
log_error "A variável de ambiente obrigatória SECRETS_DIR não está definida."
exit 1
fi
if [[ -z "${VARIABLES_FILE:-}" ]]; then
log_error "A variável de ambiente obrigatória VARIABLES_FILE não está definida."
exit 1
fi
log_info "Lendo variáveis de: $VARIABLES_FILE"
log_info "Escaneando diretório de segredos: $SECRETS_DIR"
if [[ ! -f "$VARIABLES_FILE" ]]; then
log_error "Arquivo de variáveis não encontrado em: $VARIABLES_FILE"
exit 1
fi
log_info "Sincronização concluída com sucesso."
Orquestrador Desacoplado: compose.yaml (DIP & ISP)
O orquestrador mapeia arquivos físicos locais para os alvos abstratos exigidos pelo limite do container:
services:
gh-cli:
build:
context: ../../services/gh-cli
dockerfile: Dockerfile
container_name: elo-tools-gh-cli
env_file:
- .env.infra
environment:
- SECRETS_DIR=/etc/github-tool/secrets
- VARIABLES_FILE=/etc/github-tool/variables/variables.json
- GITHUB_TOKEN=${GITHUB_TOKEN}
volumes:
- ../../config/security/secrets:/etc/github-tool/secrets:ro
- ../../config/security/variables:/etc/github-tool/variables:ro
- ../../infrastructure/logs:/var/log/gh-cli:rw
restart: 'no'
Sob este layout, adicionar um novo container de ferramentas (por exemplo, sentry-uploader ou sonar-scanner) é tão simples quanto colocar uma pasta sob services/, estabelecer seus requisitos de .env e registrá-lo em /infrastructure/docker/compose.yaml. As ações de core, fluxos de trabalho e diretórios de configuração existentes permanecem bloqueados e completamente seguros.