DreamLake

Mounts

A Mount is a per-namespace registry entry describing a shared filesystem — an NFS export, an SMB share, an S3 bucket, a host directory, a Kubernetes ConfigMap — that the runner attaches into a job's workdir before dispatch. The server stores the kind-specific config and validates the required fields at write time; everything beyond that (mount-option syntax, credential enforcement, the actual mount -t <kind> / rclone / aws-cli invocation) belongs to the runner.

Status: metadata only

Mount storage — add / list / show / update / remove — is live. Activation — the runner actually mounting NFS / s3fs / bind / configmap into the sandbox before user code runs — is a daemon-side follow-up. Build the registry today; the wire-up at launch time lands in a later release.

For shipping code and moving objects in and out of jobs, see Storages and Code mounts — those paths work end-to-end today. The Mounts registry is for network filesystems the runner will attach wholesale.

Kinds

Exactly ten kinds are accepted. The server validates required-field presence per kind (422 on a miss) and stores the rest as-is.

KindWhat it isRequiredOptional
nfsNFS export.server, pathoptions
sambaSMB/CIFS share (runner uses mount -t cifs).server, shareoptions, creds
ftpFTP server.serverpath, port, creds
sftpSFTP over SSH (runner uses sshfs or curlftpfs).serverpath, port, creds, key
s3S3-compatible bucket via a userspace client (aws-cli, boto, rclone copy). Objects pulled into the workdir on demand; no FUSE.bucketendpoint, region, prefix, creds
s3fsThe same bucket, FUSE-mounted with s3fs-fuse — POSIX-y file ops on a real path.bucketendpoint, region, prefix, creds, options
google_driveA Drive folder (rclone-backed). folderId may be root for My Drive.folderIdcreds
dropboxA path inside a Dropbox account (rclone-backed).pathcreds
bindHost directory bind-mounted into the container.hostPathreadOnly
configmapA Kubernetes ConfigMap materialized into files.kubeNamespace, nameitems

Note the spellings: google_drive takes an underscore, and s3fs has no separator.

Three things worth knowing:

  • s3 vs s3fs — same required fields, different activation. Use s3 for throughput and simple copy-on-read semantics; use s3fs when the job code expects a real filesystem path.
  • Non-AWS S3 — endpoint is the hook for Ceph, MinIO, R2, and Backblaze B2. Omit it and the runner assumes AWS S3.
  • Anonymous access — credential refs are deliberately not required on kinds that can mount anonymously (public buckets, public NFS exports, anonymous FTP). The runner enforces credentials at activation time, where the error can be clearer than "field required".
There is no `git` mount kind

Some design notes describe a git mount that clones a repo at a resolved commit. It is not implemented: neither the control plane nor the CLI accepts --kind git. For shipping a working tree today, use lakeshore code push — see Code mounts.

CLI

bash
lakeshore mounts add <name> --kind <kind> [--kwarg k=v ...] [--config-file <path>]
lakeshore mounts list [--json]
lakeshore mounts show <name> [--json]
lakeshore mounts update <name> [--kwarg k=v ...] [--config-file <path>]
lakeshore mounts remove <name>

The name must match ^[a-z0-9][a-z0-9-]*$. Reusing a name inside a namespace is a 409.

Config can come from repeatable --kwarg key=value entries (dotted keys nest), from --config-file pointing at YAML or JSON, or from both on add — the file seeds the config and the --kwarg entries override. Values parse like the rest of the CLI: true / false / null and numbers coerce, values starting with [, {, or " parse as JSON, and everything else stays a string.

On update the two flags are mutually exclusive: --kwarg entries deep-merge into the existing config (--kwarg foo=null drops a key), while --config-file replaces the config wholesale.

Secret references

Credentials belong in Secrets, not in mount config. A {"$secret": "<name>"} marker anywhere inside the config resolves through the same plumbing that providers and tunnels use. The dotted-key form on the CLI is:

bash
lakeshore mounts add team-cache \
  --kind s3 \
  --kwarg bucket=my-team-cache \
  --kwarg 'creds.$secret=aws-team-keys'

Every referenced secret must already exist in the same namespace — the server rejects the write with a 422 otherwise. A $secret marker is a leaf: the walker does not recurse into sibling keys once it sees one, and the value must be a non-empty string.

Worked example

Register an NFS export of a dataset, mark it read-only for the runner, and inspect it:

bash
lakeshore mounts add imagenet \
  --kind nfs \
  --kwarg server=10.0.0.12 \
  --kwarg path=/exports/imagenet

# Runner-side mount options ride in `options` — deep-merged in.
lakeshore mounts update imagenet --kwarg options=ro

lakeshore mounts list
lakeshore mounts show imagenet --json
json
{
  "name": "imagenet",
  "kind": "nfs",
  "config": {
    "server": "10.0.0.12",
    "path": "/exports/imagenet",
    "options": "ro"
  }
}

Larger configs read better from a file:

app-config.yamlyaml
kubeNamespace: training
name: app-config
items:
  - key: config.json
    path: config.json
bash
lakeshore mounts add app-config --kind configmap --config-file ./app-config.yaml
lakeshore mounts remove app-config

HTTP

POST   /v1/namespaces/:ns/mounts
GET    /v1/namespaces/:ns/mounts
GET    /v1/namespaces/:ns/mounts/:name
PATCH  /v1/namespaces/:ns/mounts/:name
DELETE /v1/namespaces/:ns/mounts/:name

PATCH replaces config wholesale — the CLI's deep-merge happens client-side (fetch, merge, PATCH the result) — and the new config must pass the same per-kind required-field gate as create.

These routes auto-create the namespace on first write, unlike the queue and worker routes which 404 on an unknown namespace.

Read next

  • Storages — named S3 backends for moving data and code in and out of jobs (works end-to-end today).
  • Code mounts — shipping git snapshots for reproducible remote execution.
  • Tunnels — the parallel registry for WireGuard tunnels, with the same metadata-only status.
  • Secrets — storing the credentials mounts reference via $secret.