Docker
E2Engine is available as a multi-platform container image containing the e2engine CLI.
The image provides the same commands and behavior as a locally installed CLI, packaged as a minimal standalone container.
The E2Engine image is published to GitHub Container Registry:
ghcr.io/e2engine/cliImages are available for:
linux/amd64linux/arm64Each release publishes a version tag and latest.
For reproducible environments and CI/CD pipelines, use a specific version:
docker pull ghcr.io/e2engine/cli:0.1.0To use the latest published version:
docker pull ghcr.io/e2engine/cli:latestRun the CLI
Section titled “Run the CLI”The container entrypoint is the e2engine executable, so CLI arguments are passed directly to the image.
For example:
docker run --rm \ ghcr.io/e2engine/cli:0.1.0 \ versionis equivalent to:
e2engine versionOther CLI commands work the same way:
docker run --rm \ ghcr.io/e2engine/cli:0.1.0 \ get environmentsSee CLI for the complete command reference.
Persist data
Section titled “Persist data”E2Engine stores resources and execution records in its local database.
Because each docker run --rm invocation creates a temporary container, mount a host directory as the E2Engine data directory to preserve state between commands:
docker run --rm \ -v "$PWD/.e2engine:/data" \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ get environmentsWith the default database configuration, the database is persisted on the host as:
./.e2engine/e2engine.sqliteThe same data directory should be mounted for all commands that operate on the same E2Engine resources and executions.
Use resource specifications
Section titled “Use resource specifications”Mount specification files when creating E2Engine resources:
docker run --rm \ -v "$PWD/.e2engine:/data" \ -v "$PWD/e2engine:/specs:ro" \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ create environment /specs/payment-demo.docker.env.ymlThe same approach applies to Tests:
docker run --rm \ -v "$PWD/.e2engine:/data" \ -v "$PWD/e2engine:/specs:ro" \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ create test /specs/successful-payment.docker.test.ymland TestSuites:
docker run --rm \ -v "$PWD/.e2engine:/data" \ -v "$PWD/e2engine:/specs:ro" \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ create testsuite /specs/smoke.ts.ymlExternal files
Section titled “External files”Specifications may reference additional files that E2Engine needs during execution.
For example, an Environment can use an external protobuf definition:
proto: external: file: ./proto/account.proto service: account.v1.AccountServiceThe referenced file must be available inside the E2Engine container at the path resolved by E2Engine.
For example:
docker run --rm \ -v "$PWD/.e2engine:/data" \ -v "$PWD/e2engine:/specs:ro" \ -v "$PWD/proto:/proto:ro" \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ get environmentsWhen resource creation and execution use separate docker run --rm invocations, mount required external files for every invocation that may need them.
Configuration
Section titled “Configuration”A custom configuration file can be mounted into the container:
docker run --rm \ -v "$PWD/e2engine/config.yml:/config/config.yml:ro" \ -v "$PWD/.e2engine:/data" \ -e E2ENGINE_CONFIG_PATH=/config/config.yml \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ get environmentsConfiguration can also be supplied through supported E2ENGINE_ environment variables.
See Configuration for available settings.
Minimal image
Section titled “Minimal image”The E2Engine image is built from scratch and contains the statically built e2engine executable.
It does not contain a shell, package manager, or general-purpose command-line utilities.
Commands such as sh, bash, and curl are therefore not available inside the container.
Container networking
Section titled “Container networking”When E2Engine and the system under test run in containers, Docker networking determines how they address each other.
There are two directions of communication to consider:
E2Engine ──▶ real services
system under test ──▶ E2Engine-managed service boundariesPut the participating containers on the same user-defined Docker network:
docker network create e2engine-networkContainer names can then be used as hostnames on that network.
Reaching real services
Section titled “Reaching real services”A real service can be addressed using its Docker container name.
For example, if a real Account service runs in a container named account and listens on port 50051, the Environment can use:
grpc_target: account:50051E2Engine can then forward calls to the real service over the shared Docker network.
Reaching E2Engine from the system under test
Section titled “Reaching E2Engine from the system under test”Mocked services and observed real services expose E2Engine-managed service boundaries.
For example:
spec: services: - id: fraud kind: http mode: mocked address: 0.0.0.0:8081
- id: account kind: grpc mode: real address: 0.0.0.0:8082 grpc_target: account:50051
- id: notification kind: grpc mode: mocked address: 0.0.0.0:80830.0.0.0 makes these service boundaries reachable through the E2Engine container’s network interface.
Give the E2Engine execution container a stable name:
docker run --rm \ --name e2engine \ --network e2engine-network \ -v "$PWD/.e2engine:/data" \ -v "$PWD/e2engine:/specs:ro" \ -v "$PWD/proto:/proto:ro" \ -e E2ENGINE_DATA_DIR=/data \ ghcr.io/e2engine/cli:0.1.0 \ run testsuite smoke payment-demoOther containers on the same network can then address the E2Engine service boundaries using the hostname e2engine.
For example, a Payment API can be configured with:
FRAUD_SERVICE_URL=http://e2engine:8081ACCOUNT_SERVICE_ADDR=e2engine:8082NOTIFICATION_SERVICE_ADDR=e2engine:8083The resulting topology is:
Payment API │ ├── HTTP ──▶ e2engine:8081 ─────────────▶ mocked Fraud service │ ├── gRPC ──▶ e2engine:8082 ──▶ account:50051 │ real Account service │ └── gRPC ──▶ e2engine:8083 ─────────────▶ mocked Notification serviceFor the real Account service, E2Engine sits between the system under test and the real dependency:
Payment API │ ▼e2engine:8082 │ ▼E2Engine │ ▼account:50051 │ ▼Account serviceThis allows E2Engine to observe the call while forwarding it to the real service.
If the Payment API called account:50051 directly, the application call could succeed, but E2Engine would not observe it. Call expectations for the Account service would therefore see zero calls.
Avoid loopback addresses between containers
Section titled “Avoid loopback addresses between containers”127.0.0.1 inside a container refers to that container itself.
For example:
address: 127.0.0.1:8081makes the service boundary accessible only from inside the E2Engine container.
If another container must call the service, bind it to:
address: 0.0.0.0:8081and address it through the E2Engine container name:
e2engine:8081Similarly, host.docker.internal is not required when both E2Engine and the system under test are containers on the same Docker network. They should communicate using their Docker network names.
Complete examples
Section titled “Complete examples”For a complete example covering Docker networks, real and mocked services, mounted specifications, external protobuf files, persistent data, and test execution, see Running E2Engine with Docker.
For an automated pipeline using the same container model, see CI/CD pipelines.
The public E2Engine demo also provides an executable example of both local CLI and Docker/CI usage.

