Zaroz
Guías de Workloads

Despliega un Workload desde una imagen pública

Esta guía te lleva de cero a un Workload en marcha usando solo la API. Ejecuta nginx desde Docker Hub, pero cualquier imagen pública funciona igual.

El Workload se llamaba antes Container; los nombres de archivo de las guías conservan la palabra antigua.

Antes de empezar

Necesitas una cuenta con una organización, saldo en la cartera u otra forma de pagar, y un token. Los ejemplos leen dos variables de entorno:

TerminalCode
export ZAROZ_API="https://kernel.zaroz.cloud/api/v2" export ZAROZ_TOKEN="<tu token de sesión o token de acceso personal>"

Cada petición envía Authorization: Bearer $ZAROZ_TOKEN. Los ejemplos de TypeScript necesitan Node 20 o posterior (ejecútalos con npx tsx archivo.ts); los de Python necesitan pip install requests. Todos usan este pequeño ayudante, que se muestra una sola vez:

TypeScript

TypeScriptCode
const API = process.env.ZAROZ_API ?? "https://kernel.zaroz.cloud/api/v2"; const TOKEN = process.env.ZAROZ_TOKEN!; export async function api(method: string, path: string, body?: unknown) { const res = await fetch(API + path, { method, headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), }); if (!res.ok) throw new Error(`${method} ${path} -> ${res.status} ${await res.text()}`); return res.status === 204 ? null : res.json(); }

Python

Code
import os, requests API = os.environ.get("ZAROZ_API", "https://kernel.zaroz.cloud/api/v2") S = requests.Session() S.headers["Authorization"] = "Bearer " + os.environ["ZAROZ_TOKEN"] def api(method, path, body=None, **params): r = S.request(method, API + path, json=body, params=params or None) r.raise_for_status() return None if r.status_code == 204 else r.json()

1. Encuentra el producto, un plan y una región

Lista el catálogo y elige el producto Workload por su name. Después pide sus planes en una región, y las regiones en las que puedes comprar.

TerminalCode
curl -s "$ZAROZ_API/catalog/products?page_size=100" -H "Authorization: Bearer $ZAROZ_TOKEN" | jq '.data[] | {id, name, slug}' curl -s "$ZAROZ_API/catalog/regions?product_id=$PRODUCT_ID" -H "Authorization: Bearer $ZAROZ_TOKEN" | jq '.data[] | {id, name, available}' curl -s "$ZAROZ_API/catalog/products/$PRODUCT_ID/plans?region_id=$REGION_ID" -H "Authorization: Bearer $ZAROZ_TOKEN" | jq '.data[] | {id, name, price, available}'
TypeScriptCode
import { api } from "./api"; const products = await api("GET", "/catalog/products?page_size=100"); const product = products.data.find((p: any) => /workload/i.test(p.name)); const regions = await api("GET", `/catalog/regions?product_id=${product.id}`); const region = regions.data.find((r: any) => r.available); const plans = await api("GET", `/catalog/products/${product.id}/plans?region_id=${region.id}`); const plan = plans.data.find((p: any) => p.available);
Code
products = api("GET", "/catalog/products", page_size=100) product = next(p for p in products["data"] if "workload" in p["name"].lower()) regions = api("GET", "/catalog/regions", product_id=product["id"]) region = next(r for r in regions["data"] if r["available"]) plans = api("GET", f"/catalog/products/{product['id']}/plans", region_id=region["id"]) plan = next(p for p in plans["data"] if p["available"])

plan.price es el precio mensual; la tarifa de unidad extra es ese precio dividido entre 720 (mira Facturación).

2. Cotiza la compra

Una cotización pone precio a la compra sin comprar nada. Envía el cuerpo de checkout sin name ni slug.

TerminalCode
curl -s -X POST "$ZAROZ_API/checkout/quote" \ -H "Authorization: Bearer $ZAROZ_TOKEN" -H "Content-Type: application/json" \ -d "{\"product_id\":\"$PRODUCT_ID\",\"plan_id\":$PLAN_ID,\"region_id\":$REGION_ID}"
TypeScriptCode
const quote = await api("POST", "/checkout/quote", { product_id: product.id, plan_id: plan.id, region_id: region.id, }); console.log(quote.total_cents, quote.currency, quote.cadence_label);
Code
quote = api("POST", "/checkout/quote", { "product_id": product["id"], "plan_id": plan["id"], "region_id": region["id"], }) print(quote["total_cents"], quote["currency"], quote["cadence_label"])

3. Cómpralo

El checkout crea una suscripción pendiente y la factura que la establece. name lo eliges tú. slug es el segmento de URL que identifica el servicio, único dentro de su proyecto; además se convierte en el nombre privado del Workload.

TerminalCode
curl -s -X POST "$ZAROZ_API/checkout" \ -H "Authorization: Bearer $ZAROZ_TOKEN" -H "Content-Type: application/json" \ -d "{\"product_id\":\"$PRODUCT_ID\",\"plan_id\":$PLAN_ID,\"region_id\":$REGION_ID,\"name\":\"Web\",\"slug\":\"web\"}"
TypeScriptCode
const order = await api("POST", "/checkout", { product_id: product.id, plan_id: plan.id, region_id: region.id, name: "Web", slug: "web", }); const subscriptionId = order.subscription.id; const invoiceId = order.invoice.id;
Code
order = api("POST", "/checkout", { "product_id": product["id"], "plan_id": plan["id"], "region_id": region["id"], "name": "Web", "slug": "web", }) subscription_id = order["subscription"]["id"] invoice_id = order["invoice"]["id"]

Añade organization_id para facturar a una organización en lugar de a tu cuenta personal, y project_id para archivarlo en un proyecto concreto. Si omites project_id, se usa el proyecto por defecto de la organización.

4. Paga la factura

Desde la cartera:

TerminalCode
curl -s -X POST "$ZAROZ_API/billing/invoices/$INVOICE_ID/pay-with-wallet" -H "Authorization: Bearer $ZAROZ_TOKEN"
TypeScriptCode
await api("POST", `/billing/invoices/${invoiceId}/pay-with-wallet`);
Code
api("POST", f"/billing/invoices/{invoice_id}/pay-with-wallet")

Para pagar con tarjeta o PayPal, inicia el checkout de la factura (/billing/invoices/{id}/checkout/mollie o .../paypal) y sigue el enlace devuelto. Una vez pagada, la suscripción se activa y el aprovisionamiento empieza solo.

5. Encuentra la instancia de servicio

La suscripción es la compra; la instancia de servicio es lo que se ejecuta. Lee la suscripción para obtener su project_id y sus recursos para obtener el id de la instancia. Espera a que el estado sea active.

TerminalCode
curl -s "$ZAROZ_API/subscriptions/$SUBSCRIPTION_ID" -H "Authorization: Bearer $ZAROZ_TOKEN" | jq '{status, project_id}' curl -s "$ZAROZ_API/subscriptions/$SUBSCRIPTION_ID/resources" -H "Authorization: Bearer $ZAROZ_TOKEN" | jq '.service_instance.id'
TypeScriptCode
const sub = await api("GET", `/subscriptions/${subscriptionId}`); // espera a sub.status === "active" const projectId = sub.project_id; const res = await api("GET", `/subscriptions/${subscriptionId}/resources`); const serviceId = res.service_instance.id;
Code
sub = api("GET", f"/subscriptions/{subscription_id}") # espera a sub["status"] == "active" project_id = sub["project_id"] res = api("GET", f"/subscriptions/{subscription_id}/resources") service_id = res["service_instance"]["id"]

Si el producto hace preguntas de configuración, GET /service-instances/{id}/setup lista los pasos sin responder, y responder el último inicia el primer aprovisionamiento (PUT /service-instances/{id}/setup/steps/{step}).

6. Indica qué imagen ejecutar

Guardar el origen no arranca nada; solo registra lo que descargará el próximo despliegue. Usa kind: registry. Para una imagen pública, no envíes credentials.

TerminalCode
curl -s -X PUT "$ZAROZ_API/service-instances/$SERVICE_ID/source" \ -H "Authorization: Bearer $ZAROZ_TOKEN" -H "Content-Type: application/json" \ -d '{"kind":"registry","host":"docker.io","repository":"nginx","tag":"1.27"}'
TypeScriptCode
const source = await api("PUT", `/service-instances/${serviceId}/source`, { kind: "registry", host: "docker.io", repository: "nginx", tag: "1.27", }); console.log(source.image_reference); // docker.io/library/nginx:1.27
Code
source = api("PUT", f"/service-instances/{service_id}/source", { "kind": "registry", "host": "docker.io", "repository": "nginx", "tag": "1.27", }) print(source["image_reference"])

Zaroz completa con library/ un nombre de un solo segmento de Docker Hub, así que nginx funciona. Usa una etiqueta concreta; la plataforma no vuelve a descargar cuando una etiqueta se mueve (watch_tag es siempre false).

7. Despliega

Un despliegue no lleva cuerpo. Envía el origen exactamente como está guardado.

TerminalCode
curl -s -X POST "$ZAROZ_API/service-instances/$SERVICE_ID/deployments" -H "Authorization: Bearer $ZAROZ_TOKEN"
TypeScriptCode
const deployment = await api("POST", `/service-instances/${serviceId}/deployments`); // consulta hasta que se registre el resultado for (;;) { const d = await api("GET", `/service-instances/${serviceId}/deployments/${deployment.id}`); if (d.outcome) { console.log(d.outcome, d.failure_reason); break; } await new Promise((r) => setTimeout(r, 3000)); }
Code
import time deployment = api("POST", f"/service-instances/{service_id}/deployments") while True: d = api("GET", f"/service-instances/{service_id}/deployments/{deployment['id']}") if d["outcome"]: print(d["outcome"], d.get("failure_reason")); break time.sleep(3)

outcome es succeeded o failed; null significa que aún no se ha registrado, nunca un fallo. Tu Workload ya ejecuta una unidad.

Siguientes pasos

Last modified on