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 mais tarde).
- Ingress (Traefik) + cert-manager — encaminhamento e TLS automático via Let's Encrypt.
- PostgreSQL e Redis in-cluster — a base de dados definitiva e a fila/pub-sub de registos.
- Registry de artefactos 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, base de dados equantic-space-db).Runners de CI
Os jobs de pipeline correm como pods isolados no cluster — um pod por job, com limites próprios de CPU/memória, pelo que um job pesado nunca esgota a plataforma nem os vizinhos. A capacidade é derivada do próprio cluster (reservando sempre folga para o control plane): os jobs além do limite aguardam na fila, e adicionar um nó à fleet aumenta automaticamente a capacidade de CI. Um job para o qual o cluster ainda não tem espaço quando o pod é criado também aguarda, e indica-o no registo, em vez de falhar. O timeout-minutes só começa a contar quando o pod existe.
Todos os containers do pod de um job têm limites — o próprio job, os sidecars de services: e o daemon Docker de cada job carregam tetos explícitos, e o disco do job tem um tamanho próprio (abaixo), pelo que um job desgovernado se despeja a si próprio em vez de pressionar o nó. O timeout-minutes do job também fica carimbado no pod: mesmo que o processo da plataforma morra a meio do job, o próprio cluster encerra o pod.
docker build (ou Testcontainers) dentro dos jobs? Passe EQS_RUNNER_DIND=true ao instalador — EQS_RUNNER_DIND=true bash install.sh, numa primeira instalação ou num update. Cada job passa a receber o seu próprio daemon Docker privado, nunca partilhado entre jobs ou workspaces. Aplica-se a todos os jobs da instalação, e o daemon é privilegiado, portanto ligue-o de propósito.Afinar a capacidade
O cálculo é um bom padrão, não uma sentença: em Configurações → Plataforma → Capacidade do CI decide quanto da máquina o runner pode tomar, e cada alteração mostra logo o que renderia neste cluster antes de gravar.
O painel ao lado dos campos responde à pergunta a que só os números nunca responderam: porquê só este tanto? Para o nó que lê, mostra o que o nó tem, o que a plataforma ocupa (o uso medido mais a folga da reserva, não só a percentagem), 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 tecto 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 cabem mais vagas a dividir 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 fica fixo quando o pod nasce, pelo que uma descida passageira da memória livre pode dar a um build de duas horas um limite sob o qual não termina. Abaixo do piso o nó não oferece vaga e o job espera na fila — tarde é melhor do que aleijado.
A reserva tem ainda um piso absoluto — pelo menos 2 cores e 3 GiB ficam com o control plane, diga o que disser a percentagem (em hosts minúsculos, encolhe sozinho). Um nó dedicado aos runners, sem plataforma nenhuma a correr nele, pode pôr o piso a zero via EQS_RUNNER_MIN_PLATFORM_RESERVE_CPU / EQS_RUNNER_MIN_PLATFORM_RESERVE_MEMORY_GI.
EQS_RUNNER_* apenas semeia uma instalação que nunca gravou aqui. A alteração entra em vigor num ciclo do orçamento (30 s), sem reiniciar nada. Limpe um campo para devolver essa decisão à plataforma, e a linha sob o rótulo diz sempre 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 para toda a vida. Esse número é um palpite sobre uma curva: um build é pequeno enquanto instala, grande enquanto verifica tipos de tudo ao mesmo tempo, e pequeno outra vez enquanto empacota. Palpite alto e o nó desperdiça-se; palpite baixo e um build de duas horas morre aos 95%.
Com a memória elástica ligada (vem ligada), a plataforma observa cada job em execução e sobe-lhe a memória no lugar quando se aproxima do tecto e o nó tem folga. Pedido e limite sobem juntos, por isso o pod mantém a classe de QoS e o escalonador continua a saber a verdade... e o orçamento vê o novo tamanho, por isso o job seguinte 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 vê: nunca na reserva da plataforma, nunca na fatia de outro job. O tecto do crescimento limita um job sozinho num nó grande. Ambos estão em Definições → Plataforma → Capacidade do CI.
exit 137: uma alocação única maior do que a folga restante mata na mesma o contentor entre duas leituras, e um nó sem nada livre não tem o que dar. Exige Kubernetes 1.33 ou mais recente para o resize no lugar — um cluster mais antigo mantém a fatia fixa de sempre.Um disco por job
Um job tem um único disco, como num runner do GitHub: o workspace, as imagens e a cache de build do Docker e tudo o resto que ele grava partilham o mesmo espaço. São pelo menos 14 GB, o que o GitHub documenta para o seu runner, e normalmente mais: a plataforma mede o disco livre de cada nó, mantém o piso de espaço livre que o armazenamento do CI defende (Definições → Plataforma → Armazenamento do CI, 15% por omissão) e divide o resto pelos jobs que correm. Quando o disco é o que se esgota primeiro, é ele que decide quantos jobs correm, e o painel ao lado dos campos indica-o.
Um job que grava além do seu disco é despejado pelo nó, e o registo dele diz que limite ultrapassou e onde esse limite é definido. Em Definições → Plataforma → Capacidade do CI define o piso com que um job é contado, ou fixa o disco de todos os jobs.
Execuções que nunca terminam
O tecto também se aplica 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 desapareceu ficaria em curso para sempre.
Por isso a plataforma desiste sozinha. Uma execução à espera de runner para além do tecto na fila (24 h por omissão), e uma execução em curso para além do tecto em execução (12 h), são terminadas por tempo; o mesmo para um job isolado para além do tecto por job (6 h), depois de quem o executava ter deixado de contar. O timeout-minutes do próprio job vence sempre este último. Os três estão em Definições → Plataforma → Capacidade do CI, e 0 desliga qualquer um deles.
E quando a fila não anda porque nada pode começar, o ecrã de execuções di-lo, com o tamanho de 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 lhe pede nada 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 durante dezasseis horas sem um único job.
Definições → Plataforma → Máquinas de runner passa a ter um interruptor para cada máquina que a própria plataforma executa. Desligar pede primeiro o encerramento ao sistema convidado e só depois pára a VM, o que é mais limpo e mais seguro do que matar o processo, e a memória volta de imediato para o resto da instalação.
Uma máquina que registou pelo endereço não é afectada: a plataforma liga-se a ela, não desliga o seu hardware.
Uma máquina que se desliga sozinha
Cada máquina que a plataforma executa tem a definição Desligar após … min ociosa, ao lado do interruptor. 0 é o valor por omissão e significa nunca — uma VM que leva minutos a arrancar não é o que toda a instalação quer parada a seguir a um almoço tranquilo.
Com um tecto definido, a plataforma desliga a máquina quando nada corre nela durante esse tempo, e liga-a novamente sozinha quando um job pede aquele sistema operativo. O job espera no seu próprio registo enquanto ela arranca, em vez de falhar numa ligação a algo que não está de pé.
Registos e retenção
Um único step pode armazenar até 50.000 linhas de registo (EQS_RUNNER_MAX_LOG_LINES_PER_STEP; 0 remove o teto). Ultrapassado o teto, o step continua a correr até à sua conclusão real — fica gravado um marcador de truncagem bem visível e o resto da saída é descartado, o que protege a base de dados e o stream ao vivo de um set -x desgovernado.
Os registos de step expiram ao fim de 90 dias, definidos no ecrã de Armazenamento do CI abaixo (0 guarda-os para sempre). As execuções, os jobs, as conclusões e as anotações ficam — o histórico continua navegável, só a transcrição em bruto expira. O garbage collector de blobs e a rotina de retenção do registry também vêm ligados por predefinição (cada EQS_REGISTRY_*_ENABLED=false desativa o seu): os blobs sem referência são recolhidos sozinhos, e uma política de retenção gravada no ecrã de Artefactos passa simplesmente a correr.
Armazenamento do CI
A cache do Actions e os artefactos das execuções ficam no armazenamento da plataforma, e numa instalação de um só servidor esse armazenamento é o próprio disco do servidor. Definições → Plataforma → Armazenamento do CI mantém-nos dentro de uma política, aplicada de hora a hora:
- Cache: as regras do GitHub. Sai a entrada que ninguém restaurou há mais de 7 dias, e um repositório que passe dos 10 GB perde primeiro as entradas usadas há mais tempo.
- Artefactos: guardados no máximo 90 dias (de 1 a 400). O
retention-daysde um workflow é respeitado quando pede menos, nunca mais. Baixar o valor encurta também os artefactos já guardados. - Limite total: a cache e os artefactos juntos podem ocupar um quinto do disco por predefinição (ou um número de GB;
0para nenhum). Acima disso, sai primeiro o que foi usado há mais tempo, cache ou artefacto, e os artefactos de uma execução em curso nunca saem. Regras por idade, sozinhas, não seguram um disco: um repositório que envia um pacote grande em cada build mantém tudo com menos de 90 dias e enche-o na mesma. Com armazenamento S3 não há disco para medir, por isso defina o limite em GB. - Manter livre: 15% do disco por predefinição. Quando o disco desce abaixo disso por qualquer motivo, o CI devolve exatamente o que falta, antes que o Kubernetes comece a expulsar pods. É verificado a cada cinco minutos.
O ecrã mostra o que o CI ocupa face ao limite, quem ocupa mais e o que as últimas limpezas removeram, falhas incluídas com o motivo; um número escrito aparece como pré-visualização contra este disco antes de gravar. Limpar agora aplica um limite acabado de baixar sem esperar pela 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ó servem de semente a uma instalação que nunca gravou esse ecrã.
A fatia da própria plataforma
A plataforma dimensiona os próprios pods a partir do host — a base de dados, a api e a web declaram requests de recursos derivados na instalação (e preenchidos retroativamente pelas atualizações), pelo que, sob carga, o kernel arbitra a favor da plataforma em vez de tratar um job de CI e a base de dados como iguais. O override é por componente, com variáveis ao estilo de EQS_PG_CPU_REQUEST, para quando conhece a sua máquina melhor do que a fórmula.