Container Images¶
Hawk doesn't publish prebuilt images for its services. Every pulumi up builds them from your checkout on your default Docker builder1 and pushes them to your stack's own ECR repositories.
Using an AI agent? Point it at the agent reference.
What happens during a deploy¶
flowchart LR
subgraph local["Your machine"]
S2["<b>2. Check for changes</b>"]
S3["<b>3. Build</b><br/><i>default Docker builder</i>"]
end
subgraph aws["AWS, your stack's Region"]
S1["<b>1. Create repositories</b>"]
S4["<b>4. Push to ECR</b>"]
S5["<b>5. Switch services</b><br/><i>ECS · Lambda · Batch · EKS</i>"]
end
NET["<b>Internet</b><br/><i>base images · GitHub</i>"]
S1 --> S2 --> S3 --> S4 --> S5
NET --> S3
- Create repositories. Pulumi creates an ECR repository for each image in your stack.
- Check for changes. Pulumi hashes each image's files and Dockerfile. If nothing changed, it keeps the image already in ECR.
- Build. Changed images build at the same time on your default Docker builder, for
hawk:cpuArchitecture(arm64 unless you change it). Each build pulls its base images, installs dependencies2 and copies in its code. - Push to ECR. Each image is pushed as
:latest, together with a build cache that makes the next deploy faster. - Switch services. ECS, Lambda, Batch and Kubernetes refer to images by digest, so they only change when an image's content does.
How long it takes¶
| Step | First deploy (cold cache) | Later deploys (warm cache) |
|---|---|---|
| 1–2. Repositories and change check | Seconds | Seconds |
| 3–4. Build and push, per image | 1.5–3 min in the stack's Region4; up to 35 min from home5 | 15 s–3.5 min3 |
| 5. Switch services | Varies with ECS rollouts | Varies |
Whole pulumi up |
30–45 min; longer from home5 | 2–8 min3 |
Images¶
| Image | Runs as | Notes |
|---|---|---|
api |
ECS service | Also runs database migrations |
runner, janitor |
Kubernetes | |
middleman, relay |
ECS services | Both on by default |
viewer-static |
ECS service | Built with your stack's domain and login settings |
eval-log-importer, sample-editor |
Batch jobs | |
token_broker, job_status_updated, scan_importer |
Lambda | Lambda needs the image in ECR in the same Region |
eval_log_reader, jumphost |
Lambda, ECS | Optional |
Things to know¶
- The first deploy is the slow one. A new stack starts with an empty cache, so every layer is built and uploaded.
- The build machine needs disk space and upload bandwidth. If yours is short on either, see step 5 of the deploy guide.
- Pick your Docker host before the first deploy. Switching it later (with
DOCKER_HOST) can make Pulumi replace every image, and a replace can delete an image your services still use.
-
Your machine, unless you set up a remote one. Registry logins are read on the machine running Pulumi, even when the builder is remote. ↩
-
Most Python images use
uv sync; the Lambdas useuv pip install, the viewer pnpm, and the jumphostapk. Some also clone METR's pinnedinspect_aiorinspect_scoutfork from GitHub. ↩ -
METR's own deploys on GitHub's arm64 runners, building arm64 images with the GitHub Actions cache, October 2026. ↩↩
-
A 4-vCPU x86 EC2 instance in the stack's Region, building amd64 images (
hawk:cpuArchitecture: amd64) as a remote builder with an empty cache. ↩ -
An x86 laptop running Docker under WSL2 on home fibre, building amd64 images. Several builds failed and had to be retried. Building for a different architecture than the build machine is much slower; see Build host architecture. ↩↩