Laboratórios
Sessões curtas, do zero a um resultado que se verifica. Cada uma inclui a limpeza — nenhuma deixa nada para trás.
A verificação no fim de cada lab não é decorativa: é o que separa «copiei comandos» de «sei o que isto faz». Onde um passo pode falhar em silêncio, o lab diz exactamente o que olhar.
Primeiro serviço, em 60 segundos iniciante
Objectivo: perceber o ciclo run → ps → logs → exec → rm e ver
que não há daemon nenhum por baixo.
# 1. Um serviço web, em segundo plano, publicado na porta 8080 do host
delonix container run -d --name web -p 8080:80 nginx:alpine
# 2. Confirmar — o STATUS diz há quanto tempo está de pé
delonix ps
# 3. A prova de que não há daemon: NENHUM processo residente do motor
pgrep -a delonix || echo "sem daemon — o container é filho do init do host"
# 4. Falar com ele
curl -s localhost:8080 | head -3
# 5. Entrar lá dentro
delonix exec -it web sh -c 'hostname; id; ls /etc/nginx'
# 6. Ver o que ele escreveu
delonix logs web | tail -5
# 7. Limpar
delonix rm -f web
Verificação: o passo 3 não imprime processo nenhum do motor. Um container a correr sem supervisor residente é a diferença de fundo para o Docker, e vê-se aqui em duas linhas.
Limites de recursos que pegam mesmo iniciante
Objectivo: descobrir se este host aplica limites — e o que fazer quando não aplica. É o erro nº1 de quem começa em rootless.
# 1. Perguntar ANTES de assumir
delonix system setup
# 2. Se disser INERT ou PARTIAL, a 1.ª correcção não precisa de root nenhum
systemd-run --user --scope -p Delegate=yes -- delonix system setup
# … e é dentro desse scope que corres os passos seguintes.
# Só se ELE ainda disser que falta o `cpu`:
# sudo delonix system setup --delegate (+ logout / login)
# 3. Um container com tecto de memória
delonix container run -d --name limitado -m 128M alpine sleep 300
# 4. A prova: ler o cgroup REAL, não o que o comando diz
PID=$(delonix container inspect limitado | jq -r .pid)
cat /sys/fs/cgroup$(awk -F: '/^0::/{print $3}' /proc/$PID/cgroup)/memory.max
delonix rm -f limitado
Verificação: o passo 4 imprime
134217728 (128 MiB), não max. Se imprimir
max, a delegação não está feita — e o container corre sem
limite nenhum, em silêncio. É por isso que o passo 1 existe.
Nota: cpuset e io
aparecem quase sempre como absent, e está certo — num Ubuntu de
fábrica o user.slice (da root) só passa cpu memory
pids para baixo. Nada aqui precisa deles.
Duas aplicações que se falam por nome intermédio
Objectivo: rede de utilizador, DNS interno, e isolamento — sem configurar DNS nenhum.
# 1. Uma rede própria
delonix network create loja
# 2. Base de dados e app, ambas nela
delonix container run -d --name db --net loja -e POSTGRES_PASSWORD=x postgres:16-alpine
delonix container run -d --name app --net loja -p 8080:80 nginx:alpine
# 3. A app resolve a db PELO NOME, sem /etc/hosts nem variáveis
delonix exec app sh -c 'getent hosts db; nc -z db 5432 && echo "porta aberta"'
# 4. Fechar a db a tudo menos à app (alcançabilidade DIRIGIDA)
cat > dep.yaml <<'EOF'
apiVersion: delonix.io/v1
kind: Dependency
metadata:
name: app-conhece-db
spec:
from: app
to: db
ports: ["5432"]
EOF
delonix stack apply -f dep.yaml
# 5. Provar: um terceiro container na MESMA rede já não alcança a db
delonix container run --rm --net loja alpine sh -c 'nc -z -w2 db 5432 || echo BLOQUEADO'
delonix rm -f db app; delonix network rm loja; rm dep.yaml
Verificação: o passo 3 diz "porta aberta" e o
passo 5 diz "BLOQUEADO". A mesma rede, dois resultados — é isso que
kind: Dependency faz e uma rede sozinha não faz.
Do Dockerfile à imagem, sem daemon intermédio
Objectivo: construir uma imagem e correr o que construíste.
mkdir -p lab-build && cd lab-build
cat > Delonixfile <<'EOF'
FROM alpine:latest
RUN apk add --no-cache curl
COPY ola.txt /ola.txt
HEALTHCHECK CMD test -f /ola.txt
CMD ["sh", "-c", "cat /ola.txt; sleep 300"]
EOF
echo "construído com delonix" > ola.txt
# `Delonixfile` é procurado antes de `Dockerfile` — sem -f nenhum
delonix build -t minha-app:1.0 .
# `--wait` bloqueia até o HEALTHCHECK passar: sem isto escreve-se
# `until ...; do sleep 1; done`, e escreve-se mal
delonix run -d --name a1 --wait --health-interval 2 minha-app:1.0
delonix ps
delonix rm -f a1; delonix image rm minha-app:1.0; cd ..; rm -rf lab-build
Verificação: o ps mostra
(healthy) na coluna STATUS. O motor está a sondar o container
sozinho — sem systemd, ao contrário do Podman rootless.
Uma microVM a sério intermédio
Objectivo: uma VM completa com o mesmo CLI dos containers.
# 1. Sem imagem local, o create descarrega a oficial sozinho
delonix vm create dev
# 2. Onde ficou, e com que IP
delonix vm ls
delonix vm describe dev
# 3. Entrar (voltar ao host: Ctrl+])
delonix vm console dev
# 4. Checkpoint de sistema — memória E disco, com a VM a correr
delonix vm snapshot dev limpa
delonix vm snapshots dev
# 5. Estragar alguma coisa lá dentro e voltar atrás
delonix vm restore dev limpa
delonix vm rm dev
Verificação: o passo 4 devolve sem erro com a
VM A CORRER. Um snapshot de uma VM parada falha de propósito — o
vm stop faz undefine do domínio para não deixar
órfãos.
A tua própria imagem de VM, com VMfile avançado
Objectivo: construir uma imagem qcow2 à tua medida, como se constrói uma imagem de container.
mkdir -p lab-vm && cd lab-vm
# Scaffold que CONSTRÓI COMO ESTÁ — apaga o que não precisares
delonix vm init --vmfile --name minha-base
cat VMfile
# Precisa de libguestfs no host: sudo apt install libguestfs-tools
delonix vm build -t minha-base:1.0 .
delonix vm ls
# Um RUN com `apt-get install` precisa de rede no convidado, e pede-se:
# delonix vm build --network -t minha-base:1.0 .
# Arrancar a partir dela
delonix vm create teste --disk-image minha-base:1.0 --ssh-key @~/.ssh/id_ed25519.pub
# …ou a partir de um qcow2 publicado por ti, sem passar pelo store
delonix vm create outra --url-img https://o-teu-bucket/imagem.qcow2
delonix vm rm teste; cd ..; rm -rf lab-vm
Verificação: o build imprime
[1/1] stage-1: FROM ubuntu:24.04 e verifica o checksum da cloud
image. Com --url-img, se não houver <url>.sha256
publicado, o motor diz que está a confiar só no TLS — em vez de calar.
A chave que injectas vai para a conta delonix, não para a conta
default da distro — o bloco de próximos passos do vm create
imprime o ssh exacto.
Kubernetes sem Docker avançado
Objectivo: um cluster local cujo runtime dos nós É o Delonix.
# 1. Preflight — falha em milissegundos se faltar a delegação de `cpu`,
# em vez de descarregar 425 MB para morrer aos 90 segundos
delonix system setup
# 2. O cluster
delonix cluster create --name lab
# 3. Falar com ele
export KUBECONFIG=$(delonix cluster ls -o json | jq -r '.[0].kubeconfig')
kubectl get nodes -o wide
# 4. Levar uma imagem TUA para dentro dos nós, sem registo nenhum
delonix build -t app:dev .
delonix cluster load app:dev --name lab
kubectl run app --image=app:dev --image-pull-policy=Never
# 5. A prova que interessa
kubectl get pod app -w
delonix cluster delete --name lab
Verificação: o passo 5 chega a
Running. Nem o ctr images import nem o
crictl images provam isto — os dois já reportaram sucesso sobre
uma imagem que o kubelet depois não resolvia.