☰ 📦 Datalayer Runtimes
Datalayer Runtimes service manages access to ⚪ Runtimes based on the defined 🎱 Runtime Pools.
🌳 Environments that define the type, requested and limits for CPU/GPU and memory, the parameters, the Runtime Contents they bring (selected by uid: git repositories pinned to a revision, subpaths of the shared filesystem, S3 buckets) and a Docker Image (the Datalayer Operator is responsible to build the Docker Images).
🎱 Runtime Pool that deploys parametrised Runtimes with an availability based on a calendar.
⚪ Runtimes (active or paused) ready to serve users.
📎 Contents attachments — the Home Folder, a Volume, a local folder over the bridge relay — prepared with the Contents service at launch and handed to the Operator (in the cluster) or mounted by the sandbox itself (at an external provider).
Deploy Datalayer Runtimes
- Plane
- Helm
- Terraform
plane up datalayer-runtimes
export RELEASE=datalayer-runtimes
export NAMESPACE=datalayer-api
helm upgrade \
--install $RELEASE \
oci://${DATALAYER_HELM_REGISTRY_HOST}/datalayer-charts/jupyter \
--create-namespace \
--namespace $NAMESPACE \
--set jupyter.image="${DATALAYER_DOCKER_REGISTRY}/jupyter:0.1.1" \
--set jupyter.certificateIssuer="letsencrypt" \
--set jupyter.env.DATALAYER_RUN_HOST="${DATALAYER_RUN_HOST}" \
--set jupyter.env.DATALAYER_CDN_URL="${DATALAYER_CDN_URL}" \
--set jupyter.env.DATALAYER_JWT_ISSUER="${DATALAYER_JWT_ISSUER}" \
--set jupyter.env.DATALAYER_JWT_SECRET="${DATALAYER_JWT_SECRET}" \
--set jupyter.env.DATALAYER_JWT_ALLOWED_ISSUERS="${DATALAYER_JWT_ALLOWED_ISSUERS}" \
--set jupyter.env.DATALAYER_OPERATOR_API_KEY="${DATALAYER_OPERATOR_API_KEY}" \
--set jupyter.env.DATALAYER_AUTHZ_ENGINE="${DATALAYER_AUTHZ_ENGINE}" \
--timeout 5m
cd terraform
terraform init
terraform apply
./generated/clouder-Kubeadm-setup.sh
export KUBECONFIG=~/.clouder/kubeadm/<cluster-name>/kubeconfig
./generated/services/deploy-datalayer-runtimes.sh
- Plane
- Helm
plane ls
helm ls -A
Check the availability of the Datalayer Runtimes Pods.
kubectl get pods -n datalayer-api -l app=jupyter
Check the logs of the Datalayer Runtimes Pods.
kubectl logs -n datalayer-api -l app=jupyter -f
Check the availability of the Datalayer Runtimes Certificate.
kubectl describe certificate ${DATALAYER_RUN_HOST}-datalayer-api-cert-secret -n datalayer-api
Check the availability of the Datalayer Runtimes Endpoints.
open https://${DATALAYER_RUN_HOST}/api/runtimes/version
open https://${DATALAYER_RUN_HOST}/api/runtimes/v1/ping
Environment Contents
An Environment selects Runtime Contents by uid (see the Operator page for the definitions). Whether a selected content can be delivered depends on where the sandbox runs. In the cluster everything is a mount. At an external provider there is no cluster: a git content is a materialized checkout, a bucket is reachable from code through a Python filesystem object (fsspec) with the bucket's credentials — not mounted — and the platform shared filesystem cannot be reached at all.
| Content type | Datalayer | Daytona, E2B, Modal |
|---|---|---|
git | mount of the pinned checkout | materialized checkout |
nfs | mount of the shared filesystem subpath | refused (nothing can mount the platform filesystem) |
s3 | mount (Datashim) | python access from code; not mounted |
Any other provider has no delivery rules and delivers nothing.
Endpoints
GET /api/runtimes/v1/environments— every Environment, withcontents: the selected uids and, resolved from their definitions,name,type,revision,mountandpermissions.GET /api/runtimes/v1/environments/<name>/contents?provider=<provider>— the contents resolved for a provider (the Environment's own by default):environment,provider,supportedandcontents, a list of resolved contents each carryinguid,name,type,mount,permissions,revision,sha256, astatusofresolved,unsupportedorunresolved, and adetailsaying what the content becomes or what cannot be met. When the Environment resolves on Datalayer, the result is recorded as a Contentsenvironmentsource (once per Environment, idempotent on its uid, brought up to date when the build changes) and returned assource.PUT /api/runtimes/v1/environments/<name>/contents— platform administrators only; body{"contents": [{"uid": "...", "mount": "...", "permissions": "ro"}]}; proxied to the Operator, which resolves every uid before patching theRuntimeEnvironment.GET /api/runtimes/v1/runtime-contents— the catalog as a user may see it:uid,name,type,description,permissions, and for a public git repository itssourceand pinnedrevision. Credentials, bucket names and filesystem paths are withheld.
The launch gate
POST /api/runtimes/v1/runtimes refuses a launch — before anything starts — when a content the Environment selects cannot be delivered where the sandbox will run: 422 with code ENVIRONMENT_CONTENT_UNSUPPORTED and a message naming the content, the provider and the semantics that cannot be met (ENVIRONMENT_CONTENT_UNRESOLVED when a selection matches no definition or a git content is not pinned).
Registering the environment source needs DATALAYER_RUNTIMES_API_KEY (the Runtimes identity Contents accepts for it) and DATALAYER_CONTENTS_URL.
Contents attachments
An account attaches what a sandbox should see through the
Contents catalog (POST /api/contents/v1/attachments,
naming the sandbox), and Runtimes is where that attachment meets the launch.
The Environment Contents above are the Environment's; these are the
account's. Runtimes' part, in order:
- Prepare.
POST /api/runtimes/v1/runtimeswithcontent_attachment_uids: [...](and apod_name; without one Runtimes names the sandboxruntime-<ulid>and prepares for that name). Runtimes reads the sandbox's manifest,GET /attachments/manifest/{sandbox_uid}, with the caller's credentials — a uid the manifest does not list is404— then has Contents prepare each one,POST /attachments/{uid}/preparewithtoken_audience: sandbox:<uid>, under its own identity (DATALAYER_RUNTIMES_API_KEY, theattachments:preparescope). Preparing is what mints a short-lived token for what the sandbox will fetch, or a bridge session for a local mount. Each prepared attachment is stamped with its source'skind, read with the caller's credentials again — a source the caller cannot read refuses the launch — because the Operator renders a Home Folder (files) and a Volume differently and the catalog is where that difference is written. - Resolve the Home Folders. When the request asks for the
home_foldercapability or one attachment is a Home Folder, Runtimes asks IAM for the caller's memberships and setshome_folder_mountsto their own folder plus one per organization and team — mounts supplied by the client are replaced, never trusted. When IAM cannot answer, the runtime gets its own folder only. Without a Home Folder in the request, no home folder is mounted: a Volume alone mounts its Volume. - Refuse before anything runs. Two gates answer
422with acodebefore a provider is chosen:ENVIRONMENT_CONTENT_UNSUPPORTED/ENVIRONMENT_CONTENT_UNRESOLVED(the Environment's contents, above), andLOCAL_BRIDGE_UNSUPPORTEDfor alocal-bridgeattachment on an environment that cannot run the bridge filesystem. A bridge mount is a userspace filesystem inside the sandbox — fusepy over/dev/fuse— and whether a sandbox has one is a property of its environment, never of the provider: Runtimes reads the environment'sfeaturesfrom the Operator's record of it, else from the provider catalog incode_sandboxes, and refuses unlessfuseis among them, naming the environment, the provider, what it would need and what it advertises, and offering Synchronize (a copy, called a copy). On Datalayer nothing is refused: the Operator renders a CSI volume and the node driver mounts it, so nothing runs in the sandbox. The stock external environments declare nofuse. - Hand over. In the cluster the prepared attachments go to the
Operator in
content_attachmentsofPOST /api/operator/v1/runtimes, which mounts them and reports each outcome to Contents itself (see Operator). At an external provider (Daytona, E2B, Modal) there is no Operator in the path: the session thread fetches the manifest with the user's credentials, builds thecode_sandboxescontent manifest — the account's attachments, then the Environment's contents asenvironmententries, pluscontents_url— hascode_sandboxesprepare it inside the sandbox (materialized checkouts, bucket access from code, the bridge filesystem run from inside the sandbox), and reports every outcome underDATALAYER_RUNTIMES_API_KEY(theattachments:statusscope). A required attachment Contents no longer lists is an error; an optional one is skipped and logged. Without a service key nothing is reported and the attachment stayspreparing— a misconfiguration that shows in the catalog rather than hiding.
The attachments a runtime was launched with travel on its record, so a runtime's description lists what it actually mounts, and an external session's manifest can be put back in the form Contents takes.
Which launches wait for a Pod
A Pod's volumes are fixed when it is created, so a launch that mounted
anything used to be given a Pod of its own — scheduling, an image pull and a
Jupyter startup probe — while a launch that mounted nothing was handed a
prewarmed one. With the
Node Mount Gateway deployed and
DATALAYER_NODE_MOUNT_GATEWAY_ENABLED set on the Operator, a Home Folder launch
is served from the pool as well: the Operator writes the mount set on the
pooled Pod and the node agent binds the folders in while it runs.
Nothing in step 2 changes. The memberships are still resolved in Runtimes, from IAM, with the caller's own credentials, and still replace whatever the client sent — the gateway changes when a folder is mounted, never who decides which. A Volume or a Local Mount still gets a Pod of its own, and so does everything when the gateway is off. The Operator's page has the full table: Pool or its own Pod.
A runtime's record carries mount_gateway, so a client can tell before it
asks whether this sandbox takes a mount while it runs.
Configuration
| Variable | Meaning |
|---|---|
DATALAYER_CONTENTS_URL | Where the manifest is read and attachments are prepared and reported (runtimes.env in the chart; default the in-cluster datalayer-contents-svc). |
DATALAYER_RUNTIMES_API_KEY | Runtimes' identity to Contents (attachments:prepare, attachments:status, and registering the environment source). Required as soon as a launch names an attachment: 503 without it. |
DATALAYER_OPERATOR_API_KEY | The key Runtimes uses towards the Operator, unchanged. |
Tear Down Datalayer Runtimes
If needed, tear down.
- Plane
- Helm
plane down datalayer-runtimes
export RELEASE=datalayer-runtimes
export NAMESPACE=datalayer-api
helm delete $RELEASE --namespace $NAMESPACE
OpenAPI Specification
The OpenAPI (Swagger) specification is available online.