Read when:
- choosing
provider: azure-dynamic-sessions(orprovider: azurewith thedynamic-sessionsbackend); - running Linux commands inside Azure Container Apps dynamic sessions instead of a full SSH VM;
- changing
internal/providers/azuredynamicsessionsor the runner image.
This is a delegated-run provider: there is no SSH box. Azure owns the Hyper-V-isolated session pool and its lifecycle; Crabbox owns the runner image, local claims, archive sync, command streaming, and timing output. It is direct from the CLI only and never goes through the broker.
The same backend is selectable two ways:
provider: azure-dynamic-sessions, orprovider: azurewithazure.backend: dynamic-sessions(alias--azure-backend dynamic-sessions).
Microsoft docs:
- https://learn.microsoft.com/en-us/azure/container-apps/session-pool
- https://learn.microsoft.com/en-us/azure/container-apps/sessions-custom-container
Use Dynamic Sessions for fast, isolated, Linux-only command runs where you do
not need SSH, a desktop, a browser, code-server, or Actions hydration, and where
sizing and egress are governed by the Azure session pool rather than per-lease
flags. For a full SSH VM (including macOS/Windows targets and desktop/browser
capabilities) use provider: azure instead.
- An Azure Container Apps custom-container dynamic session pool.
- A pool image that exposes the Crabbox container runner on port
8787; build it fromworker/azure-dynamic-sessions.Dockerfile. - The caller holds the
Azure ContainerApps Session Executorrole on the pool. - Either
CRABBOX_AZURE_DYNAMIC_SESSIONS_TOKENholds a bearer token for thehttps://dynamicsessions.ioaudience, orazis logged in locally so Crabbox can mint one.
Crabbox resolves a bearer token in this order:
CRABBOX_AZURE_DYNAMIC_SESSIONS_TOKEN, if set.- Otherwise
az account get-access-token --resource https://dynamicsessions.io. Ifazure.tenant/azure.subscription(or their env/flags) are set, they are passed as--tenant/--subscription.
The endpoint must be https:// on an *.azurecontainerapps.io host (a
loopback http://localhost endpoint is allowed for local testing). Endpoints
with userinfo, query strings, or fragments are rejected.
The bundled image is intentionally small: the Crabbox container runner plus
bash, ca-certificates, curl, git, jq, ripgrep, and tar. Extend the
Dockerfile or supply your own image when a pool needs Node, Go, Python,
browsers, or other test runtimes.
For private Azure Container Registry images, prefer a managed identity with
AcrPull on the registry and pass that identity through --registry-identity,
rather than putting registry passwords on the command line:
az acr login --name <registry>
docker buildx build \
--platform linux/amd64 \
--push \
--tag <registry>.azurecr.io/crabbox-runner:<tag> \
--file worker/azure-dynamic-sessions.Dockerfile \
worker
identity_id="$(az identity show \
--name <pull-identity> \
--resource-group example-sandboxes-rg \
--query id \
--output tsv)"
identity_principal_id="$(az identity show \
--name <pull-identity> \
--resource-group example-sandboxes-rg \
--query principalId \
--output tsv)"
registry_id="$(az acr show \
--name <registry> \
--query id \
--output tsv)"
az role assignment create \
--assignee "$identity_principal_id" \
--role AcrPull \
--scope "$registry_id"
az containerapp sessionpool create \
--name example-pool \
--resource-group example-sandboxes-rg \
--environment example-env \
--registry-server <registry>.azurecr.io \
--registry-identity "$identity_id" \
--container-type CustomContainer \
--image <registry>.azurecr.io/crabbox-runner:<tag> \
--target-port 8787 \
--cpu 0.25 \
--memory 0.5Gi \
--cooldown-period 300 \
--max-sessions 20 \
--ready-sessions 1 \
--network-status EgressEnabled \
--location eastusFetch the pool management endpoint Crabbox needs:
az containerapp sessionpool show \
--name example-pool \
--resource-group example-sandboxes-rg \
--query "properties.poolManagementEndpoint" \
--output tsvPoint Crabbox at the custom-container pool management endpoint:
provider: azure-dynamic-sessions
target: linux
azureDynamicSessions:
endpoint: https://<pool>.<environment-id>.eastus.azurecontainerapps.io
workdir: /workspace/crabboxEquivalent Azure-family form:
provider: azure
target: linux
azure:
backend: dynamic-sessions
azureDynamicSessions:
endpoint: https://<pool>.<environment-id>.eastus.azurecontainerapps.io
workdir: /workspace/crabboxConfig key (azureDynamicSessions.*) |
Flag | Env override | Default |
|---|---|---|---|
endpoint |
--azure-dynamic-sessions-endpoint |
CRABBOX_AZURE_DYNAMIC_SESSIONS_ENDPOINT |
(required) |
apiVersion |
--azure-dynamic-sessions-api-version |
CRABBOX_AZURE_DYNAMIC_SESSIONS_API_VERSION |
2025-02-02-preview |
workdir |
--azure-dynamic-sessions-workdir |
CRABBOX_AZURE_DYNAMIC_SESSIONS_WORKDIR |
/workspace/crabbox |
timeoutSecs |
--azure-dynamic-sessions-timeout-secs |
CRABBOX_AZURE_DYNAMIC_SESSIONS_TIMEOUT_SECS |
1800 |
The token uses CRABBOX_AZURE_DYNAMIC_SESSIONS_TOKEN (see
Authentication).
Legacy azureDynamicSessions.pool and
CRABBOX_AZURE_DYNAMIC_SESSIONS_POOL values are rejected. The
endpoint setting is already the pool-specific management endpoint.
All five bindings share one typed declaration, including the legacy pool
field so its existing client-time rejection is preserved. It gains no flag, and
token discovery remains outside these bindings. Nonempty YAML strings override
earlier values without trimming; omitted, null, and empty strings preserve them.
Accepted endpoint inputs retain their source classification, with explicit
endpoint flag visits recorded in the existing later phase.
YAML timeoutSecs applies only when positive: zero and negative values leave the
earlier value unchanged. Its environment parser keeps the earlier value on
malformed input but accepts parsed zero/negative values, as do explicit flags.
The effective timeout uses a positive configured value first, otherwise a
positive --ttl rounded up to seconds, otherwise 1800 seconds. This does not
replace nonpositive values with 1800 before checking TTL. Command timeouts are
converted to wire milliseconds only when the deadline also fits existing
deployed runners: at most 9223372036 whole seconds. Larger explicit values or
TTL values whose ceiling exceeds that bound are rejected before run authentication
or session acquisition, never truncated or saturated. TTL rounding does not
overflow. The bundled Azure/Cloudflare runner also rejects direct positive
timeoutMs values above 9223372036854 before creating a working directory or
opening a command stream; nonpositive values retain the no-deadline policy. Status,
stop, and cleanup do not require a command timeout.
API-version, workdir, and final timeout fallbacks share the compiled defaults. Azure backend routing, Linux-only handling, endpoint/legacy-pool validation, authentication and session lifecycle remain unchanged.
workdir must be an absolute path and may not be a broad system directory such
as /, /tmp, /usr, or bare /workspace; pick a dedicated subdirectory.
warmupallocates a randomazds-…session identifier and verifies the runner by calling/healththrough the pool management endpoint.--keep(default) retains the session for reuse; without it the session is stopped via/.management/stopSession.runuploads the dirty checkout as a gzip tar archive to the runner over/v1/files, extracts it underworkdir, then streams the command over/v1/exec(NDJSON event stream).--no-syncskips the upload,--sync-onlystops after sync. Acquired-but-not-kept sessions are stopped after the run.--lease-outputrecords the session lease, whether it was reused or retained, and the matchingcrabbox stopcleanup command. API redirects are followed only when they remain on the configured endpoint's origin, preventing credentials and request bodies from crossing trust boundaries.status/listread/.management/getSessionand/.management/listSessionsand join them with local Crabbox claims.statuscan--waitfor readiness.stopstops the session and removes the local claim; a missing session just clears the stale claim.
Sessions are tracked by local claims scoped to the endpoint. run,
status, and stop accept kept Crabbox lease IDs or slugs only — raw Dynamic
Sessions identifiers are rejected unless they are already claimed.
Run cleanup completes before final timing is written. If stopping a newly created session fails or its original claim has changed, the claim and session remain available for recovery; an otherwise successful run now fails with exit code 1 instead of reporting a warning and success. Command exits and cancellation keep their original outcome when cleanup or timing output also fails. The cleanup timeout covers waiting for the claim lock as well as the stop request.
- Targets
linuxonly. - Supported commands:
warmup,run,status,list,stop,doctor. - No SSH, VNC, desktop, browser, code-server, Actions hydration, downloads, or
run artifacts — the provider has no SSH target. SSH-run artifact flags such as
--artifact-globand--require-artifactare rejected. --classand--typeare rejected; choose CPU/memory and egress in the Azure session pool configuration.--actions-runneris rejected.- Sync is archive upload/extract, not rsync, so rsync-specific options
(for example
--checksum) are rejected.
If a command stream ends before its completion event while the caller context is canceled, Crabbox reports cancellation rather than a missing-completion error. An accepted completion event and explicit stream-read errors retain their existing precedence.