Skip to content
DocsAll docs
Console

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 runUseCommand
CreateStart 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
RunRun 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 terminalType 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-.

PartDescription
Main processThe 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.
PackagesThe toolchain, from nixpkgs. Give name or name@version at creation.
OutputThe live output of the main process, then its last 256 KiB. See Read the output.
NetworkInternet access, or none. The network none gives no DNS and no internet.
Resources1 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.

AspectStandaloneIn a desk
Created withPOST /v1/capsulesPOST /v1/desks/{id}/capsules. See Capsules.
Ended byThe main process, you, or the time limitThe main process, you, the time limit, or the end of its desk
Reaches an environmentNoThe desk's environment, and no other. See Capsules.
desk fieldEmptyThe desk's name

Sources

A capsule starts from one of three sources. The source decides what is in the capsule when it starts.

SourceHow you give itWhat the capsule has
The platformNo source fieldThe base tools and the packages that you give.
An imageimageThe tools of that container image.
A copyfrom_workspace or from_snapshot (not both)The files of the workspace at the time of the request, or of the snapshot.

Creation parameters

ParameterRequiredDescription
cmdYesThe main process: the program, then its arguments. 256 arguments and 256 KiB at most. The capsule ends when it exits.
ttyNoRun cmd on a terminal. The default is false.
stdinNoKeep the input open so that you can attach to the process. The default is false.
timeout_sNoThe hard lifetime, 10 to 86400 seconds. The default is 300.
networkNointernet (default) or none.
cpuNovCPU cores, 1 to 8. The default is 1.
memory_gbNoMemory, 1 to 32 GB. The default is 2.
envNoVariables, 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.
packagesNoThe packages to install: name or name@version.
image, from_workspace, from_snapshotNoThe source. See Sources. Give one.
teamNoA 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.

phaseMeaning
pendingThe platform recorded the capsule.
startingThe platform starts the capsule.
runningThe main process runs. The time limit counts from here.
terminatedThe capsule ended. The field reason gives the cause.
reasonMeaning
TerminatedYou ended the capsule.
TimeoutIt reached timeout_s.
ExitedThe main process exited. exit_code gives its code.
FailedThe capsule or the create failed. message gives the cause.
UnplaceableThe platform found no place to run it.
SourceGoneThe workspace or snapshot it started from no longer exists.
LostThe platform stopped running it.
EnvironmentGoneThe 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, then starting, then running.
  • Run. The hard lifetime counts from running and 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.

ItemLimit
Hard lifetime10 to 86400 seconds.
Command256 arguments and 256 KiB.
Output keptThe last 256 KiB.
CPU cores1 to 8.
Memory1 to 32 GB.
Variables64, each value up to 32 KiB.
Record90 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

WARNING

The files of a capsule are lost when it ends. Read the files that you need before the end.

Procedure

  1. Create the capsule with the command. The call returns at once.

    Python
    from kloudlite import Kodekl = Kloudlite()sb = kl.capsules.create(cmd=["python3", "main.py"], packages=["python3"], timeout_s=600)
    TypeScript
    import { Kode } from "./index.ts";const kl = new Kloudlite();const sb = await kl.capsules.create({ cmd: ["python3", "main.py"], packages: ["python3"], timeoutS: 600 });
    Go
    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)}
    Ruby
    require_relative "kloudlite"kl = Kloudlite::Client.newsb = kl.capsules.create(cmd: ["python3", "main.py"], packages: ["python3"], timeout_s: 600)
    Java
    var kl = new Kloudlite();var sb = kl.capsules().create(new Kloudlite.CreateCapsule().cmd(List.of("python3", "main.py")).packages("python3").timeout(Duration.ofSeconds(600)));
    CLI
    kode capsules create --package python3 --timeout-s 600 -- python3 main.py

Close-out

  1. Show the status as in task 002. Make sure that phase is pending, starting, running, or terminated.

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

Procedure

  1. Read the record of the capsule. The record shows the phase, the reason, the exit code, and the times.

    Python
    print(kl.capsules.get(capsule="cap-3c4d5e6f7a8b9c0d").doc)
    TypeScript
    console.log((await kl.capsules.get({ capsule: "cap-3c4d5e6f7a8b9c0d" })).doc);
    Go
    got, err := kl.Capsules.Get("cap-3c4d5e6f7a8b9c0d")if err != nil {    log.Fatal(err)}fmt.Printf("%+v\n", got.CapsuleDoc)
    Ruby
    pp kl.capsules.get(capsule: "cap-3c4d5e6f7a8b9c0d").doc
    Java
    System.out.println(kl.capsules().get("cap-3c4d5e6f7a8b9c0d").json());
    CLI
    kode capsules get cap-3c4d5e6f7a8b9c0d
  2. Wait until the capsule is running. The call fails with the reason when the capsule ends first.

    Python
    sb.wait_running(timeout_s=600)
    TypeScript
    await sb.waitRunning({ timeoutS: 600 });
    Go
    if err := sb.WaitRunning(600 * time.Second); err != nil {    log.Fatal(err)}
    Ruby
    sb.wait_running(timeout_s: 600)
    Java
    sb.waitRunning(Duration.ofSeconds(600));
    CLI
    kode capsules wait-running cap-3c4d5e6f7a8b9c0d --timeout-s 600

Close-out

  1. Make sure that the phase is running, or terminated with a reason. Make sure that exit_code is set when the reason is Exited.

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

WARNING

A delete removes the record of the capsule. A capsule that still runs ends with it.

Procedure

  1. Terminate the capsule. The call is safe to repeat.

    Python
    sb.terminate()
    TypeScript
    await sb.terminate();
    Go
    if err := sb.Terminate(); err != nil {    log.Fatal(err)}
    Ruby
    sb.terminate
    Java
    sb.terminate();
    CLI
    kode capsules terminate cap-3c4d5e6f7a8b9c0d
  2. Wait until the capsule ends. The call returns the exit code, or no code when the process did not exit by itself.

    Python
    code = sb.wait()
    TypeScript
    const code = await sb.wait();
    Go
    code, err := sb.Wait(0)if err != nil {    log.Fatal(err)}
    Ruby
    code = sb.wait
    Java
    int code = sb.waitFor(null);
    CLI
    kode capsules wait cap-3c4d5e6f7a8b9c0d
  3. Delete the record if you do not need it.

    Python
    sb.delete()
    TypeScript
    await sb.delete();
    Go
    if err := sb.Delete(); err != nil {    log.Fatal(err)}
    Ruby
    sb.delete
    Java
    sb.delete();
    CLI
    kode capsules delete cap-3c4d5e6f7a8b9c0d

Close-out

  1. Make sure that reason is Terminated, or Exited when 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

Procedure

  1. Show the capsules, newest first. Give a team to show only its capsules.

    Python
    for s in kl.capsules.list():    print(s.id, s.phase, s.reason)
    TypeScript
    for (const s of await kl.capsules.list()) {  console.log(s.id, s.phase, s.reason);}
    Go
    capsules, err := kl.Capsules.List("")if err != nil {    log.Fatal(err)}for _, s := range capsules {    fmt.Println(s.ID, s.Phase, s.Reason)}
    Ruby
    kl.capsules.list.each do |s|  puts "#{s.id} #{s.phase} #{s.reason}"end
    Java
    for (var s : kl.capsules().list(null)) {    System.out.println(s.id() + " " + s.phase() + " " + s.reason());}
    CLI
    kode capsules list

Close-out

  1. 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

NOTE

After the end, the platform keeps the last 256 KiB of the output with the record for 90 days.

Procedure

  1. Wait for the command to exit. The call returns the exit code.

    Python
    code = sb.wait()
    TypeScript
    const code = await sb.wait();
    Go
    code, err := sb.Wait(0)if err != nil {    log.Fatal(err)}
    Ruby
    code = sb.wait
    Java
    int code = sb.waitFor(null);
    CLI
    kode capsules wait cap-3c4d5e6f7a8b9c0d
  2. Read the output. Give follow to hold the call until the command ends.

    Python
    print(sb.logs())
    TypeScript
    console.log(await sb.logs());
    Go
    out, err := sb.Logs(false)if err != nil {    log.Fatal(err)}fmt.Print(out)
    Ruby
    puts sb.logs
    Java
    System.out.print(sb.logs(false));
    CLI
    kode capsules logs cap-3c4d5e6f7a8b9c0d

Close-out

  1. Make sure that the exit code is 0 and the output is the one that you expect.

Troubleshooting

SymptomPossible causeCorrective 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 foundThe capsule does not exist, or is not yours.Check the id in the run records.
422 with timeout_secs must be between 10 and 86400The time limit is out of range.Set timeout_s from 10 to 86400.
422 for cmdThe command is empty or too long.Give the program and at most 256 arguments.
422 with from_workspace and from_snapshot are exclusiveThe create call gives two sources.Give one of them.
422 with env: HOME is set by the platformA variable name is not valid.Use a different name.
422 with create a desk's capsule with POST /v1/desks/{id}/capsulesThe 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 deskThe 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 UnplaceableThe 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 SourceGoneThe 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 0The command failed.Read the output.
phase is terminated and reason is Failed or LostThe 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 pausedA team admin paused your access.Ask a team admin to restore it.