Quickstart
In five minutes you'll have a Linux microVM running on a ScaiBunker worker, you'll execute a command in it, drop a file into it, and tear it down.
You need:
- A ScaiGrid API key with
scaibunker:create and scaibunker:execute (any tenant admin has these).
- The managed endpoint, or a self-hosted ScaiGrid with at least one worker registered.
| export SCAIGRID_HOST="https://scaigrid.scailabs.ai"
export SCAIGRID_API_KEY="sgk_..."
|
1. Create the bunker
POST to /bunkers with the image, lifecycle mode, network profile, and resource request. Defaults are sensible for a one-off Python workload.
| curl -X POST "$SCAIGRID_HOST/v1/modules/scaibunker/bunkers" \
-H "Authorization: Bearer $SCAIGRID_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image":"python-3.12","lifecycle_mode":"ephemeral","network_profile":"registry","cpu_millicores":1000,"memory_mb":512,"disk_mb":1024}'
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | import httpx, os
HOST = os.environ["SCAIGRID_HOST"]
H = {"Authorization": f"Bearer {os.environ['SCAIGRID_API_KEY']}"}
bunker = httpx.post(
f"{HOST}/v1/modules/scaibunker/bunkers",
headers=H,
json={
"image": "python-3.12",
"lifecycle_mode": "ephemeral",
"network_profile": "registry",
"cpu_millicores": 1000,
"memory_mb": 512,
"disk_mb": 1024,
},
).json()["data"]
print(bunker["id"], bunker["status"])
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | const HOST = process.env.SCAIGRID_HOST;
const H = { "Authorization": `Bearer ${process.env.SCAIGRID_API_KEY}` };
const res = await fetch(`${HOST}/v1/modules/scaibunker/bunkers`, {
method: "POST",
headers: { ...H, "Content-Type": "application/json" },
body: JSON.stringify({
image: "python-3.12",
lifecycle_mode: "ephemeral",
network_profile: "registry",
cpu_millicores: 1000,
memory_mb: 512,
disk_mb: 1024,
}),
});
const { data: bunker } = await res.json();
console.log(bunker.id, bunker.status);
|
Save the returned bunker.id — every subsequent call references it. Status starts at pending and flips to running once the worker has booted the microVM (usually under a second on a warm worker).
2. Run a command
Send a shell command to the bunker. The registry profile lets pip reach PyPI; the install takes a few seconds on a warm worker.
| curl -X POST "$SCAIGRID_HOST/v1/modules/scaibunker/bunkers/$BUNKER_ID/exec" \
-H "Authorization: Bearer $SCAIGRID_API_KEY" \
-H "Content-Type: application/json" \
-d '{"command":"pip install --quiet pandas && python -c \"import pandas; print(pandas.__version__)\"","timeout_s":120}'
|
| result = httpx.post(
f"{HOST}/v1/modules/scaibunker/bunkers/{bunker['id']}/exec",
headers=H,
json={
"command": "pip install --quiet pandas && python -c 'import pandas; print(pandas.__version__)'",
"timeout_s": 120,
},
timeout=180,
).json()["data"]
print(result["exit_code"], result["stdout"])
|
| const r = await fetch(`${HOST}/v1/modules/scaibunker/bunkers/${bunker.id}/exec`, {
method: "POST",
headers: { ...H, "Content-Type": "application/json" },
body: JSON.stringify({
command: "pip install --quiet pandas && python -c 'import pandas; print(pandas.__version__)'",
timeout_s: 120,
working_dir: "/workspace",
}),
});
const { data } = await r.json();
console.log(data.exit_code, data.stdout);
|
You should see the pandas version printed in stdout. The registry profile lets pip reach PyPI; on the isolated profile the install would fail with no route to host.
3. Write and read a file
PUT and GET against /files/{path} write and read bytes inline. The path is rooted at the bunker's filesystem; conventionally use /workspace for caller-supplied data.
| printf "name,score\nalice,42\nbob,17\n" > scores.csv
curl -X PUT "$SCAIGRID_HOST/v1/modules/scaibunker/bunkers/$BUNKER_ID/files/workspace/scores.csv" \
-H "Authorization: Bearer $SCAIGRID_API_KEY" --data-binary @scores.csv
curl "$SCAIGRID_HOST/v1/modules/scaibunker/bunkers/$BUNKER_ID/files/workspace/scores.csv" \
-H "Authorization: Bearer $SCAIGRID_API_KEY"
|
Files under /workspace are the convention for caller-supplied data.
4. Snapshot before terminating
To preserve state before tearing down, take a snapshot. Or pass ?snapshot=true on terminate (step 5) to do snapshot-then-destroy in one call.
| curl -X POST "$SCAIGRID_HOST/v1/modules/scaibunker/bunkers/$BUNKER_ID/snapshot" \
-H "Authorization: Bearer $SCAIGRID_API_KEY"
|
The snapshot id comes back on the bunker record; download the archive later with GET /snapshots/{id}/archive.
5. Terminate
DELETE on the bunker tears it down and decrements your tenant's quota counters across every bucket the bunker contributed to.
| curl -X DELETE "$SCAIGRID_HOST/v1/modules/scaibunker/bunkers/$BUNKER_ID?snapshot=true" \
-H "Authorization: Bearer $SCAIGRID_API_KEY"
|
What just happened
The scheduler picked one worker and booted a Firecracker microVM with the python-3.12 ext4 rootfs, attached to a registry-profile network namespace. Every exec and file call streamed through ScaiGrid to the worker; large outputs go to S3 via the storage proxy. Quota counters in Redis went up on create and back down on terminate. Next: read Architecture, Network profiles, and the data analysis tutorial.