2.1

Install with ate-setup

Install from the release images: that path skips the image builds, the Rust compile, and a failure that the upstream quickstart does not mention.

You follow a quickstart on a clean machine. The third command runs for almost three minutes and then stops with an error from Docker about a flag you never typed. We hit that error on our first install, and you do not need to.

When you finish this section, you can install Agent Substrate v1.0.0 on a kind cluster from the release images. You can also say what the build from source needs, and fix the install errors we hit.

What you need

  • Linux or macOS with Docker. On Apple silicon we used Docker Desktop with 10 CPU and 8 GB.
  • Go 1.27. The checkout asks for toolchain go1.27.3, and Go downloads kind for you.
  • git and kubectl.
  • About 13 GB of disk. Our guest used 13 GB in all after this install, with the operating system.

Installer: ate-setup is the Go program in the checkout that installs and removes Agent Substrate. The release has no ate-setup binary, so you run it with go run from a checkout of the tag. The manifests also come from that checkout, so check out the tag that you install.

On Linux we raised two inotify limits before the install, because many pods on one node use many watches:

bash
sudo sysctl -w fs.inotify.max_user_instances=8192 fs.inotify.max_user_watches=1048576

Create the kind cluster

Clone the tag, then run the cluster script from the repository root:

bash
git clone --branch v1.0.0 https://github.com/agent-substrate/substrate.git
cd substrate
hack/create-kind-cluster.sh

The script does more than kind create cluster. Substrate needs three settings that a plain kind cluster does not have:

  • It starts a local image registry named kind-registry on 127.0.0.1:5001.
  • It turns on three Kubernetes preview features: ClusterTrustBundle, ClusterTrustBundleProjection, and PodCertificateRequest. Substrate gives every pod its certificate through them.
  • It looks for /dev/kvm. With KVM, the node can run the microVM sandbox class. Without KVM, only gVisor works.

The script deletes an existing kind cluster with the same name before it creates the new one. The default name is kind. Set KIND_CLUSTER_NAME if you already have a cluster with that name.

Install the control plane from the release images

Tell ate-setup that the target is kind, then deploy:

bash
export ATE_INSTALL_KIND=true
go run ./cmd/ate-setup deploy ate-system \
  --credential-provider='{"name":"k8s.io"}' \
  --ingress-allowed-spiffe-ids=spiffe://cluster.local/ns/ate-system/sa/atenet-client \
  --image-repo ghcr.io/agent-substrate/substrate --image-tag v1.0.0

Each flag has a reason:

  • ATE_INSTALL_KIND=true selects the kind profile: the kind overlays, the local registry, and the object store in the cluster. Export it in every shell that runs ate-setup.
  • --credential-provider is required. The value {"name":"k8s.io"} deploys the bundled provider that reads Kubernetes Secrets. Section 6.5 uses it.
  • --ingress-allowed-spiffe-ids lists the clients that the router lets through. With no value, no client reaches any actor. The identity in this command is the one that kubectl ate proxy presents.
  • --image-repo and --image-tag install published images. Each of the two needs the other.

The installer prints every setting first, and then one line for each step. These lines tell you that the images came from the registry and that the install is complete:

outputthe install from the release imagesFull log
>> Downloading kata-static 4.3.1 (amd64)...
>> Downloading cloud-hypervisor v53.0 (cloud-hypervisor-static)...
…
[step]: images: pre-built from ghcr.io/agent-substrate/substrate, tag v1.0.0
…
[step]: Waiting for ATE system components to be ready...
  (rollout status deployment/ate-api-server took 0.005s)
…
  (rollout status daemonset/atelet took 0.003s)
  (rollout status deployment/k8s-credential-provider took 0.003s)
Seven lines from 142. The settings table, the secrets, and the other rollout lines are cut.

The first two lines show a download that the release images do not remove. The installer fetches the guest files of the microVM class from GitHub on the first install from a directory, and it keeps them under bin/microvm-assets. A later install from the same directory skips the download when the files and their version stamp are present. The installer documents --sandbox-classes=gvisor to install gVisor only. We ran that flag for one install, on a cluster with three kind nodes on the second x86 server guest (16 vCPU, 23 GB). The system step took 114 s.

Deploy the counter demo

The demo gives you a WorkerPool, a template, and an atespace to test with:

bash
go run ./cmd/ate-setup deploy demo counter

This step builds two images with ko and pushes them to kind-registry, also on the release path. The release images leave out the demos. The step ends when the golden snapshot of the counter template is ready.

What we measured

Figure 2.1 shows the steps of both x86 installs.

Fig. 2.1install steps from the release images and from sourcechart
Install steps from the release images and from source Two groups of horizontal bars with the seconds of each install step. From the release images on an x86 guest with 16 vCPU: kind cluster 55 s, deploy ate-system 162 s, deploy demo counter 94 s, 311 s in all. Built from source on an x86 guest with 24 vCPU: kind cluster 56 s, deploy ate-system 163 s and failed, the same step again 266 s, deploy demo counter 47 s, 532 s in all. The failed step is rose and stopped on the missing Docker buildx plugin. FROM THE RELEASE IMAGES · X86 GUEST, 16 VCPU 311 s in all kind cluster 55 s deploy ate-system 162 s deploy demo counter 94 s 0 100 200 300 s BUILT FROM SOURCE · X86 GUEST, 24 VCPU 532 s in all kind cluster 56 s deploy ate-system 163 s, exit 1: no buildx the same step again 266 s deploy demo counter 47 s 0 100 200 300 s The source build made the Envoy image with docker buildx and compiled a Rust module. In both installs the demo step built the worker and counter images with ko.
From the release images deploy ate-system took 162 s on one guest, and from source on a larger guest it failed, then took 266 s. Each bar is one step of one install, on an axis in seconds. The two installs ran on two x86 guests of different sizes, so read each group alone. The rose bar is the failed step.

We measured the release-image install once on a second x86 server guest (16 vCPU, 23 GB). The kind cluster took 55 s, deploy ate-system took 162 s, and deploy demo counter took 94 s. The disk held 13 GB afterwards. Raw runs

We measured the build from source once on the x86 server guest (24 vCPU, 47 GB, nested KVM). The first deploy ate-system failed after 163 s. After we installed one package, the same command took 266 s, and the demo took 47 s. The disk held 18 GB afterwards. Raw runs

We measured the release-image install once on an Apple silicon laptop under Docker Desktop. The kind cluster took 119 s, and deploy ate-system took 702 s. The longest wait in its log was 178 s for the object store pod. The kind node held 2.7 GiB of memory after the install. Raw runs

The two x86 installs ran on different guests, so the difference of 104 s between 162 s and 266 s is indicative only. It is not a controlled comparison. What we can state without a number is what each path does. The release-image path skips the image builds and the Rust compile, and the next heading shows both in the source log. The laptop is a third machine on another network, so keep its seconds apart from the seconds of the guests.

What the build from source costs

Leave out --image-repo and --image-tag, and ate-setup builds every image from the checkout. The upstream quickstart shows that form. It lists Go, kubectl, and Docker as the things you need. On Ubuntu 24.04 with the stock Docker package, that list is one item short:

outputthe source install without the Docker buildx pluginFull log
unknown flag: --platform
…
Error: while building the envoy-dataplane image: exit status 125
The docker usage text between the two lines is cut.

The Envoy dataplane image is built from a Dockerfile with docker buildx. The other images are built with ko. On Ubuntu the fix is one package:

bash
sudo apt-get install -y docker-buildx

The second cost is a Rust compile. The Envoy image contains a Rust module for the egress policy. The build clones the Envoy repository and compiles that module:

outputthe Rust module in the source buildFull log
#11 0.323     Updating git repository `https://github.com/envoyproxy/envoy`
…
#11 53.04    Compiling proc-macro2 v1.0.107
…
#11 91.89     Finished `release` profile [optimized] target(s) in 1m 31s
…
#11 DONE 92.2s
Four lines from the build of the Envoy dataplane image. About 90 dependency lines are cut.

That one build step took 92 s of the 266 s. You pay it again when the build cache is empty. Build from source when you change Substrate itself. For every other install, use the release images.

Change the dataplane later

The same command switches a running cluster from Envoy to agentgateway. Add one flag and run it again:

bash
go run ./cmd/ate-setup deploy ate-system \
  --credential-provider='{"name":"k8s.io"}' \
  --ingress-allowed-spiffe-ids=spiffe://cluster.local/ns/ate-system/sa/atenet-client \
  --image-repo ghcr.io/agent-substrate/substrate --image-tag v1.0.0 \
  --atenet-dataplane=agentgateway

We measured this switch once on the second x86 server guest (16 vCPU, 23 GB). It took 32 s and needed no new cluster. Section 6.6 compares the two dataplanes. Raw runs

If the install fails

What you seeCauseFix
unknown flag: --platform, then exit status 125A build from source without the Docker buildx pluginInstall the plugin, or install from the release images
The installer stops and prints retry with: ate-setup deploy ate-system --config and a fileA step failed, and the installer saved the settings of the runFix the cause, then run the printed command. Start it with go run ./cmd/ate-setup, because the release has no ate-setup binary
kubectl shows pods you do not knowThe kubeconfig context is not the one of your kind clusterRun kubectl config use-context kind-kind. With your own KIND_CLUSTER_NAME, the context is kind- and that name

The last row happened to us on the laptop. After a restart of Docker Desktop, kubectl pointed at the cluster that Docker Desktop includes, and our first test ran there.

To remove everything, delete the cluster and the registry:

bash
./hack/delete-kind-cluster.sh

Old guides for v0.x use install scripts that no longer exist. Section 8.4 lists what changed.

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