Provisionamento
O que a engine instala no passo Infraestrutura.
O passo Infraestrutura é onde tudo é montado no host. A engine instala, em sequência, com progresso transmitido ao vivo:
- k3s — Kubernetes leve e production-grade (escala para multi-node depois).
- Ingress (Traefik) + cert-manager — roteamento e TLS automático via Let's Encrypt.
- PostgreSQL e Redis in-cluster — o banco definitivo e a fila/pub-sub de logs.
- Registry de artefatos e os Runners de CI.
- Runtime serverless do Deploy.
- As imagens definitivas de api e web (deploy + migrações + seed do super admin como Jobs in-cluster).
equantic-space-* (namespace equantic-space, Deployments equantic-space-api / equantic-space-platform, banco equantic-space-db).Runners de CI
Os jobs de pipeline rodam como pods isolados no cluster — um pod por job, com limites próprios de CPU/memória, de modo que um job pesado nunca derruba a plataforma nem os vizinhos. A capacidade é derivada do próprio cluster (sempre reservando folga para o control plane): jobs além do teto esperam na fila, e adicionar um nó à fleet aumenta a capacidade de CI automaticamente. Um job para o qual o cluster ainda não tem espaço quando o pod é criado também espera, e diz isso no log, em vez de falhar. O timeout-minutes dele só começa a contar quando o pod existe.
Todo container do pod de um job é limitado — o próprio job, os sidecars de services: e o daemon Docker por job carregam tetos explícitos, e o disco do job tem um tamanho próprio (abaixo), de modo que um job desgovernado despeja a si mesmo em vez de pressionar o nó. O timeout-minutes do job também fica carimbado no pod: mesmo que o processo da plataforma morra no meio do job, o cluster aposenta o pod por conta própria.
docker build (ou Testcontainers) dentro dos jobs? Passe EQS_RUNNER_DIND=true para o instalador — EQS_RUNNER_DIND=true bash install.sh, na primeira instalação ou num update. Cada job passa a ganhar seu próprio daemon Docker privado, nunca compartilhado entre jobs ou workspaces. Vale para todos os jobs da instalação, e o daemon é privilegiado, então ligue de propósito.Ajustando a capacidade
O cálculo é um bom padrão, não uma sentença: em Configurações → Plataforma → Capacidade do CI você decide quanto da máquina o runner pode tomar, e cada alteração já mostra o que ela renderia neste cluster antes de você salvar.
O painel ao lado dos campos responde a pergunta que só os números nunca responderam: por que só esse tanto? Para o nó que ele lê, mostra o que o nó tem, o que a plataforma ocupa (o uso medido mais a folga da reserva, não só a porcentagem), o que sobra para o CI, a fatia de cada job, e o limite que decidiu a contagem, seja a CPU alvo por job, o piso de memória, o teto rígido, um tamanho fixo ou o piso de admissão. Com mais de um nó, escolha qual ler, e o total da frota aparece ao lado.
Dois botões importam mais. A reserva da plataforma é a fatia de cada nó que o CI nunca toca — baixá-la dá mais ao CI no total, mas aí cabem mais vagas dividindo a memória, e cada job pode acabar menor. E o "não iniciar abaixo de" é um piso de admissão: o teto de um job é congelado quando o pod nasce, então um vale passageiro de memória livre pode entregar a um build de duas horas um limite sob o qual ele não termina. Abaixo do piso o nó não oferece vaga e o job espera na fila — tarde é melhor que aleijado.
A reserva também tem um piso absoluto — pelo menos 2 cores e 3 GiB ficam com o control plane, diga o que disser o percentual (em hosts minúsculos, ele encolhe sozinho). Um nó dedicado só a runners, sem nada da plataforma rodando nele, pode zerar o piso via EQS_RUNNER_MIN_PLATFORM_RESERVE_CPU / EQS_RUNNER_MIN_PLATFORM_RESERVE_MEMORY_GI.
EQS_RUNNER_* só semeia uma instalação que nunca salvou aqui. A mudança passa a valer em até um ciclo do orçamento (30 s), sem reiniciar nada. Limpe um campo para devolver aquela decisão à plataforma, e a linha sob o rótulo sempre diz de onde veio o valor.Memória que cresce com o job
Um job recebia uma fatia de memória decidida no nascimento do pod e fixa pela vida inteira. Esse número é um chute sobre uma curva: um build é pequeno enquanto instala, grande enquanto checa tipos de tudo ao mesmo tempo, e pequeno de novo enquanto empacota. Chute alto e o nó é desperdiçado; chute baixo e um build de duas horas morre em 95%.
Com a memória elástica ligada (e ela vem ligada), a plataforma observa cada job em execução e sobe a memória dele no lugar quando ele se aproxima do teto e o nó tem folga. Pedido e limite sobem juntos, então o pod mantém a classe de QoS e o escalonador continua sabendo a verdade... e o orçamento enxerga o novo tamanho, então o próximo job não é admitido dentro da memória que este acabou de tomar.
Só cresce para dentro da folga que a mesma conta da admissão enxerga: nunca na reserva da plataforma, nunca na fatia de outro job. O teto do crescimento limita um job sozinho num nó grande. Os dois ficam em Configurações → Plataforma → Capacidade do CI.
exit 137: uma alocação única maior do que a folga restante ainda mata o container entre duas leituras, e um nó sem nada livre não tem o que dar. Exige Kubernetes 1.33 ou mais novo para o resize no lugar — um cluster mais antigo mantém a fatia fixa de sempre.Um disco por job
Um job tem um disco só, como num runner do GitHub: o workspace, as imagens e o cache de build do Docker e tudo o mais que ele grava dividem o mesmo espaço. São pelo menos 14 GB, o que o GitHub documenta para o runner dele, e em geral mais: a plataforma mede o disco livre de cada nó, mantém o piso de espaço livre que o armazenamento do CI defende (Configurações → Plataforma → Armazenamento do CI, 15% por padrão) e divide o resto entre os jobs que rodam. Quando o disco é o que acaba primeiro, ele decide quantos jobs rodam, e o painel ao lado dos campos mostra isso.
Um job que grava além do seu disco é despejado pelo nó, e o log dele diz qual limite passou e onde esse limite é definido. Em Configurações → Plataforma → Capacidade do CI você define o piso com que um job é contado, ou fixa o disco de todo job.
Execuções que nunca terminam
O teto também vale de fora para dentro. Quando o cluster nunca tem espaço — em geral um tamanho de job fixado acima do que qualquer nó oferece — as execuções atrás dele ficariam dias na fila, e um job cujo executor sumiu ficaria em andamento para sempre.
Então a plataforma desiste sozinha. Uma execução esperando runner além do teto na fila (24 h por padrão), e uma execução em andamento além do teto em execução (12 h), são encerradas por tempo; o mesmo vale para um job isolado além do teto por job (6 h), depois que quem o executava parou de contar. O timeout-minutes do próprio job sempre vence esse último. Os três ficam em Configurações → Plataforma → Capacidade do CI, e 0 desliga qualquer um deles.
E quando a fila não anda porque nada pode começar, a tela de execuções diz isso, com o tamanho que um job precisaria.
Desligar uma máquina de runner
Um runner Windows ou macOS é uma VM que esta instalação executa, e enquanto ninguém pede nada a ela são 8 GiB parados. Na instalação para a qual isto foi escrito, as duas seguraram 14,2 GiB e cerca de 2,4 cores por dezesseis horas sem um único job.
Configurações → Plataforma → Máquinas de runner agora tem um interruptor para cada máquina que a própria plataforma executa. Desligar pede primeiro o encerramento ao sistema convidado e só então para a VM, o que é mais limpo e mais seguro do que matar o processo, e a memória volta na hora para o resto da instalação.
Uma máquina que você registrou pelo endereço não é afetada: a plataforma se conecta a ela, não desliga o seu hardware.
Uma máquina que se desliga sozinha
Cada máquina que a plataforma executa tem a configuração Desligar após … min ociosa, ao lado do interruptor. 0 é o padrão e significa nunca — uma VM que leva minutos para bootar não é o que toda instalação quer parando depois de um almoço tranquilo.
Com um teto definido, a plataforma desliga a máquina quando nada roda nela por esse tempo, e a liga de novo sozinha quando um job pede aquele sistema operacional. O job espera no próprio log enquanto ela boota ("ligando, uma máquina fria leva alguns minutos para responder") em vez de falhar numa conexão com algo que não está de pé.
Logs e retenção
Um único step pode armazenar até 50.000 linhas de log (EQS_RUNNER_MAX_LOG_LINES_PER_STEP; 0 remove o teto). Passado o teto, o step continua rodando até sua conclusão real — um marcador de truncamento bem visível é gravado e o restante da saída é descartado, o que protege o banco e o stream ao vivo de um set -x desgovernado.
Logs de step expiram após 90 dias, definidos na tela de Armazenamento do CI abaixo (0 os guarda para sempre). Execuções, jobs, conclusões e anotações ficam — o histórico continua navegável, só a transcrição bruta expira. O garbage collector de blobs e a rotina de retenção do registry também vêm ligados por padrão (cada EQS_REGISTRY_*_ENABLED=false desliga o seu): blobs sem referência são recolhidos sozinhos, e uma política de retenção salva na tela de Artefatos simplesmente roda.
Armazenamento do CI
O cache do Actions e os artifacts das execuções ficam no storage da plataforma, e numa instalação de um servidor esse storage é o próprio disco do servidor. Configurações → Plataforma → Armazenamento do CI os mantém dentro de uma política, varrida a cada hora:
- Cache: as regras do GitHub. Sai a entrada que ninguém restaurou em mais de 7 dias, e um repositório que passa de 10 GB perde primeiro as entradas usadas há mais tempo.
- Artifacts: guardados por no máximo 90 dias (de 1 a 400). O
retention-daysde um workflow vale quando pede menos, nunca mais. Baixar o valor encurta também os artifacts já guardados. - Limite total: cache e artifacts juntos podem ocupar um quinto do disco por padrão (ou um número de GB;
0para nenhum). Acima disso, sai primeiro o que foi usado há mais tempo, cache ou artifact, e os artifacts de uma execução em andamento nunca saem. Regras por idade sozinhas não seguram um disco: um repositório que sobe um pacote grande a cada build mantém tudo com menos de 90 dias e o enche do mesmo jeito. Com storage S3 não há disco para medir, então defina o limite em GB. - Manter livre: 15% do disco por padrão. Quando o disco fica abaixo disso por qualquer motivo, o CI devolve exatamente o que falta, antes que o Kubernetes comece a despejar pods. É verificado a cada cinco minutos.
A tela mostra o que o CI ocupa frente ao limite, quem mais ocupa e o que as últimas varreduras removeram, falhas incluídas com o motivo; um número digitado aparece como prévia contra este disco antes de salvar. Varrer agora aplica um limite recém-baixado sem esperar a hora. As variáveis EQS_CI_CACHE_IDLE_DAYS, EQS_CI_CACHE_REPO_LIMIT_GB, EQS_CI_ARTIFACT_RETENTION_DAYS, EQS_CI_LOG_RETENTION_DAYS, EQS_CI_STORAGE_LIMIT_GB, EQS_CI_DISK_FLOOR_PERCENT só semeiam uma instalação que nunca salvou essa tela.
A fatia da própria plataforma
A plataforma dimensiona os próprios pods a partir do host — banco, api e web declaram requests de recursos derivados na instalação (e preenchidos retroativamente pelas atualizações), de modo que, sob carga, o kernel arbitra a favor da plataforma em vez de tratar um job de CI e o banco como iguais. Dá para sobrescrever por componente com variáveis no estilo EQS_PG_CPU_REQUEST, quando você conhece a sua máquina melhor do que a fórmula.