Capsules
Create a short-lived, isolated capsule that runs one command, follow its state, and read its output and record.
Last updated
On this page
Overview
A capsule is a disposable container for one command or one shell. It is deleted when it exits. It is not a long-lived sandbox: that is a workspace. It has a file system, a toolchain, and a network. It has no effect on other workspaces.
A capsule runs one main process. You give the command at creation. The capsule ends when that process exits. Other processes can run inside the capsule, but the capsule waits only for the main one.
A capsule runs once. When it ends, its files are gone and it cannot start again. To run again, create a new capsule.
| Way to run | Use | Command |
|---|---|---|
| Create | Start a capsule, keep its id, and read the output and the exit code later. See Create a capsule with a command. | kode capsules create -- cmd |
| Run | Run one command and read its output and exit code in one step. The capsule ends with the command. See Run a command. | kode capsules run -- cmd |
| Run with a terminal | Type to the process. Add -it. See Open a shell. | kode capsules run -it -- sh |
Each capsule has its own kernel, file system, and network stack, with allocated vCPU, memory, and disk. A capsule belongs to you or to a team that you are an active member of. Nobody else sees it. The platform gives it an id that starts with cap-.
| Part | Description |
|---|---|
| Main process | The command that you give at creation. See Commands and Shell. |
| Disk | /home/kl. It is removed when the capsule ends. The home is not kept. |
| Working directory | ~/workspace. The main process starts here. |
| Packages | The toolchain, from nixpkgs. Give name or name@version at creation. |
| Output | The live output of the main process, then its last 256 KiB. See Read the output. |
| Network | Internet access, or none. The network none gives no DNS and no internet. |
| Resources | 1 to 8 vCPU, 1 to 32 GB of memory, and a disk that grows with the files. |
Capsule types
A capsule is standalone or in a desk. The type is set at creation and does not change.
| Aspect | Standalone | In a desk |
|---|---|---|
| Created with | POST /v1/capsules | POST /v1/desks/{id}/capsules. See Capsules. |
| Ended by | The main process, you, or the time limit | The main process, you, the time limit, or the end of its desk |
| Reaches an environment | No | The desk's environment, and no other. See Capsules. |
desk field | Empty | The desk's name |
Sources
A capsule starts from one of three sources. The source decides what is in the capsule when it starts.
| Source | How you give it | What the capsule has |
|---|---|---|
| The platform | No source field | The base tools and the packages that you give. |
| An image | image | The tools of that container image. |
| A copy | from_workspace or from_snapshot (not both) | The files of the workspace at the time of the request, or of the snapshot. |
Creation parameters
| Parameter | Required | Description |
|---|---|---|
cmd | Yes | The main process: the program, then its arguments. 256 arguments and 256 KiB at most. The capsule ends when it exits. |
tty | No | Run cmd on a terminal. The default is false. |
stdin | No | Keep the input open so that you can attach to the process. The default is false. |
timeout_s | No | The hard lifetime, 10 to 86400 seconds. The default is 300. |
network | No | internet (default) or none. |
cpu | No | vCPU cores, 1 to 8. The default is 1. |
memory_gb | No | Memory, 1 to 32 GB. The default is 2. |
env | No | Variables, 64 at most, 32 KiB for each value. A value of ${{ secrets.NAME }} refers to a secret. In a team capsule, your personal secret in the team comes first, then the secret of the team. |
packages | No | The packages to install: name or name@version. |
image, from_workspace, from_snapshot | No | The source. See Sources. Give one. |
team | No | A team that you belong to. The default is you. |
The variables belong to the main process. A variable name uses letters, digits, and _, does not start with a digit, and is not HOME or KD_ followed by anything.
States
A capsule never stops and starts again. A create call returns at once with the phase pending. A fast command can end without the capsule being running.
phase | Meaning |
|---|---|
pending | The platform recorded the capsule. |
starting | The platform starts the capsule. |
running | The main process runs. The time limit counts from here. |
terminated | The capsule ended. The field reason gives the cause. |
reason | Meaning |
|---|---|
Terminated | You ended the capsule. |
Timeout | It reached timeout_s. |
Exited | The main process exited. exit_code gives its code. |
Failed | The capsule or the create failed. message gives the cause. |
Unplaceable | The platform found no place to run it. |
SourceGone | The workspace or snapshot it started from no longer exists. |
Lost | The platform stopped running it. |
EnvironmentGone | The environment of its desk was deleted. |
The record also has exit_code, message (the cause of a failure), the times, the size, and the source.
Lifecycle
- Create. The call returns at once. The phase is
pending, thenstarting, thenrunning. - Run. The hard lifetime counts from
runningand always applies. A capsule has no idle limit. - In a desk. A capsule created through a desk is controlled through that desk. It ends when the desk is deleted. See Capsules.
- End. The main process exits, you end the capsule, or the time limit ends it. Its processes end and its files are gone.
- Record. The record of an ended capsule stays for 90 days. It shows the phase, the reason, the exit code, the output, the times, the size, and the source. A delete removes the record.
Adding packages to a running capsule
Inside a capsule, kd pkg add, kd pkg rm, kd pkg list, and kd pkg update change the packages of that capsule. The capsule does not restart, and its processes keep running. A new package is on PATH after the nix service answers, usually within seconds. kd pkg add jq followed by jq --version in the same shell works once the farm is rewritten.
The capsule holds a credential of its own for this, in KD_CAPSULE_TOKEN. It reaches the packages of that one capsule and nothing else, and it stops working when the capsule ends. A package that does not resolve is refused with a message, and the capsule keeps running with the packages it had.
Quota and limits
A running capsule counts its CPU, memory, and disk against the owner's quota. An ended capsule counts nothing. The capsules dimension of the quota limits how many capsules run at the same time.
| Item | Limit |
|---|---|
| Hard lifetime | 10 to 86400 seconds. |
| Command | 256 arguments and 256 KiB. |
| Output kept | The last 256 KiB. |
| CPU cores | 1 to 8. |
| Memory | 1 to 32 GB. |
| Variables | 64, each value up to 32 KiB. |
| Record | 90 days after the end. |
Tasks
Create a capsule with a command
Reason for the task
Start an isolated machine that runs one command and ends with it.
Job set-up
- Access: you.
- References:
POST /v1/capsules.
The files of a capsule are lost when it ends. Read the files that you need before the end.
Procedure
Create the capsule with the command. The call returns at once.
from kloudlite import Kodekl = Kloudlite()sb = kl.capsules.create(cmd=["python3", "main.py"], packages=["python3"], timeout_s=600)import { Kode } from "./index.ts";const kl = new Kloudlite();const sb = await kl.capsules.create({ cmd: ["python3", "main.py"], packages: ["python3"], timeoutS: 600 });kl := kloudlite.New(kloudlite.Options{})sb, err := kl.Capsules.Create(kloudlite.CreateCapsule{Cmd: []string{"python3", "main.py"}, Packages: []string{"python3"}, Timeout: 600 * time.Second})if err != nil { log.Fatal(err)}require_relative "kloudlite"kl = Kloudlite::Client.newsb = kl.capsules.create(cmd: ["python3", "main.py"], packages: ["python3"], timeout_s: 600)var kl = new Kloudlite();var sb = kl.capsules().create(new Kloudlite.CreateCapsule().cmd(List.of("python3", "main.py")).packages("python3").timeout(Duration.ofSeconds(600)));kode capsules create --package python3 --timeout-s 600 -- python3 main.py
Close-out
- Show the status as in task 002. Make sure that
phaseispending,starting,running, orterminated.
Show the status of a capsule
Reason for the task
Read the phase of a capsule and, when it ended, the reason and the exit code.
Job set-up
- Access: you.
- References:
GET /v1/capsules/{id}.
Procedure
Read the record of the capsule. The record shows the phase, the reason, the exit code, and the times.
print(kl.capsules.get(capsule="cap-3c4d5e6f7a8b9c0d").doc)console.log((await kl.capsules.get({ capsule: "cap-3c4d5e6f7a8b9c0d" })).doc);got, err := kl.Capsules.Get("cap-3c4d5e6f7a8b9c0d")if err != nil { log.Fatal(err)}fmt.Printf("%+v\n", got.CapsuleDoc)pp kl.capsules.get(capsule: "cap-3c4d5e6f7a8b9c0d").docSystem.out.println(kl.capsules().get("cap-3c4d5e6f7a8b9c0d").json());kode capsules get cap-3c4d5e6f7a8b9c0dWait until the capsule is
running. The call fails with the reason when the capsule ends first.sb.wait_running(timeout_s=600)await sb.waitRunning({ timeoutS: 600 });if err := sb.WaitRunning(600 * time.Second); err != nil { log.Fatal(err)}sb.wait_running(timeout_s: 600)sb.waitRunning(Duration.ofSeconds(600));kode capsules wait-running cap-3c4d5e6f7a8b9c0d --timeout-s 600
Close-out
- Make sure that the phase is
running, orterminatedwith areason. Make sure thatexit_codeis set when the reason isExited.
Terminate a capsule and delete its record
Reason for the task
End a capsule before its command exits or its time limit, and release its resources.
Job set-up
- Access: you.
- Conditions: you have the handle
sb. Usecapsules.getwith the id to get it. - References:
POST /v1/capsules/{id}/terminate,DELETE /v1/capsules/{id}.
A delete removes the record of the capsule. A capsule that still runs ends with it.
Procedure
Terminate the capsule. The call is safe to repeat.
sb.terminate()await sb.terminate();if err := sb.Terminate(); err != nil { log.Fatal(err)}sb.terminatesb.terminate();kode capsules terminate cap-3c4d5e6f7a8b9c0dWait until the capsule ends. The call returns the exit code, or no code when the process did not exit by itself.
code = sb.wait()const code = await sb.wait();code, err := sb.Wait(0)if err != nil { log.Fatal(err)}code = sb.waitint code = sb.waitFor(null);kode capsules wait cap-3c4d5e6f7a8b9c0dDelete the record if you do not need it.
sb.delete()await sb.delete();if err := sb.Delete(); err != nil { log.Fatal(err)}sb.deletesb.delete();kode capsules delete cap-3c4d5e6f7a8b9c0d
Close-out
- Make sure that
reasonisTerminated, orExitedwhen the command ended first.
List the run records
Reason for the task
Find the capsules of an owner and read why each one ended.
Job set-up
- Access: you.
- References:
GET /v1/capsules,GET /v1/capsules/{id}.
Procedure
Show the capsules, newest first. Give a team to show only its capsules.
for s in kl.capsules.list(): print(s.id, s.phase, s.reason)for (const s of await kl.capsules.list()) { console.log(s.id, s.phase, s.reason);}capsules, err := kl.Capsules.List("")if err != nil { log.Fatal(err)}for _, s := range capsules { fmt.Println(s.ID, s.Phase, s.Reason)}kl.capsules.list.each do |s| puts "#{s.id} #{s.phase} #{s.reason}"endfor (var s : kl.capsules().list(null)) { System.out.println(s.id() + " " + s.phase() + " " + s.reason());}kode capsules list
Close-out
- Make sure that each ended capsule shows the phase
terminated, a reason, and its times.
Read the output and the exit code
Reason for the task
Read what the command printed and how it ended.
Job set-up
- Access: you.
- Conditions: you have the handle
sb. Usecapsules.getwith the id to get it. - References:
GET /v1/capsules/{id}/logs,POST /v1/capsules/{id}/wait.
After the end, the platform keeps the last 256 KiB of the output with the record for 90 days.
Procedure
Wait for the command to exit. The call returns the exit code.
code = sb.wait()const code = await sb.wait();code, err := sb.Wait(0)if err != nil { log.Fatal(err)}code = sb.waitint code = sb.waitFor(null);kode capsules wait cap-3c4d5e6f7a8b9c0dRead the output. Give
followto hold the call until the command ends.print(sb.logs())console.log(await sb.logs());out, err := sb.Logs(false)if err != nil { log.Fatal(err)}fmt.Print(out)puts sb.logsSystem.out.print(sb.logs(false));kode capsules logs cap-3c4d5e6f7a8b9c0d
Close-out
- Make sure that the exit code is
0and the output is the one that you expect.
Troubleshooting
| Symptom | Possible cause | Corrective action |
|---|---|---|
409 with capsules: … in use; request more under Quota (or cpu, memoryGb, diskGb) | You use the full quota. | Terminate a capsule that you do not need, or request more quota. |
409 with capsule cap-… has no output yet (starting) | The capsule has not started. | Wait, then read the output again. An empty answer after the start means no output yet. |
409 with capsule cap-… has terminated (Timeout) | The capsule ended. The text gives the reason. | Create a new capsule with a larger timeout_s. |
404 with not found | The capsule does not exist, or is not yours. | Check the id in the run records. |
422 with timeout_secs must be between 10 and 86400 | The time limit is out of range. | Set timeout_s from 10 to 86400. |
422 for cmd | The command is empty or too long. | Give the program and at most 256 arguments. |
422 with from_workspace and from_snapshot are exclusive | The create call gives two sources. | Give one of them. |
422 with env: HOME is set by the platform | A variable name is not valid. | Use a different name. |
422 with create a desk's capsule with POST /v1/desks/{id}/capsules | The create body has desk. | Remove desk. To create a capsule in a desk, see Capsules. |
409 with capsule cap-… is managed by desk dev; use the desk | The capsule belongs to a desk, and the call ends or deletes it directly. | Delete the desk, or wait for the time limit. See Capsules. |
phase is terminated and reason is Unplaceable | The platform found no place to run the capsule. | Create the capsule again with less cpu or memory_gb, or wait. |
phase is terminated and reason is SourceGone | The workspace or snapshot that the capsule copies was deleted. | Create the capsule again from another source. |
phase is terminated and reason is Exited with an exit_code other than 0 | The command failed. | Read the output. |
phase is terminated and reason is Failed or Lost | The capsule or the create failed, or the platform stopped it. | Read message in the record. Create a new capsule. |
403 with your access to {team} is paused | A team admin paused your access. | Ask a team admin to restore it. |