Emulator Components
Emulator components are stack-scoped, long-running containers that stand in for a cloud API (AWS, GCP, Azure), Kubernetes, or a backing service (Vault/OpenBao, an OCI/Terraform registry) during local development and testing. You declare them with the same stack-based configuration used for Terraform, Helmfile, Packer, and Ansible, and operate them with the atmos emulator command group — letting the rest of your stack run offline, with no cloud account.
An emulator container outlives the atmos process and is discovered by labels derived from the canonical component instance address, so atmos emulator ps, logs, exec, and down reattach to the already-running container.
Available Configuration Sections
Emulator components are declared under components.emulator and support these first-class sections (siblings of metadata — not nested under vars):
driver- Required. The built-in driver that selects the image and target, for example
floci/aws,k3s,openbao, orregistry. See Supported Drivers & Targets. cloud- Optional explicit target (
aws,gcp,azure,kubernetes,vault,registry). Derived from the driver when omitted; if set, it must match the driver's target. region- Cloud region for the
aws/gcp/azuretargets. project- GCP project id for the
gcptarget. services- The emulated services to enable (informational; may drive the emulator's environment).
ephemeral- Set to
trueto run the emulator without persisting state — all data is discarded ondown. Defaults tofalse, so emulators persist state by default (see Persistence). The CLI--ephemeralflag overrides this for a singleup. container- Container overrides for the emulator —
image,command,ports,mounts,pull,user,run_args,restart,healthcheck, and more. Reuses the same schema as the container component, so emulator and container configuration stay consistent. Anything you don't set falls back to the driver's defaults (see Health Checks & Restart Policies). metadata- Component behavior and inheritance (e.g.
metadata.type: abstractfor catalog base components).
Component Structure
A minimal emulator component selects a driver; everything else has a sensible default:
components:
emulator:
aws:
driver: floci/aws
region: "{{ .vars.region }}"
With the configuration above, atmos emulator up aws --stack=plat-ue2-dev starts a local AWS sandbox for the plat-ue2-dev stack.
Supported Drivers & Targets
Each driver maps to one target and supplies a default image and port. The host port is auto-assigned unless you pin it with container.ports.
| Driver | Target | Default image | Container port |
|---|---|---|---|
floci/aws (default for AWS) | aws | floci/floci:latest | 4566 |
ministack/aws | aws | ministack/ministack:latest | 4566 |
localstack/aws (opt-in/legacy) | aws | localstack/localstack:3 | 4566 |
floci/gcp | gcp | floci/floci-gcp:latest | 4588 |
floci/az | azure | floci/floci-az:latest | 4577 |
k3s | kubernetes | rancher/k3s:latest | 6443 |
openbao (default for Vault) | vault | openbao/openbao:latest | 8200 |
vault (opt-in) | vault | hashicorp/vault:latest | 8200 |
registry | registry | registry:2 | 5000 |
The aws, gcp, azure, and kubernetes targets bind to your components automatically through an emulator identity (kind: aws/emulator, gcp/emulator, azure/emulator, kubernetes/emulator): the identity injects the live endpoint, dummy credentials, and provider configuration, so components need no providers.tf and no endpoint wiring.
The vault and registry targets have no identity. You consume their live endpoint with the !emulator YAML function in stack manifests, or — for a store declared in atmos.yaml — by pinning a host port and pointing at it with a static address (see Vault/OpenBao).
Configuring Each Emulator Type
AWS
The default floci/aws driver emulates the AWS control plane. Bind it with an aws/emulator identity; Terraform components then apply against the sandbox with no provider block:
# atmos.yaml
auth:
identities:
local-aws:
kind: aws/emulator
emulator: aws # the emulator component name
default: true # every component runs under it
# stack manifest
components:
emulator:
aws:
driver: floci/aws
region: us-east-1
The identity injects AWS_ENDPOINT_URL, AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY (test/test), and AWS_REGION into Terraform.
GCP
components:
emulator:
gcp:
driver: floci/gcp
project: my-project
region: us-central1
A gcp/emulator identity exposes STORAGE_EMULATOR_HOST, PUBSUB_EMULATOR_HOST, GOOGLE_CLOUD_PROJECT, and disables credential lookups (CLOUDSDK_AUTH_DISABLE_CREDENTIALS=true).
Azure
components:
emulator:
azure:
driver: floci/az
An azure/emulator identity exposes an Azurite-compatible AZURE_STORAGE_CONNECTION_STRING and AZURE_STORAGE_ACCOUNT.
Kubernetes
components:
emulator:
kubernetes:
driver: k3s
k3s runs a nested Kubernetes in a single privileged container. A kubernetes/emulator identity harvests the kubeconfig from the running container and sets KUBECONFIG; you can also materialize it explicitly with KUBECONFIG: !emulator kubernetes kubeconfig.
Vault/OpenBao
openbao (the default) and vault run an API-compatible secret server backed by file storage, so secrets persist across down/up (see Persistence). A fresh server boots sealed and uninitialized; Atmos automatically initializes it, unseals it, and enables the KV v2 engine at secret/ on start, recording the unseal key and the dynamically generated root token under the data dir. Atmos's hashicorp-vault store talks to it, so you can practice the full secrets workflow with no real Vault.
A store lives in atmos.yaml (global config, no stack context), so it cannot use the stack-scoped !emulator function. Pin the port and point the store at it with a static address; omit token so the store reads the dynamic root token from the standard VAULT_TOKEN environment variable (surfaced by a Vault/OpenBao emulator identity, or exported manually from the recorded bootstrap):
# atmos.yaml
stores:
secrets/vault:
kind: hashicorp-vault
secret: true
options:
address: http://localhost:8200
# token omitted -> read from the VAULT_TOKEN environment variable
mount: secret
# stack manifest
components:
emulator:
openbao:
driver: openbao
container:
ports:
- host: 8200 # pin so the store reaches it at a stable address
container: 8200
terraform:
app:
secrets:
vars:
APP_SECRET:
description: Application secret stored in the OpenBao (Vault KV v2) emulator.
store: secrets/vault
required: true
vars:
app_secret: !secret APP_SECRET
Then atmos secret set APP_SECRET=… -c app, atmos secret list -c app, and atmos terraform apply app round-trip the value through OpenBao — delivered to Terraform off-disk as TF_VAR_app_secret.
Registry
registry runs the standard OCI / Terraform registry (registry:2) for vendoring and the registry cache. Consume its live host:port with !emulator in a stack manifest:
components:
emulator:
registry:
driver: registry
terraform:
app:
vars:
registry_host: !emulator registry url # e.g. http://localhost:5000
The !emulator function
For the vault and registry targets (which have no emulator identity), the !emulator YAML function resolves a running emulator's live connection details in stack manifests:
vars:
url: !emulator registry url # endpoint URL (alias: endpoint)
host: !emulator registry host # host only
port: !emulator registry port # bound host port
vault_addr: !emulator openbao env.VAULT_ADDR # a single SDK env var
The available keys are endpoint/url, host, port, region, project, kubeconfig, and env.<VAR>. The emulator must be running (atmos emulator up) for the function to resolve.
Health Checks & Restart Policies
Emulators are long-lived local services, so they support the same healthcheck and restart configuration as the container component — set under the container block (the shape is shared between the two kinds):
components:
emulator:
aws:
driver: floci/aws
container:
restart:
policy: unless-stopped # no | always | on-failure | unless-stopped
max_retries: 5 # on-failure only
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:4566/_localstack/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
Driver defaults
You rarely need to write any of this — each built-in driver already supplies sensible defaults, which your container.restart / container.healthcheck override:
- Restart policy
- Every built-in driver defaults to
unless-stopped, so an emulator comes back after a daemon restart or a crash.atmos emulator downstill stops and removes it. - Health check
- The lightweight emulators ship a default readiness probe: Floci (AWS/GCP/Azure) and the registry probe their listening port from inside the container. Vault/OpenBao and k3s ship no default probe — their readiness is handled by the automatic Vault bootstrap (init/unseal) and the Kubernetes identity's API wait, respectively. You can still set
container.healthcheckexplicitly on any emulator.
Readiness gating
When a health check applies (yours or the driver default), atmos emulator up blocks until the container reports healthy before returning, so anything that depends on the emulator — the emulator identity, a !emulator lookup, or a follow-on atmos terraform apply — never races a not-yet-ready emulator. To opt a specific emulator out of the default probe (and the gating), disable it:
container:
healthcheck:
disable: true # or: test: ["NONE"]
Component-Type Defaults
Define defaults for all emulator components under the top-level emulator key:
emulator:
vars:
managed_by: Atmos
components:
emulator:
aws:
driver: floci/aws
Complete Example
This native scenario brings up an OpenBao emulator and round-trips a secret through it — the same fixture the end-to-end test exercises:
Running Emulator Commands
# Start (or reuse) the emulator for a stack
atmos emulator up aws -s plat-ue2-dev
# List running emulators in the stack
atmos emulator ps -s plat-ue2-dev
# Stream the emulator's logs
atmos emulator logs aws -s plat-ue2-dev
# Run a command inside the emulator container
atmos emulator exec aws -s plat-ue2-dev -- aws s3 ls
# Stop and remove the emulator container (persisted state is kept)
atmos emulator down aws -s plat-ue2-dev
# Stop the emulator and wipe its persisted state
atmos emulator reset aws -s plat-ue2-dev --force
Container Runtime
Emulators run inside a container runtime selected by the global container.runtime.provider configuration and the ATMOS_CONTAINER_RUNTIME environment variable; Docker and Podman are auto-detected.
Persistence
By default, emulators persist their state across down/up. Atmos bind-mounts a per-instance host directory under the XDG cache onto the emulator's in-container data directory, so resources you create (S3 buckets, registry images, the k3s cluster, OpenBao secrets, …) survive restarts.
- Location
$XDG_CACHE_HOME/atmos/emulator/<instance>(defaulting to~/.cache/atmos/emulator/…on Linux/macOS). Override the base withATMOS_XDG_CACHE_HOMEorXDG_CACHE_HOME. The<instance>segment is the sanitized canonical instance name (atmos-<stack>-emulator-<component>), so instances never collide.- Disabling it
- Set
ephemeral: trueon the component, or pass--ephemeralto a singleatmos emulator up. Ephemeral instances mount nothing and discard all state ondown. - Resetting it
atmos emulator resetstops the container and deletes its persisted state directory — the nextupstarts fresh.downalways keeps state.- Scope
- Persistence applies to every driver: Floci AWS/GCP/Azure, LocalStack, the registry, and k3s persist their data directories directly. OpenBao/Vault run a file-storage backend that Atmos auto-initializes and unseals on start (recording the unseal key and generated root token under the data dir), so secrets persist too.
resetwipes the unseal key and token with the rest of the state.
Environment Variables
Each target publishes the connection environment its SDKs and tools expect. The emulator identity (or the !emulator function) surfaces these from the live endpoint:
AWS_ENDPOINT_URL,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION- AWS target — the sandbox endpoint plus dummy credentials.
STORAGE_EMULATOR_HOST,PUBSUB_EMULATOR_HOST,GOOGLE_CLOUD_PROJECT,CLOUDSDK_AUTH_DISABLE_CREDENTIALS- GCP target.
AZURE_STORAGE_CONNECTION_STRING,AZURE_STORAGE_ACCOUNT- Azure target (Azurite-compatible).
KUBECONFIG- Kubernetes target — path to the kubeconfig harvested from the k3s container.
VAULT_ADDR,VAULT_TOKEN- Vault/OpenBao target — the server address and the root token harvested from the running emulator.
ATMOS_REGISTRY_HOST- Registry target — the live host:port of the OCI/Terraform registry.
Best Practices
-
Prefer the default drivers:
floci/awsandopenbaoare free and MIT/MPL-licensed; reach forlocalstack/awsorvaultonly when you specifically need them. -
Bind cloud targets with an identity, not by hand: an
aws/emulator(orgcp/azure/kubernetes) identity removes the need for anyproviders.tfor endpoint wiring. -
Pin a host port for
atmos.yamlstores: a store can't use!emulator, so pin the emulator's port and point the store at a static address. -
Pin images by digest for reproducibility: override
container.imagewith a digest in CI to avoid pulling a drifting:latest. -
Keep secrets off disk: declare them in
secrets.varsbacked by an emulated store and reference them with!secret; the value is delivered asTF_VAR_*, never written to a varfile.