R.5

Flags and preview features

The flags that change what an actor does are few: two snapshot timers on atelet, the parking budget on the router, and the dataplane and image choice in the installer.

Each table gives the literal flag and the default that the code sets at v1.0.0. Where a recorded argument list shows it, the table also gives the value of our install. A component has more flags than these. The tables hold the ones that this manual uses or that change behaviour you can observe.

The installer, ate-setup

ate-setup reads each setting from a flag, then a configuration file, then an environment variable, then the default.

FlagDefaultWhat it doesSection
--image-repo, --image-tagnoneInstalls published images. Without them the installer builds every image from the checkout. Each flag requires the other.2.1
--kindfalse (environment variable ATE_INSTALL_KIND)Uses the kind overlays: the bundled Postgres, rustfs, and the local registry.2.1
--namespaceate-systemThe namespace of the control plane.2.4
--credential-providernone, requiredA JSON object. {"name":"k8s.io"} installs the provider that reads Kubernetes Secrets. {"enabled":false} turns injection off.6.5
--ingress-allowed-spiffe-idsnoneThe client identities that the router accepts. With no value, no client reaches an actor.5.1
--atenet-dataplaneenvoyenvoy or agentgateway. A second run with the other value switches a live cluster.6.6
--sandbox-classesgvisor,microvmThe sandbox classes to prepare. The default is the same on kind.4.2
--previewemptyThe preview features to turn on in every component.this page
--cluster-sizesize0size10 assumes a PostgreSQL node that you provide. It makes the bundled Postgres request 80 CPUs and 140 GiB of memory, and it changes the database settings to match. It does not create or reserve the node. Do not use it on kind or on a small cluster.8.1
--rollout-timeout60sHow long the installer waits for each workload.2.1
--cordon-system-infra-componentsoffKeeps the system components off the worker nodes. With size10, this flag is what puts Postgres alone on its node.8.4
--ateapi-log-levelnone: keeps the installed level, else infoThe log level of ate-api-server.-
--snapshot-locationnone. The kind profile sets gs://ate-snapshots/.The --snapshot-location of ate-api-server. Required unless PerTemplateSnapshotLocation is on.3.4
--actor-jwt-issuerhttps://idp.<namespace>.svcThe issuer in each actor JWT.5.3
--actor-jwt-algorithmES256The signing algorithm of a new actor JWT key: ES256 or RS256.5.3
--ateapi-authz-bootstrap-ownerssystem:serviceaccount:<namespace>:ate-clientThe --authz-bootstrap-owners of ate-api-server.5.2
--e2e-tuningfalseSets the atelet timers to an upload delay of 2 s and a detach delay of 30 s. It is for test runs.3.4
--setup-csinoneAlso installs a CSI driver: nfs, hostpath, or both.-
--record-dirthe cache directory of your userWhere the installer writes the record of each install.2.4

The help text of --credential-provider says that a provider requires Envoy. In our run the installer accepted {"name":"k8s.io"} with agentgateway, and injection worked.

atelet: when a snapshot becomes durable

FlagDefaultWhat it does
--snapshot-upload-delay5mAfter an asynchronous suspend, how long the snapshot waits on the node before the upload starts.
--snapshot-detach-delay30mHow long a suspended actor stays assigned to its node, with the node copy kept. Must not be shorter than the upload delay.
--snapshot-upload-timeout2mThe limit for one upload attempt, before a size allowance. Each failure in a row doubles the limit of the next attempt, up to 8 times the first.
--snapshot-upload-est-throughput-mib100The size allowance. Each attempt gets the time that the snapshot needs at this rate, in MiB per second, on top of the timeout.
--snapshot-upload-workers2Uploads that run at the same time on one node.
--snapshot-detach-workers2Detaches that run at the same time on one node.
--snapshot-report-workers1Snapshot state reports to ate-api-server that run at the same time.
--snapshot-report-give-up-after10mHow long atelet retries a failed state report.
--snapshot-cache-min-age10mA cached snapshot file younger than this is never removed.
--snapshot-cache-fetch-timeout10mThe limit for the download of one cached snapshot file. A restore that waits for a download that hangs waits this long.
--actor-stats-poll-interval1mHow often atelet samples the resource use of actors.
--drain-delay0How long atelet accepts new calls after SIGTERM.
--drain-timeout5mHow long atelet waits for its work to end when it stops.
--log-levelinfoOur source install ran with debug.
outputthe atelet arguments of our install, default timersFull log
atelet --localhost-registry-replacement=kind-registry:5000 --grpc-server-cred-bundle=/run/podidentity.podcert.ate.dev/credential-bundle.pem --client-ca-certs=/run/podidentity.podcert.ate.dev/trust-bundle.pem --log-level=debug --preview=
The whole file. No timer flag is present, so the defaults of 5 minutes and 30 minutes apply.

For one experiment we shortened both timers so that a resume from the bucket took seconds to set up. Section 3.3 uses that run.

outputthe atelet arguments with short timersFull log
… --log-level=debug --preview= --snapshot-upload-delay=3s --snapshot-detach-delay=10s
The end of the one line in the file. The first four flags are the same as above.

Short timers move snapshots to the bucket sooner. A resume after the detach delay then reads from the bucket, which is slower. A resume before it still uses the copy on the node. Do not copy the 3 s value into a cluster that serves users.

The router: parking and ports

FlagDefaultWhat it does
--parked-request-budget5sHow long the router holds a request that has no worker yet.
--parked-request-max1024How many requests the router holds at once. 0 turns parking off.
--parked-request-retry-interval100msThe first wait between two tries for a parked request.
--parked-request-retry-factor1.1The growth of that wait.
--parked-request-retry-jitter0.1A random part of each wait, as a fraction between 0 and 1.
--extproc-max-requests0The request limit of the Envoy connection to the router process. 0 means two times --parked-request-max, and at least 1024.
--drain-delay13sHow long the router serves after SIGTERM before it starts to drain.
--drain-timeout0The limit for the drain. 0 means the parking budget plus 10 s plus a margin of 5 s, which is 20 s with defaults. An explicit value must not be less than the parking budget. Parked requests finish inside it.
--route-timeout5mThe limit for one whole request.
--ingress-allowed-spiffe-idsnoneThe allowlist that the installer flag sets.
--port-https8443The listener for requests with the ate-target-actor header.
--port-connect-tls8444The listener for CONNECT tunnels, which kubectl ate proxy uses.
--upstream-connecttrueThe router reaches the worker with CONNECT.
--egress-policy-cache-ttl10sHow long the egress gateway keeps a policy that it read.
outputthe router arguments of our installFull log
atenet-router router --mode=ingress --namespace=ate-system … --port-https=8443 … --port-connect-tls=8444 … --drain-delay=13s --ingress-allowed-spiffe-ids=spiffe://cluster.local/ns/ate-system/sa/atenet-client --preview=
Parts of the first line. No parking flag is present, so the budget is the default of 5 seconds.

The 5.05 to 5.16 s in every no worker has room response of our runs is this budget plus the request time. Section 4.4 explains the mechanism.

ate-api-server and ate-controller

ComponentFlagDefaultWhat it does
ate-api-server--snapshot-locationnone. Required unless PerTemplateSnapshotLocation is on.The address prefix for durable snapshots, such as gs://ate-snapshots/. Without it and without that feature, the server does not start.
ate-api-server--postgres-schemasubstrateThe schema that holds every table.
ate-api-server--postgres-pool-max-conns0The size of the read-write connection pool, which the authorizer shares. 0 keeps the default of the connection string or of the driver. The owner, watch, and readiness pools do not follow it.
ate-api-server--template-resync-interval20sHow often the reconciler checks templates and their golden snapshots.
ate-api-server--authz-bootstrap-ownersnone. Required, at least one. ate-setup sets ate-client.Identities that are global owners for as long as the flag lists them, whatever the stored global access policy says.
ate-api-server--actor-jwt-issuernone. Required. ate-setup sets https://idp.ate-system.svc.The issuer in each actor JWT. It must be an https address with no query and no fragment.
ate-api-server--drain-delay, --drain-timeout13s, 15sThe wait before and during the stop of a replica.
ate-controller--dns-egress-policyemptyThe install manifest sets enforce-in-atunnel, so that the DNS relay enforces the egress policy.
ate-controller--worker-sync-concurrency2Worker pods that the controller registers as Worker records at the same time.

Two limits are fixed in the code and have no flag. A worker gives its actors 30 minutes after SIGTERM. ate-api-server ends any call after 10 minutes.

Preview features

A preview feature is off unless two switches agree.

  1. The server switch. Every component takes --preview with a list of names, or ALL. The installer flag passes one value to all of them.
  2. The client switch. A request must carry the header Ate-Preview-Allowed: true. kubectl ate --preview sends it.
NameField that it allowsDefault
ExternalVolumesvolumes[].external in a template, with a CSIDriverConfigoff
GoldenEgressPolicygoldenEgressPolicy in a templateoff
PerTemplateSnapshotLocationsnapshotConfig.storageLocation in a templateoff

The documentation says that an object that was created while a feature was on stays usable after the feature is turned off. That is true for validation only: the server does not check an unchanged value again. The code has two runtime effects that the documentation does not state.

Feature turned offWhat happens to an object that already uses it
ExternalVolumesA resume of an actor that has external volumes fails. The error is external volumes are not supported unless the ExternalVolumes preview gate is enabled.
PerTemplateSnapshotLocationThe server ignores snapshotConfig.storageLocation of the template. New snapshots go to --snapshot-location.
GoldenEgressPolicyWe found no runtime check.

We did not run these two cases. Turn a feature off only after you have removed the objects that use it.

We tried the four combinations of the two switches once, on the x86 server guest. The request was kubectl ate create actor-template with a file that has a goldenEgressPolicy field.

--preview on ate-api-server--preview on kubectl ateResult
emptynot passedError: failed to create actor template: rpc error: code = InvalidArgument desc = actor_template.golden_egress_policy: Forbidden
emptypassedthe same error
GoldenEgressPolicynot passedthe same error
GoldenEgressPolicypassedaccepted, with a golden tag within 30 s

The error names the field and not the feature. A read of the new template with kubectl ate get needed no client flag. In this test only ate-api-server had the server switch, and we restored its arguments afterwards. Every other argument list that we recorded has --preview= with no value, so all three features were off in all other runs.

Kubernetes features that the cluster must have

Substrate issues its certificates with Kubernetes pod certificates. The cluster script for kind turns on three Kubernetes features and one API group for them.

NameKind
ClusterTrustBundleKubernetes feature
ClusterTrustBundleProjectionKubernetes feature
PodCertificateRequestKubernetes feature
certificates.k8s.io/v1beta1API group and version

A cluster without them cannot start the Substrate components. We ran Kubernetes 1.37.0 in every test.

Agent Substrate 1.0.0 · b34fbee · 2026-11-05 · Edition 2026.11