01Documentation
Configuration
Sandbox0 configuration is split across direct service YAML, root-owned credential/identity files, Nomad client configuration, and the warm-carrier job. Keep these inputs under versioned infrastructure management and pin them to one tested release.
Configure In This Order#
- region and cluster identity;
- PostgreSQL writer and RootFS object storage;
- manager node authority and active-active terminal reconciliation;
- dedicated node identity and truthful capacity;
- immutable runtime-class catalog;
- resource-neutral carrier count;
- gateway identity, routing, registry, network, quota, and telemetry; and
- rollout and acceptance policy.
Region And Cluster Identity#
A provider/region has one independent PostgreSQL and S3 boundary. Several data-plane clusters may share it.
Use stable values for:
region_idon regional and data-plane services;cluster_id/default_cluster_idfor each data plane;- Nomad server cluster identity;
- exact Nomad client node IDs;
- a durable node UID that survives reboot; and
- a new boot ID for every host boot.
global-gateway routes teams to regions only. It must not contain a region's
Nomad or data-plane cluster topology.
For one data-plane cluster, run cluster-gateway in full mode and omit scheduler. For several clusters, regional-gateway calls scheduler, and scheduler selects a cluster from live PostgreSQL capacity for new claims.
PostgreSQL#
All replicas in one region use the same PostgreSQL writer endpoint. Manager, scheduler, and gateways must not point at independently maintained lifecycle stores.
Manager validates that new and pooled connections are read-write. During a failover, readiness and new capacity-changing work fail closed until the writer endpoint resolves to the new primary.
PostgreSQL is authoritative for:
- sandbox/template lifecycle and runtime generations;
- node capacity, carrier slots, and exact resource leases;
- RootFS heads, writer epochs, snapshots, forks, imports, and deletion queues;
- network and credential policy state; and
- metering projection state and transactional outbox.
RootFS Object Storage#
Configure rootfs_object_storage on every manager and ctld with one regional
bucket and endpoint. Use conditional object creation and keep credentials
private.
yamlrootfs_object_storage: type: s3 bucket: sandbox0-rootfs region: us-east-1 endpoint: https://s3.internal.example.com access_key: ${SANDBOX0_S3_ACCESS_KEY} secret_key: ${SANDBOX0_S3_SECRET_KEY} object_encryption_enabled: true object_encryption_key_path: /etc/sandbox0/rootfs/object-key
The object-encryption key is installation state. Losing it loses access to encrypted RootFS objects; changing it without a migration makes existing objects unreadable.
RootFS caches are demand-filled after the artifact is selected; warm carriers do not preload tenant RootFS data. Before exposing its runtime, a ctld primary resolves initial S3-compatible provider credentials into the SDK's existing credential cache. This does not read tenant objects or require OSS bucket lifecycle permissions. Initial credential failures prevent runtime readiness; later expiry/refresh still follows the provider and can affect subsequent reads. This initialization is not proof of object permissions or a latency guarantee. The session manager shares a 128 MiB verified range LRU, including decoded mapping pages and their accounted memory. Parent bindings are still checked on mapping-cache hits. A cold encrypted-object header load normally combines its fixed prefix and JSON header in one bounded 1 KiB range GET. For bounded offset-zero demands, including mapping pages, the first GET can also include demanded ciphertext, up to 256 KiB total. That ciphertext belongs only to the initiating read, not the shared header cache; other waiters share only parsed crypto state. For cold nonzero offsets, the store may overlap the header load with a bounded ciphertext probe using current writer geometry. There are at most eight private probes of up to 256 KiB per store, including completed probes waiting for a header. At most 1 KiB of incidental bytes can precede the demanded frame; the intervening pack prefix is never downloaded. The stored header must validate the hinted layout before use. Old frame sizes, large headers or failed probes fall back to the ordinary exact demanded range; probe saturation never queues extra speculative work. Cancellation is per caller, and slow private probes do not delay shared-header publication. Larger valid headers require one exact remainder GET, up to the existing 1 MiB header limit. Stored frame geometry determines any continuation range, including old objects whose frames differ from current writer defaults. Demanded frames still authenticate separately, and plaintext ranges still require checksum validation. This reduces request round trips without changing persisted objects or requiring tenant RootFS prewarming. Each encrypted RootFS store also bounds cached envelope headers and crypto state to 1,024 entries / 8 MiB. If GC recreates an immutable plaintext key with a new encryption envelope, a reader can refresh the header once before any frame authenticates; following an authentication failure it retries data only when the header changed. These caches do not change persisted formats or replace PostgreSQL/S3 authority. Cache budgets do not include active read buffers, live reader state, kernel caches, or total process RSS.
New encrypted RootFS objects use independently authenticated 16 KiB frames. Existing objects keep the frame size recorded in their header, including older 1 MiB and 64 KiB frames; changing the writer does not rewrite existing immutable keys. Block-map checksums and encryption frames are separate boundaries: reducing only one does not remove overfetch imposed by the other. Keys, algorithms and stored format versions are unchanged.
For mapping entries smaller than 128 KiB, a bulk read of at least 128 KiB can combine logically and physically adjacent entries from the same verified leaf and object into a bounded 1 MiB window. Every entry is checksum-verified before use or cache admission. Small reads retain the selected entry's granularity. With less than 2 MiB of read cache, coalescing stays within the actual demand; otherwise a bulk demand can fill the remainder of its 1 MiB window. It does not fetch extra mapping pages or cross holes, object boundaries, or coarse entries. Verified cache hits at a window's edges are excluded from its transport range. Interior hits stay inside the single contiguous request, avoiding extra serial GETs; their verified cached bytes are reused when assembling the result. The whole-window flight identity and source-buffer/concurrency limits are unchanged. This is claim-time demand-driven reading, not tenant RootFS prewarming.
Set dirty-tail and materializer limits from measured storage latency and node disk headroom. The regional composite-tail backlog is bounded: an S3 outage must apply backpressure instead of growing unbounded local or PostgreSQL data. Do not release a writer or delete its local branch before immutable publication or an explicit crash-abandon terminal transaction. The shared retirement reserve remains charged to its writer group across WAL close and reopen, until every charged journal is reclaimed. Reopening a journal alone does not authorize retirement writes or enlarge ordinary write admission.
Durable OCI Importer#
Manager's RootFS importer is required for the Nomad runtime. Configure:
yamlrootfs_importer: work_root: /var/lib/sandbox0/rootfs-importer procd_path: /usr/local/bin/procd procd_protocol: <pinned-protocol> procd_digest: sha256:<pinned-digest> discovery_interval: 5s discovery_page_size: 100 format_generation: 2 # Require the default 64 KiB decoded geometry for new image-based claims. data_range_bytes: 65536 data_layout_policy: "" mapping_group_policy: ""
The work root must have enough space for bounded OCI extraction and block-image
construction. Use registry.pull_credentials_file for private source images.
All manager replicas run bounded template discovery and may run the importer.
The discovery cursor is expendable; deterministic PostgreSQL import operations
are the durable authority. PostgreSQL leases and conditional object publication
provide active-active ownership and retry safety. The importer identity includes
the image digest, OCI platform, block format, exact RootFS size, and pinned
procd protocol and digest.
Before changing rootfs_importer.procd_path and procd_digest, upgrade every
manager to executable-filtered import leasing. Older workers can otherwise
abandon a new version's pending import. Prepare matching ready artifacts for
all image templates before switching claim selection; installing host binaries
alone neither updates importer configuration nor replaces embedded /procd.
Snapshots and captured templates keep the executable bound by their immutable
artifact, provided its procd protocol remains compatible. Updating the importer
digest does not rewrite existing sandbox generations or snapshots.
rootfs_importer.format_generation selects the durable format for new image
imports and image-based claims. Omitted or 0 selects format 1; 2 opts into
independently compressed, directly addressed data and mapping ranges. Other
values are rejected. Discovery, durable operation reconstruction, and claim
selection use the same format binding; there is no fallback to a different
format when the requested artifact is not yet ready.
rootfs_importer.data_range_bytes controls the checksummed data ranges of new
imported base artifacts. An omitted value or 0 uses the selected format's
build default and does not filter compatible artifacts by their import geometry.
| Import format | Default data range | Maximum data range |
|---|---|---|
1 | 8 MiB | 8 MiB |
2 | 64 KiB decoded | 64 KiB decoded |
An explicit value must be a positive multiple of 4 KiB that evenly divides the
default 64 MiB pack size. 1048576 selects 1 MiB ranges for format 1, but is
rejected for format 2. These decoded/checksummed ranges are distinct from the
16 KiB encryption frames of newly written objects.
Smaller ranges reduce overfetch for sparse demand, but can increase object GET
counts. Measure both bytes and first-command latency against the actual storage
backend before enabling this policy.
Explicit geometry is shared by template discovery and ordinary image-based
claims. A ready artifact with different or unknown import geometry cannot
satisfy that policy. Discovery uses the existing durable importer to ensure a
matching artifact, and new claims remain unavailable until one is selectable.
For a legacy artifact, retained ready-import records can supply missing geometry
only when their complete source and build-contract provenance agrees. Conflicting
or unverifiable history stays unknown and is reported as unavailable, not guessed
from the old default or accepted merely because an import says ready. Source
selection also matches the exact digest-pinned image reference, not just its
digest. Import geometry provenance stays with immutable artifact metadata after
completed import operations are garbage-collected.
Changing data_range_bytes alone does not rewrite existing objects, change the
block or encryption format, or add a runtime compatibility class. Existing generations, captured
templates, snapshots, forks, and resume continue to use their exact artifact
identity; the new-import selector is not applied to those lookups. It does not
change incremental checkpoint or materializer geometry. Quiesce old import and
import-GC workers before applying the geometry migration or recovering legacy
provenance: old workers cannot preserve conflicting evidence under the new
rules. Upgrade all participating managers, then enable the same value on every
manager in the region. Already-collected history cannot be recovered. Do not
prewarm tenant RootFS contents or increase request timeouts to make an acceptance
test pass.
rootfs_importer.data_layout_policy is an optional import optimization, not a
runtime compatibility class. Empty retains legacy global-grid segmentation and
selects legacy-policy artifacts for new image claims. xfs-file-ranges-v1
requires format 2 and 64 KiB data ranges (explicit or the format-2 default).
It aligns complete data ranges relative to files after read-only XFS extent
discovery; it does not change filesystem placement, read tenant data at claim
in advance, or cache a tenant RootFS in the generic warm carrier.
The requested policy participates in the immutable import operation identity. Version-2 artifact attestations additionally bind policy, range size and any whole-image fallback. Existing legacy operation/attestation bytes do not change. Discovery and new image claims select the exact policy; snapshots, captured templates, forks and resume remain bound to their committed artifact digest. Upgrade all managers and apply the layout migration before enabling the same policy across the region. The database rejects a pre-policy worker attempting to complete a new-policy operation with a legacy artifact. Downgrading the migration is refused while policy-bearing rows exist; do not erase provenance to force a downgrade.
Discovery is bounded to 10,000,000 entries, 1,048,576 extents, hardlink identities
and preferred spans, depth 256, and 4096-byte paths. Exhausting an optimization
budget discards the entire preferred plan and publishes the original global
segmentation; the attestation and successful import log record
scan-budget-exceeded. This preserves ordinary OCI input support and is not an
optimization success. Unsafe or malformed metadata, filesystem boundary changes,
I/O failures and cancellation still fail closed. A successful import or absence
of fallback is not a cold-start guarantee: verify full-image cost, fresh-node
claim plus the first real command, and actual density/reclaim before rollout.
rootfs_importer.mapping_group_policy defaults to empty and applies only to new
image imports. The opt-in contiguous-mapping-v1 requires format 2 and packs
adjacent mapping pages into bounded immutable objects (up to four pages,
240 KiB stored and 1 MiB decoded per group). It can coexist with
xfs-file-ranges-v1; it does not alter data-range geometry or carrier identity.
Readers can fetch contiguous sibling mappings together, verify each page, and
parse entries only on demand using the existing bounded shared cache and source
admission. This reduces some request counts but can amplify bytes for partial
reads; it is not a cold-start latency guarantee.
The policy is part of the durable import identity and version-3 Ready artifact attestation. Empty-policy operation and version-1/2 attestation identities remain unchanged. Upgrade all managers and apply the mapping migration before enabling the same policy region-wide. PostgreSQL prevents old workers from completing a grouped operation with an ungrouped artifact. Rollback refuses policy-bearing rows rather than discarding their provenance. New image selection matches the exact policy; committed snapshots, captures, forks and resume retain their exact artifact identity. Incremental and batch publishers do not accept this import setting. Validate fresh-node claim plus the first real command and occupied production width before rollout; neither tenant prewarming nor a larger timeout is part of this policy.
After the staging XFS image is unmounted, the importer reads it through an exclusively owned read-only descriptor. On Linux, filesystem-reported holes can be skipped without changing the data-unit boundaries, immutable objects or descriptor. Unsupported hole discovery falls back to a complete scan; actual I/O failures or detected file changes still fail the import. No extra setting, format migration, tenant prewarming or timeout increase is involved. A sparse logical image is not equivalent to the same size of populated data, and faster offline import does not prove faster sandbox claim or first-command execution.
Before selecting format 2, upgrade every participating manager, ctld instance,
and task driver to readers that support it. The upgraded runtime still uses the
same generic carrier catalog; do not split pools by image or tenant. Do not enable
format 2 while old readers can receive claims. Apply the same import policy to
all managers in the region. Existing snapshot claims and captured templates use
their attested generation's format, and resume retains its committed generation,
even if the new-image policy changes in either direction. Reverting that policy
does not permit rolling readers back to binaries that cannot read already
published format-two generations. No automatic migration or object rewrite is
performed. Format-two opt-in is not a production cold-start acceptance result;
validate empty-node-cache and cached-new-sandbox claims, first real commands,
mixed images and sustained node occupancy before rollout.
Manager Node Authority#
Use the manager example in deploy/nomad/control/manager.yaml.example as the
field reference. Production requires node_authority.enabled: true and the
plugin-independent terminal worker enabled.
Every manager replica needs identical:
- server certificate/key and node client CA;
- certificate-CN to cluster/node/node-UID/agent-UID mappings;
- 32-byte writer-token key;
- runtime-class catalog;
- trusted Nomad endpoint catalog and referenced credentials; and
- claim/heartbeat/writer lease policies.
Node channels use mTLS and exact identities. Bind the authority endpoint to a private address and configure exact DNS/SPIFFE SANs. Do not permit redirects, ambient HTTP proxies, wildcard node identity, or an unpinned Nomad client endpoint.
The terminal worker must remain independent of the task-driver process. It owns exact Nomad stop and client GC, node cleanup requests, physical absence observation, RootFS fencing, and the final PostgreSQL capacity release.
Nomad allocation observations use exact-ID, indexed summaries without embedding the carrier job. Incomplete, unauthorized, or mismatched catalog responses do not establish absence; physical cleanup still requires the exact node proof. Direct-client allocation observations have a five-second upper bound, even when the endpoint permits longer cleanup requests. If an observation fails, the worker defers other slots on that exact node incarnation until its next pass. Their leases and physical cleanup requirements remain intact. This prevents a retired node's carrier inventory from repeatedly consuming the same pass deadline while healthy nodes wait for capacity to be reclaimed. The worker resumes each bounded batch after the previous candidate and wraps for retries at the end of the traversal. This in-memory cursor prevents an unresolved full batch from permanently hiding later cleanup work; it does not change the required authority checks or physical absence proofs.
Compact external-crash proofs are replay history for exact writer bindings
already verified terminal regionally and reclaimed on the node. Local expiry
requires the matching durable binding and physical proof, BranchRemoved,
absent branch/mount paths, no live owner, and released device reservations where
applicable. It deletes history only, never physical artifacts, and supplies no
new terminal release authority. Missing records, expired regional proofs, and
HTTP 403 responses are not terminal authority; reclamation outside this
history-only path still requires positive regional verification.
The compact proof stays quiet until 48 hours after the latest of its crash
RequestedAt, proof ObservedAt, and record UpdatedAt, not just the crash
request. After that deadline, eligible history can be forgotten without a fresh
regional grant/proof lookup, including after a node is offline beyond
PostgreSQL's 72-hour terminal-proof retention window.
Runtime Classes#
The catalog file uses outer version 3; each compatibility record uses version
2. Start from
nomad-driver-sandbox0/example/runtime-classes.example.json.
A class contains only immutable execution properties:
- artifact OS/architecture and host architecture;
- driver and stock runsc versions;
- gVisor platform;
- overlay, file-access, and DirectFS modes;
/procd, its fixed port, and static runtime control mode; and- security class or immutable device requirements.
Configure procd_internal_jwt_public_key_file with the region data-plane
Ed25519 public key. The driver bind-mounts that public key read-only at
/config/internal_jwt_public.key; it must not be baked into a base image or
copied into an immutable RootFS artifact because regional key rotation is
independent of image import.
Never include CPU quota, CPU weight, cpuset, memory, PIDs, or template memory in the compatibility digest. Those values belong to the exact claim-time resource lease.
Until an explicit public class selector exists, configure exactly one class for each requested cluster. Ambiguous or missing class selection fails closed.
Dedicated Node Capacity#
Configure the Nomad client with:
client.node_pool = "sandbox0"; and- node metadata
sandbox0_dedicated=true.
The SANDBOX0_RESOURCE_* values in ctld.env describe allocatable sandbox
capacity after host, Nomad, ctld, NBD, and network overhead is reserved:
bashSANDBOX0_RESOURCE_CPU_MILLICORES=8000 SANDBOX0_RESOURCE_MEMORY_BYTES=17179869184 SANDBOX0_RESOURCE_CPUSET_CPUS=0-7 SANDBOX0_RESOURCE_CPUSET_MEMS=0
Use only CPUs truly dedicated to this node pool. Do not advertise SMT threads as independent physical-core acceptance capacity. Carrier-job resources are small overhead reservations and must not be copied into these values.
ctld-resource-cgroup-setup provisions /sys/fs/cgroup/sandbox0 and enables
cpu, cpuset, memory, and pids for per-lease children. Existing active
lease children survive ctld A/B restart. A lease returns to capacity only after
its cgroup and all other runtime state are physically absent.
Lightly loaded pools can opt into admission budgets larger than physical
capacity using nomad_runtime.admission_cpu_millicores and
nomad_runtime.admission_memory_bytes. Omitted or zero values preserve physical
capacity admission. These budgets bound the sum of individual sandbox limits;
they do not change a sandbox's CPU quota, memory limit, metering, or isolation.
Include the 150m CPU floor for every sandbox when sizing this budget. For
example, 420 minimum-memory sandboxes require at least 63000 millicores of CPU
admission, plus the leases of any other running sandboxes. A larger admission
budget does not add physical CPUs or guarantee simultaneous peak CPU usage.
Each individual request must still fit the physical node. CPU budgets are
bounded to 16 times physical capacity and memory budgets to twice physical
capacity; these are validation ceilings, not recommended operating ratios.
Before enabling overcommit, provision the parent resource cgroup with
cpu.max equal to the physical CPU budget over a 100000-microsecond period,
memory.max equal to the physical memory budget, and memory.swap.max=0.
ctld rejects an unbounded parent when overcommit is enabled. These exact
physical bounds are also accepted without overcommit and can remain in place
when a node reboots with reduced admission budgets. With memory overcommit, new cgroups are
rejected when current aggregate usage reaches 90% of the physical budget or
the requested memory limit exceeds remaining physical headroom. Exact retries
of existing cgroups remain available. Guest growth after admission can still
reach the aggregate limit, so simultaneous peak usage is not guaranteed by an
overcommitted profile. Validate resident workload memory and tail latency
before increasing density. Admission budgets cannot change within the same
node boot. Drain expanded-budget nodes before rolling back the database
migration, and keep autoscaler per-node admission budgets consistent with the
enrolled runtime profile.
NBD And Local Disk#
The canonical warm job provisions privileged carriers. Additional groups are
eligible only on nodes with matching sandbox0_privileged_carriers Nomad
metadata. Keep the node profile, usable private IPs, and RootFS devices
consistent; drain affected carriers before reducing the bound.
nomad_runtime.nbd_devices is the actual concurrent RootFS attachment bound.
The kernel's nbds_max alone does not make devices available to ctld. Keep the
configured list wider than the largest synchronized claim batch plus
replacement/retirement headroom.
The host installer derives the NBD module device count from the configured
SANDBOX0_ROOTFS_NBD_DEVICES inventory, with a floor of 64 devices. It refuses
to reload an in-use module to grow the pool; apply a larger pool on a fresh or
drained, rebooted node.
Each NBD connection admits up to 64 independent read requests, with a separate byte budget of eight maximum-sized responses. This wider small-read window helps expose independent ranges while callers wait on coalesced range loads. Both limits remain held through the complete reply; writes, flushes, trims, zeroing, and disconnects wait for earlier reads and replies. With the default 8 MiB request limit, outstanding read-response buffers remain bounded to 64 MiB per attached device, before object decryption, verified-range caches, and kernel memory. Each generation reader separately limits distinct source range loads to eight; callers coalescing on the same immutable range share one load slot. Reserve host memory for the configured attachment count, not just warm carrier overhead. Clean branch reads retain verified ranges for the current request and stop at journal overrides; this is demand coalescing, not speculative RootFS prefetch.
state_path, runtime_slot_journal_path, and branch state under
/var/lib/sandbox0/ctld must survive process restarts. Runtime mounts and
control sockets under /run/sandbox0 are boot-scoped. On reboot, only the
new authenticated boot for the same durable node UID may reconcile old state,
and only after proving the old runtime absent.
Periodic RootFS recovery has bounded aggregate concurrency, a smaller allowance for proof housekeeping, per-attempt deadlines, and capped exponential backoff for unchanged sessions. Physical-writer recovery takes priority; authenticated regional cleanup is not held behind this speculative retry budget. Retry scheduling is disposable boot-local/process-local state, rebuilt after restart or an observed recovery transition, not durable ownership or terminal truth. The durable journal and regional authority remain the recovery inputs.
An optional node-wide disk tier reuses verified immutable RootFS ranges across
sandboxes, memory-cache eviction, and ctld process replacement. Configure both
nomad_runtime.read_cache_directory and nomad_runtime.read_disk_cache_bytes;
nomad_runtime.read_cache_bytes controls the memory tier and defaults to
128 MiB. Use a dedicated node-private local directory. The disk cache contains
decoded plaintext, validates every hit against its content checksum, and never
caches a sandbox's private writable branch. Missing or corrupt entries fall
back to object storage. Bounded asynchronous fills and eviction keep cache
failures off the source-read success path. This cache is disposable and does
not replace durable branch state or object storage.
The primary ctld metrics endpoint exposes ctld_rootfs_read_cache_disk_* hit,
miss, fill, error, drop, and occupancy metrics, plus
ctld_rootfs_read_cache_queued_write_bytes. Compare these with object-storage
reads and end-to-end command readiness. A new sandbox on a cached node does
not represent an empty-node-cache start.
Network Runtime#
Run ctld A/B directly in host mount, network, cgroup, and device namespaces. The primary owns warm default-deny, claim-time policy compilation, TPROXY/ipset state, and the exact network-namespace incarnation. The standby follows durable state and takes over after promotion.
Configure cluster DNS and platform-allowed CIDRs narrowly. Sandbox policy is applied before runsc creation, and manager exposes the generation only after the applied policy digest is part of the launch proof.
Cloud metadata destinations are always denied for sandbox traffic: Aliyun
100.100.100.200, IPv4 link-local 169.254.0.0/16, and the IPv6 metadata endpoint
fd00:ec2::254. Tenant rules, platform allow lists, DNS bypass lists, and SOCKS5
proxy selection cannot override this boundary. The IPv4 kernel drop precedes
configured bypasses and applies only to registered sandbox source IPs, preserving
host-side enrollment and credential renewal.
Never enable a second task-driver-local network-policy path. The driver consumes ctld's durable policy proof; it does not install namespace-local fallback rules.
Warm Carrier Job#
nomad-driver-sandbox0/example/warm-slot.nomad is the resource-neutral
system carrier job. The current job has eight task groups, so each admitted
dedicated node receives exactly eight one-shot carriers. Change the reviewed
group inventory—not a per-template pool or task resource profile—only when
changing node carrier width. Keep:
hclrestart { attempts = 0 mode = "fail" }
Each task group must also keep network { mode = "cni/sandbox0" }. That name
selects the rendered per-node stock CNI ptp configuration and its leased
allocation CIDR. A directly routed host veth is required for UDP TPROXY;
ctld rejects bridged carrier peers. Nomad bridge mode selects a different
built-in network and must not be used for these carriers. Drain an existing
node and wait for every old bridge port to disappear before migrating its
CNI configuration; existing namespaces retain the topology they were created with.
Each carrier is one-shot. Nomad replaces the allocation after consumption. Pool width, node capacity, and NBD count are independent constraints and should be monitored together.
Autoscaler workload demand counts resource leases for claiming, starting, and active slots. Quiescing and orphaned slots retain their resource leases until physical cleanup is proven, but do not create replacement workload demand. Cleanup backlog therefore cannot by itself purchase additional worker capacity. Unsatisfied claims and configured headroom still contribute to scale-out demand; scale-in still requires the normal stabilization and node drain protocol. Before a scale-out write, manager reads the PostgreSQL capacity snapshot and provider desired capacity again. If the target, fixed-node availability, workload, unsatisfied demand, node readiness, or provider capacity changed, it defers the purchase to the next bounded pass. A pressureless fixed-node replacement is additionally debounced for two reconcile intervals —20 seconds with the default interval—so a normal adaptive carrier refill cannot be mistaken for the fixed node disappearing. Aliyun route cleanup deletes only the verified immutable route entry ID and waits for route absence before releasing node identity or the allocation subnet. An accepted asynchronous delete request alone does not complete scale-in.
Autoscaled clients must start with sandbox0_admitted=false. After exact node
identity and a live ctld capacity heartbeat are established, bootstrap may set
it to true so the system job creates carriers. PostgreSQL must retain a
separate warming claim fence until the provider confirms scale-out; Nomad
metadata alone is not provider admission.
PostgreSQL lifecycle actions are also the recovery source after a provider lifecycle token disappears. Every nonterminal action carries a bounded recovery deadline, a fenced recovery owner and epoch, and a terminal convergence receipt. When a successful provider enumeration no longer observes the token and every child instance is absent from the exact scaling-group inventory, manager waits a bounded observation grace period, retires only expired unclaimed warm carriers with a provider-absence proof, rejects nodes that still own leases or non-warm Nomad allocations, removes the route, purges the Nomad identity, revokes the node, and closes the durable action. The provider queue can accelerate this path, but it can no longer be the only way to resume cleanup.
Gateway Identity And Routing#
For self-hosted regional-gateway, configure:
edition: self-hostedandauth_mode: self_hosted;- asymmetric JWT signing keys in files;
- built-in auth and/or OIDC;
- one stable
region_idand externalbase_url; - the default cluster-gateway URL for single-cluster mode; or
- scheduler URL and license inputs for multi-cluster mode.
Keep internal service endpoints private and use internal signed tokens for regional-to-cluster and cluster-to-manager calls. Team-owned runtime access routes directly through the regional endpoint; global-gateway is not in that path.
Registry Credentials#
Registry providers are configured directly on regional-gateway/manager. Prefer root-owned file fields over inline secret values. Manager's durable importer uses a Docker credential file for private pulls; runtime allocations receive no registry credentials.
Configure different push_registry, pull_registry, and internal_registry
endpoints when public CI and private regional traffic require different routes.
Use the pull image reference returned by the credentials API.
Quotas And Metering#
Manager's default_team_quotas declaratively reconciles regional defaults.
Team-specific PostgreSQL policy overrides the same dimension. The claim
transaction checks concurrency and resource dimensions before leasing capacity.
Metering records the actual resource lease rather than deriving CPU/memory from a static carrier or compatibility profile. Enable the PostgreSQL producer even when ClickHouse is temporarily unavailable; ClickHouse consumers replay the transactional outbox.
See Quotas and Observability.
Rollouts#
Use deploy/nomad/ctld/rollout-node.sh to restart B then A and wait for each
instance to become primary-ready or synchronized-standby-ready before touching
its peer. Drain and roll nodes one at a time when changing runsc, driver,
compatibility digest, RootFS format, NBD pool, or network policy format.
Never downgrade across an on-disk journal version unsupported by the previous binary. Keep the prior tested binary/config set for rollback and preserve writer-token and encryption keys across ordinary rollouts.