Skip to content

Run scripts in your deployment

A runner job completes one recorded calculation run by executing a short Python script inside your deployment and publishing its result through the ordinary publication path. It is how an approved agent — or a person — can have a calculation executed next to the data instead of on a laptop. Runners are off until an operator enables them; ordinary use never needs them.

  1. Install the runtime image once, pinned by digest, on the gateway host (the runner never pulls):

    Terminal window
    podman pull docker.io/library/python@sha256:f77ac9e44ae96ef2c90b8053ea08c31f8be030f824196b0ae4db6d462c84e51f
  2. Start the gateway with:

    VariableMeaning
    OPHIOLITE_RUNNER_IMAGEThe installed image (tag or digest). Required; its local image id is recorded in every receipt.
    OPHIOLITE_RUNNER_SLOTSJobs executed at the same time (default 1).
    OPHIOLITE_RUNNER_RUNTIMEOptional OCI runtime, for example runsc (gVisor) where installed.

    The gateway user needs rootless Podman. Without OPHIOLITE_RUNNER_IMAGE the runner operations answer 503 (runner-unavailable); a named image that is not installed stops the gateway from starting with a clear message.

A second, separate image runs a team’s tool versions (procedures) in the project’s sandbox. It is optional and independent of the script image above: a deployment may name either, both or neither. You build it yourself on the gateway host; Ophiolite does not publish one.

  1. From a checkout of the release you run, build it (network is used at build time only):

    Terminal window
    python3 tools/sandbox-image.py --runtime python-3.12

    It builds deployment/sandbox/python-3.12/Containerfile: a pinned python:3.12-slim, the hashed requirements.lock (the SDK’s dependencies and NumPy) and the SDK wheel of the same release (--wheel takes a wheel you already have). It then lists what pip installed, with no network, and writes two labels: org.ophiolite.sandbox.runtime (python-3.12) and org.ophiolite.sandbox.packages (each distribution and its version). It prints the image id and tags it localhost/ophiolite-sandbox:python-3.12.

  2. Name it when starting the gateway:

    VariableMeaning
    OPHIOLITE_SANDBOX_IMAGEThe installed sandbox image (tag or id).

    The server reads the labels to decide which tool versions the image can run: a tool whose requires names a distribution or version the image does not have is refused before anything runs. An image without both labels stops the gateway from starting. Each run is recorded with the image id it was admitted with, so rebuilding the image does not change what an earlier run says it ran in.

The sandbox runs each tool with the same isolation as a script job (no network, read-only root, no capabilities, user 65534, the same limits): the tool’s bundle and its exact input versions are mounted read-only at /box, and only /output is writable.

Each job is one container: no network (--network=none), no registry contact (--pull=never), a read-only root filesystem, the input mounted read-only, no Linux capabilities, no privilege escalation, an unprivileged user (65534), 16 MiB of /tmp, and one writable output folder. The script reads /input/curve.json (depth axis, values, curve, unit and the run’s parameters) and writes /output/changes.json, a list of {"index": i, "value": v}. The gateway accepts exactly that one regular file (no links, no pipes, no extra files), at most 1 MiB, finite numbers or null, each sample once, and publishes it as the person who submitted the job. The receipt of the result names the engine, image id and job — and, for an agent, its approved plan.

Who may submit: a project member with permission to run calculations, for one of their own started, unpublished runs on an exact input; an automation credential with the compute scope; or an agent with the compute scope through a plan its person approved (a job always waits for approval, because it publishes). Permissions, the agent’s validity and the project’s ownership (see project moves) are checked again when the job starts and again before it publishes.

LimitDefaultExceeded
Memory256 MiB (swap included)killed: memory
Wall time60 skilled: time
CPU1throttled
Processes64the script’s fork fails
Output folder1 MiB, 4 fileskilled: output
Logs kept64 KiB (the newest)older lines dropped
Queue10 queued jobs per person, 50 per projectsubmission refused (413)

A submitter may ask for lower memory, time and CPU. Jobs are started fairly: the person whose last job started longest ago goes next, so one person’s backlog does not hold others back.

  • Cancel a queued job (it never runs) or a running one (its container is killed); the result stays unpublished.
  • Restart: jobs survive a gateway restart. A container still running is re-attached with its original deadline; one that finished is collected; a result that was already published is recorded without running again; a job whose container is gone runs once more, then fails as interrupted twice. A job cancelled while the gateway was down stays cancelled.
  • Containers are named ophiolite-job-<id> and removed after collection. List leftovers with podman ps -a --filter name=ophiolite-job-.
  • A project with queued or running jobs cannot be moved to another deployment until they finish or are cancelled.

No GPUs, no distributed scheduling, no hosted execution and no Firecracker. Scripts run with the image’s Python only; there is no package installation. The runner code, image choice and notices are listed for the open-source release in the source boundary; publication follows that release process.