Preparar e compilar
Preparar o teu ambiente
Antes de leres: Começa aqui (Dia 0) e Fundações de Linux — as armadilhas do host abaixo são explicadas em termos de user namespaces e delegação de cgroup.
O Delonix Runtime é só para Linux: todos os primitivos que usa — namespaces, cgroups v2, nftables,
pivot_root, a nova API de mount — vivem no kernel Linux. Consegues compilar a maior parte do
workspace e correr os seus testes de lógica pura em qualquer máquina Linux com a toolchain abaixo;
para correr containers e exercitar os caminhos ao vivo precisas de um host que cumpra os requisitos
de kernel e de pacotes desta página. Depois dela o teu host passa o delonix system info, e quando
algo falha consegues distinguir um pré-requisito do host de um bug do motor.
Muito do que parece um bug do motor numa máquina acabada de instalar é um pré-requisito do host. Lê a secção Armadilhas conhecidas do host antes de abrires uma issue.
Toolchain#
- Toolchain de Rust:
1.96.0(fixada norust-toolchain.toml; orustupinstala-a na primeira chamada aocargo) - Componentes:
rustfmt,clippy
Instala o rustup e deixa-o apanhar o canal fixado; não o substituas por
stable. A CI usa exactamente o mesmo ficheiro (rustup show em todos os jobs).
protoc (necessário para compilar)#
O crates/interfaces/delonix-cri/build.rs compila o protobuf do CRI do Kubernetes com
tonic-build/prost, que precisa do compilador de Protocol Buffers no PATH. O binário delonix
depende do delonix-cri, por isso um simples cargo build --workspace falha sem ele:
# Debian / Ubuntu
sudo apt install protobuf-compiler
# Fedora / RHEL family
sudo dnf install protobuf-compiler
Ou descarrega uma release de https://github.com/protocolbuffers/protobuf/releases. A CI instala o
protobuf-compiler do apt em todos os jobs que compilam.
Ferramentas opcionais, só para gates específicos#
| Ferramenta | Necessária para | Onde está fixada |
|---|---|---|
| Python 3.11+ | todos os gates scripts/*.py (usam tomllib) |
— |
buf v1.73.0 e protoc-gen-openapi v0.7.1 (toolchain de Go para os instalar) |
scripts/ |
job contract em . |
cargo-deny |
a verificação da cadeia de fornecimento | job deny, configuração em deny.toml |
Módulo Python markdown |
docs/gen.py (renderiza o ARCHITECTURE.md) |
job docs |
groff |
verificar as man pages geradas | job docs |
Ver Clonar, compilar e testar para saber como cada uma é corrida.
Requisitos de kernel#
Estas são as funcionalidades do kernel de que o motor depende. O instalador (scripts/install.sh) e o
delonix system doctor verificam a maior parte delas por ti.
| Requisito | Porquê | Como verificar |
|---|---|---|
| cgroup v2 (hierarquia unificada) | os limites de recursos e a contabilização são escritos em /sys/fs/cgroup |
stat -fc %T / imprime cgroup2fs |
| User namespaces sem privilégio | o modelo rootless: o motor só se torna "root" dentro do seu próprio user namespace | unshare -r -n true tem sucesso |
/dev/net/tun |
slirp4netns (rede rootless) e taps de VM |
test -e /dev/net/tun |
overlayfs com a nova API de mount e lowerdir+ (Linux 6.5 ou mais recente) |
os sistemas de ficheiros raiz dos containers são mounts overlay construídos com fsopen/fsconfig/fsmount, uma chamada lowerdir+ por camada — ver ADR-0037 |
uname -r |
br_netfilter carregado, net. |
o isolamento de namespace é imposto em chains forward do nftables; sem este módulo o tráfego entre dois containers na mesma bridge nunca lhes chega, e o isolamento fica inerte em silêncio |
delonix system doctor |
KVM (/dev/kvm) |
só para microVMs — ver Construir microVMs | test -w /dev/kvm |
O requisito do 6.5 não tem verificação prévia: um kernel mais antigo falha quando o primeiro rootfs de container é montado, não no arranque (o ADR-0037 regista isto como uma escolha deliberada).
Em kernels Debian mais antigos os user namespaces sem privilégio estão desligados por
kernel.unprivileged_userns_clone=0; o instalador põe-no a 1.
Pacotes do host#
A fonte de verdade é o scripts/install.sh, que é também o
instalador oficial (é publicado como asset de release). Detecta o gestor de pacotes através de
/etc/os-release e suporta apt (Debian, Ubuntu e derivados), dnf (Fedora, RHEL,
CentOS Stream, Rocky, AlmaLinux), zypper (openSUSE, SLES) e pacman (Arch e
derivados). O instalador instala binários pré-compilados para x86_64 e aarch64 (arm64 é
normalizado): o nome do asset compõe-se a partir de uname -m como <name>-<arch>-linux, e qualquer
outra arquitectura pára com "no prebuilt binary for -v3 é um nível de microarquitectura x86-64 e
não existe lá; o Cloud Hypervisor estático fixado, o EDK2 CLOUDHV.fd e o hypervisor-fw são builds
x86-64, por isso não são descarregados (um cloud-hypervisor empacotado pela distro continua a ser
instalado se o gestor de pacotes o tiver) e o backend de VM é o libvirt; e a sonda do QEMU procura
qemu-system-aarch64. Os assets de release para aarch64 existem desde a v4.2.0 (a release v4.1.0 não
tem nenhum).
Não validado: uma instalação completa num host aarch64 real, e os nomes dos pacotes QEMU por
distro em arm64 — o que foi verificado é a composição do nome do asset contra os assets publicados da
v4.2.0.
Para correr containers o motor precisa de:
| Comando | Pacote (nomes apt / dnf) | Porquê |
|---|---|---|
slirp4netns |
slirp4netns |
rede rootless e portas publicadas — sem ele o run -p falha |
newuidmap / newgidmap |
uidmap / shadow-utils |
helpers setuid que mapeiam mais do que um uid no user namespace; sem eles as imagens com um utilizador não-root falham no chown() |
nft |
nftables |
firewall da SDN, isolamento e DNAT de portas |
ip |
iproute2 / iproute |
ligação de veth, bridge e netns |
conntrack (opcional) |
conntrack / conntrack-tools |
limpar ligações quando uma porta deixa de ser publicada |
Para VMs, qemu-img, cloud-localds (cloud-image-utils), virsh (libvirt) e/ou
Cloud Hypervisor com o seu firmware — ver Construir microVMs. Para construir imagens de VM,
libguestfs-tools (install.sh --with-image-build).
Precisas também de um intervalo subordinado de uid/gid para o teu utilizador em /etc/subuid e
/etc/subgid; sem ele o user namespace só consegue mapear um uid.
O caminho mais rápido para um host a funcionar#
Não tens de replicar o instalador à mão. Para instalar só as dependências e a configuração do host, mantendo o binário que tu próprio compilas:
bash scripts/install.sh --no-binary
Lê primeiro a lista de flags no topo do script: algumas flags mudam definições de segurança de todo o
host (--low-ports deixa qualquer programa local ligar-se a portas a partir da 80, --with-image-build
torna /boot/vmlinuz-* legível por todos), e --no-tune salta os módulos de kernel e os sysctls,
incluindo o br_netfilter. --performance / --no-performance controlam o modo de desempenho do CPU, as
hugepages transparentes com irqbalance, e um timer de utilizador que corre system prune --auto
--threshold 75; sem nenhuma das flags o instalador pergunta por cada um e, sem terminal, responde
não. A parte do CPU é um serviço systemd que guarda os valores do arranque e os repõe no stop.
Nada disto é preciso para desenvolver.
Memória e disco#
Não há um mínimo fixo. O que custa recursos é o que corres: imagens e camadas de containers, discos de
VM, e o próprio directório target/ do Rust (builds de debug do workspace inteiro ocupam vários
gigabytes). Vigia o espaço livre em disco — os kubelets de um cluster local começam a despejar pods
sob pressão de disco, o que depois parece um problema do motor.
Diagnosticar o host#
Compila o binário (ver Clonar, compilar e testar) e pergunta-lhe. Os comandos abaixo são só de
leitura, a menos que passes --delegate:
./target/debug/delonix system doctor # is every prerequisite met? says how to fix each
./target/debug/delonix system info # rootless?, cgroup delegation, network infra, counts
./target/debug/delonix system setup # diagnose cgroup delegation
./target/debug/delonix system resources # which controllers are delegated, which flags are ignored
O delonix system doctor --strict sai com código diferente de zero quando uma verificação falha, o que é
útil num script de provisionamento. Se correres estes comandos numa máquina que já tem uma instalação
do Delonix em uso, isola primeiro o estado (ver Isolar o estado do motor).
Armadilhas conhecidas do host#
Ubuntu 23.10+: o AppArmor bloqueia user namespaces para o teu binário de desenvolvimento#
O Ubuntu recente define kernel.apparmor_restrict_unprivileged_userns=1. Um binário sem perfil
AppArmor não consegue então criar um user namespace, e o motor morre no unshare() com EPERM —
o que se lê como um bug do motor.
O install.sh instala um perfil (/etc/apparmor.d/delonix, flags=(unconfined) com userns),
mas esse perfil está preso a um caminho: <install dir>/delonix (/usr/local/bin/delonix por
omissão, ~/.local/bin/delonix com --user). Um binário que acabaste de compilar em
target/debug/delonix — ou que copiaste para /tmp — não está coberto.
Opções, da menos para a mais invasiva:
- Acrescenta um segundo perfil para o teu caminho de desenvolvimento (por exemplo o
target/debug/delonixdo teu worktree), com a mesma forma do que o instalador escreve, e carrega-o comsudo apparmor_parser -r <file>. Isto não toca em nada do que já está a correr. - Instala o teu build no caminho com perfil (
sudo install -m 0755 target/debug/delonix /usr/local/bin/) — só numa máquina onde nenhum workload do Delonix esteja em uso. O binário instalado é o que as units de boot (ExecStart=<exe> container start …) e os servidores re-executam, por isso num host com workloads vivos um build de debug tornar-se-ia em silêncio o motor de produção. - Define
kernel.apparmor_restrict_unprivileged_userns=0— isto baixa uma fronteira de todo o host; só numa máquina que é tua.
Delegação de cgroup: uns limites são recusados, outros não são impostos#
Os limites de recursos só chegam ao kernel se a shell a partir da qual corres o motor estiver num cgroup delegado. Isto é uma regra do cgroup v2, não uma limitação do Delonix — o Podman rootless tem o mesmo requisito. Sem delegação o motor faz duas coisas diferentes, conforme a flag:
-m/--memory,-c/--cpuse--cpu-weight: ocontainer runrecusa antes de criar seja o que for, com um erro que diz como corrigir, e sai com 69 (Error::Unavailable, a classeEX_UNAVAILABLE—preflight_resource_limitsembins/delonix-runtime-bin/src/cmd/container.rs).DELONIX_ALLOW_UNENFORCED_LIMITS=1corre o container na mesma, sem limites, com um aviso.--cpuset,--io-weighte a família--device-read-bps/--device-write-bps/--device-read-iops/--device-write-iopssão verificados por controlador (preflight_controller_limits, que pergunta aoleaf_controllersemcrates/adapters/delonix-linux): sem o controladorcpuset/iono cgroup do container, ocontainer runrecusa com saída 69, com a mesma válvulaDELONIX_ALLOW_UNENFORCED_LIMITS=1. Medido a 2026-09-27: antes disto,--device-write-bps 5mbescrevia a 1,6 GB/s e saía 0.
Não existe a flag --pids-limit; o tecto de pids é uma propriedade do grupo de cgroup do motor, não
do container run.
O caso comum é uma sessão SSH: o seu scope fica fora da tua subárvore delegada, e a sessão não se consegue mover para lá sozinha — o porquê, com os comandos para o veres, está em Fundações de Linux — Delegação a utilizadores. A correcção por comando não precisa de root:
systemd-run --user --scope -p Delegate=yes -- ./target/debug/delonix container run -d -m 128M alpine sleep 60
Para workloads de longa duração, usa uma unit systemd de utilizador com Delegate=yes. Muitos
hosts delegam ao user@.service só cpu memory pids, e aí nenhum scope resolve cpuset/io:
um systemd-run --user --scope -p Delegate=yes só recebe o que o próprio user@.service tem
(medido: continua a 1,2 GB/s com --device-write-bps 5mb). O remédio é só de root, uma vez por
host — um drop-in /etc/systemd/system/user@.service.d/50-delonix-delegate.conf com [Service] e
Delegate=cpu cpuset io memory pids, depois systemctl daemon-reload e systemctl restart user@<uid>.service
(o daemon-reload sozinho não chega). O delonix system setup imprime-o, e lista em refused: as flags que o container run
vai recusar neste host. O sudo delonix system setup --delegate escreve esse drop-in seja qual for
o diagnóstico, corre o daemon-reload, e imprime o systemctl restart user@<uid>.service que ainda
falta; debaixo de sudo reporta sobre o user@<uid>.service de quem o chamou (do SUDO_UID), não sobre a root.
Um delonix antigo no teu PATH#
Se o Delonix estiver instalado na máquina, o delonix do teu PATH é a release instalada, não a tua
árvore. Corre sempre ./target/debug/delonix (ou target/release/delonix) quando testas uma mudança.
O --version mostra o commit e a distância à última tag
(commit: <hash> (+N commits since vX.Y.Z)), porque entre releases dois builds partilham o mesmo
número de versão.
Outras armadilhas que podes encontrar#
- Portas abaixo de 1024 falham em rootless com
slirp_add_hostfwd failed: a porta é ligada peloslirp4netns, um processo sem privilégio. Usa uma porta alta, ou faz opt-in cominstall.sh --low-ports. - Runners de CI alojados (alojados pelo GitHub) bloqueiam user namespaces sem privilégio. O workflow
de caos detecta isto e reporta
skipped, nãosuccess; para exercitar os caminhos ao vivo precisas de um host real, de um runner self-hosted ou de uma VM. - As armadilhas de firmware de VM e de construção de imagens (a escolha do firmware do Cloud
Hypervisor, um
passtantigo nos builds do libguestfs, as permissões de/boot/vmlinuz-*) são tratadas em Construir microVMs.
Seguinte: Clonar, compilar e testar — compilar, instalar e testar a tua árvore, e cada gate de CI como comando local.