Pular para o conteúdo

Primeiro deploy

Este é o fluxo base de todos os guias por stack. Escopos do token: projects:write, deploy, projects:read (veja Token de API). Todo POST que cria leva Idempotency-Key; repetir a mesma chave com o mesmo corpo devolve a mesma resposta.

Cada bloco abaixo é autossuficiente (variáveis P = id do projeto, S = id do serviço, D = id do deploy).

Um projeto é um grupo de serviços que compartilham rede e podem compartilhar variáveis por referência (Conceitos).

Janela do terminal
curl -sS -X POST "$NEBULAR_API/v1/projects" \
-H "Authorization: Bearer $NEBULAR_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pd-proj-$(date +%s)-$RANDOM" \
-d "{\"name\": \"meu-app-$(date +%s)-$RANDOM\"}"
{"id": "01j9zkk07fhzv5zsmn996cdwpb", "name": "meu-app-1760000000"}

Guarde id (P). Em erro:

Resposta O que fazer
401 Token ausente ou inválido. Pare e confira o cabeçalho.
403 forbidden Falta o escopo projects:write. Peça um token novo.
409 (ex.: slug_taken, project_quota_exceeded) Troque o nome ou apague um projeto que não usa mais.

Duas fontes (source) cobrem o primeiro deploy: imagem pública ou upload de código. Para visibility: "public" informe o slug (sai em https://<slug>.<domínio de apps>); omitido, a plataforma deriva um do nome. O web que todo projeto traz nasce público, já com slug e public_url (para privado: PATCH com {"visibility": "private"}; veja Conceitos).

Janela do terminal
SUF=$(date +%s)-$RANDOM
P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" \
-H "Authorization: Bearer $NEBULAR_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: pd-proj2-$SUF" -d "{\"name\": \"meu-app-$SUF\"}" | jq -r .id)
curl -sS -X PATCH "$NEBULAR_API/v1/projects/$P/services/web" \
-H "Authorization: Bearer $NEBULAR_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"visibility\": \"public\",
\"slug\": \"meu-app-$SUF\",
\"source\": {\"type\": \"image\", \"ref\": \"ghcr.io/org/app:1.2\"},
\"port\": 8080,
\"healthcheck_path\": \"/healthz\"
}"
{"id": "01j9zk3jremq8fkd3sjt7h300r", "name": "web", "kind": "app", "visibility": "public", "port": 8080}

Use "source": {"type": "upload"} e um build (builder = auto, node, go, rust, python, static ou dockerfile). Sem build, vale auto.

Janela do terminal
SUF=$(date +%s)-$RANDOM
P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" \
-H "Authorization: Bearer $NEBULAR_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: pd-proj3-$SUF" -d "{\"name\": \"meu-site-$SUF\"}" | jq -r .id)
curl -sS -X PATCH "$NEBULAR_API/v1/projects/$P/services/web" \
-H "Authorization: Bearer $NEBULAR_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"visibility\": \"public\",
\"slug\": \"meu-site-$SUF\",
\"source\": {\"type\": \"upload\"},
\"build\": {\"builder\": \"auto\"}
}"
{"id": "01j9zkngmvzxkw57zdyzz80b5e", "name": "web", "kind": "app", "visibility": "public", "port": 3000}

Regras do name: ^[a-z][a-z0-9-]{0,30}$, único no projeto (é o hostname na rede privada). port padrão: 3000.

Resposta O que fazer
400 invalid_request name, source.type, build.builder ou healthcheck_path inválidos: corrija o campo citado em message.
404 not_found O projeto não existe ou não é do seu time (as duas situações são indistinguíveis).
409 name_taken / slug_taken name ou slug já usado (todo projeto já nasce com um serviço web: use PATCH nele ou escolha outro nome). Troque.

Resposta imediata: o deploy fica queued e o build roda em seguida. Guarde o id (D).

Janela do terminal
# preparo (passos 1 e 2): projeto e serviço de imagem
SUF=$(date +%s)-$RANDOM
H="Authorization: Bearer $NEBULAR_TOKEN"
P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" -H "$H" -H "Content-Type: application/json" \
-d "{\"name\": \"pd4-$SUF\"}" | jq -r .id)
S=$(curl -sS -X PATCH "$NEBULAR_API/v1/projects/$P/services/web" -H "$H" -H "Content-Type: application/json" \
-d '{"source": {"type": "image", "ref": "ghcr.io/org/app:1.0"}}' | jq -r .id)
curl -sS -X POST "$NEBULAR_API/v1/projects/$P/services/$S/deployments" \
-H "$H" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pd-dep-$SUF" \
-d '{}'
{"id": "01j9zkv1t9ndd76xmr8ahxee7p", "status": "queued"}

Com source.type = "upload", envie o código como multipart/form-data nesta mesma rota (no lugar do corpo {}): -F "file=@fonte.tar.gz". Com git, o deploy usa o repositório e o branch do source.

Resposta O que fazer
403 forbidden Falta o escopo deploy.
409 deploy_in_progress Já existe um deploy em andamento para o serviço: consulte-o em vez de disparar outro.
unresolved_reference / reference_cycle Variável referenciada não existe ou há ciclo: veja Variáveis e referências.
429 Espere Retry-After (Rate limit e retry).

Não há webhooks neste ciclo. Consulte GET .../deployments/{d} começando em 2 s e dobrando até 30 s, por no máximo cerca de 10 minutos. Terminal de sucesso: ready. Terminais de falha: failed, blocked, canceled, superseded.

Janela do terminal
# preparo (passos 1 a 3): projeto, serviço de imagem e deploy
SUF=$(date +%s)-$RANDOM
H="Authorization: Bearer $NEBULAR_TOKEN"
P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" -H "$H" -H "Content-Type: application/json" \
-d "{\"name\": \"pd5-$SUF\"}" | jq -r .id)
S=$(curl -sS -X PATCH "$NEBULAR_API/v1/projects/$P/services/web" -H "$H" -H "Content-Type: application/json" \
-d '{"source": {"type": "image", "ref": "ghcr.io/org/app:1.0"}}' | jq -r .id)
D=$(curl -sS -X POST "$NEBULAR_API/v1/projects/$P/services/$S/deployments" -H "$H" \
-H "Content-Type: application/json" -d '{}' | jq -r .id)
delay=2
for i in $(seq 1 40); do
st=$(curl -sS "$NEBULAR_API/v1/projects/$P/services/$S/deployments/$D" -H "$H" | jq -r .status)
echo "tentativa $i: $st"
case "$st" in
ready) break ;;
failed|blocked|canceled|superseded) echo "deploy terminou em $st" >&2; exit 1 ;;
esac
sleep "$delay"; delay=$(( delay * 2 > 30 ? 30 : delay * 2 ))
done
[ "$st" = ready ]

Em failed, leia o log de build. Em blocked, um serviço do qual este depende falhou (Deploys e status). Em superseded, um deploy mais novo tomou o lugar: acompanhe o mais novo.

Com ready, o serviço público responde em https://<slug>.<domínio de apps>, onde <slug> é o que você enviou na criação.

Janela do terminal
curl -sS -o /dev/null -w '%{http_code}\n' "https://meu-app-1760000000.nebularws.com/healthz"

Se não for 200, leia os logs de runtime; para voltar à versão anterior, rollback. Para domínio próprio, Domínio próprio.

Janela do terminal
curl -sS "$NEBULAR_API/v1/projects" \
-H "Authorization: Bearer $NEBULAR_TOKEN"
{"items": [{"id": "01j9zkk07fhzv5zsmn996cdwpb", "name": "meu-app-1760000000"}], "next_cursor": null, "has_more": false}