Projecto completo: Delonix Temp
Do zero a um serviço na internet pública — build, run, e uma URL real, em 4 comandos. Tudo neste guia foi corrido a sério; o output é real, copiado da execução.
Uma API de tempo real em FastAPI — consulta a
temperatura ACTUAL de qualquer cidade (via Open-Meteo, sem
API key) e serve uma página que actualiza sozinha a cada 30s. O objectivo é percorrer o ciclo
completo do Delonix num só projecto pequeno: build multi-stage → container
run → expor à internet com tunnel. Os ficheiros completos estão em
examples/delonix-temp/
— git clone e segue os passos abaixo tal como estão.
1. A app
Três ficheiros. main.py — duas rotas: /api/weather/{city} (geocodifica
a cidade, pede a temperatura actual, devolve JSON) e / (uma página HTML que chama a
API própria via fetch e refaz a cada 30s):
from fastapi import FastAPI, HTTPException
from fastapi.responses import HTMLResponse
import httpx
app = FastAPI(title="Delonix Temp")
@app.get("/api/weather/{city}")
async def weather(city: str):
async with httpx.AsyncClient(timeout=8.0) as client:
geo = await client.get("https://geocoding-api.open-meteo.com/v1/search",
params={"name": city, "count": 1})
place = geo.json()["results"][0]
fc = await client.get("https://api.open-meteo.com/v1/forecast", params={
"latitude": place["latitude"], "longitude": place["longitude"],
"current": "temperature_2m,weather_code",
})
current = fc.json()["current"]
return {"city": place["name"], "country": place.get("country"),
"temperature_c": current["temperature_2m"], "observed_at": current["time"]}
@app.get("/", response_class=HTMLResponse)
async def index():
return PAGE # HTML com um <script> que faz fetch("/api/weather/"+city) a cada 30s
(versão completa, com a página HTML e /health, no ficheiro real do repo.)
requirements.txt — fastapi, uvicorn[standard],
httpx, com versões fixas.
Delonixfile — build multi-stage: um estágio instala as
dependências Python, o outro só copia o resultado + o código — a imagem final não carrega o
cache do pip nem ferramentas de build:
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY main.py .
ENV PYTHONUNBUFFERED=1
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
2. Build
cd examples/delonix-temp
delonix build -t delonix-temp:1 .
Collecting fastapi==0.115.0 (from -r requirements.txt (line 1))
...
Successfully installed annotated-types-0.7.0 anyio-4.14.2 ... fastapi-0.115.0 ...
ef708d73f029O ID no fim (ef708d73f029) é a imagem. delonix image ls confirma o
tamanho — o estágio final, sem as ferramentas de build, fica bem mais pequeno que se fosse tudo
num único FROM:
delonix image ls
REPOSITORY:TAG IMAGE ID CREATED SIZE
delonix-temp:1 ef708d73f029 agora mesmo 157.2 MiB
python:3.12-slim 25c5b8011a34 agora mesmo 41.2 MiB3. Correr
delonix container run -d --name delonix-temp -p 8080:80 delonix-temp:1
curl -s http://localhost:8080/api/weather/Luanda
{"city":"Luanda","country":"Angola","temperature_c":20.2,"observed_at":"2026-07-23T19:00"}Temperatura REAL, consultada ao vivo — não é um valor fixo. Os logs do container confirmam os pedidos:
delonix container logs delonix-temp
INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
INFO: 10.0.2.2:57786 - "GET /health HTTP/1.1" 200 OK
INFO: 10.0.2.2:57802 - "GET /api/weather/Luanda HTTP/1.1" 200 OK4. Expor à internet
Uma porta local não chega — o objectivo é uma URL que qualquer pessoa, em qualquer rede,
consiga abrir. É aqui que entra o kind: Tunnel:
delonix net tunnel expose --name delonix-temp --provider pinggy --local-port 8080
tunnel/delonix-temp: running — https://lfdhz-197-148-40-67.free.pinggy.netEssa URL é REAL — foi a que este guião recebeu ao correr o comando. (A tua vai ser diferente de cada vez: o provider grátis atribui uma nova de cada sessão.) Confirmação, de fora, sem tocar em nada local:
curl https://lfdhz-197-148-40-67.free.pinggy.net/api/weather/Luanda
{"city":"Luanda","country":"Angola","temperature_c":20.2,"observed_at":"2026-07-23T19:00"}O mesmo JSON, desta vez a chegar de fora da máquina, por um tunnel SSH até um servidor público (pinggy) e de volta — zero configuração de router, zero IP público próprio, zero conta. Abrir a URL num browser mostra a página Delonix Temp a actualizar-se sozinha.
Ir mais longe: com mais de um serviço, mete o kind:
HTTPRoute à frente (routing por Host/path para vários containers) e aponta
o tunnel para a PORTA DO PROXY em vez de directamente ao container — uma só URL
pública, tantos backends quantos precisares. Ver examples/httproute.yaml +
examples/tunnel.yaml.
Arrumar
delonix net tunnel rm delonix-temp
delonix container rm -f delonix-temp
O que isto provou
| Comando | O que validou |
|---|---|
delonix build | build multi-stage real (2 estágios, COPY --from), com rede no build |
delonix container run -p | NAT userspace sem root, porta publicada no host |
delonix container logs | observabilidade de um serviço real a correr |
delonix net tunnel expose | tráfego REAL da internet pública a chegar a um container local, sem conta nem IP público |