Skip to content

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/cli

Images are available for:

linux/amd64
linux/arm64

Each release publishes a version tag and latest.

For reproducible environments and CI/CD pipelines, use a specific version:

Terminal window
docker pull ghcr.io/e2engine/cli:0.1.0

To use the latest published version:

Terminal window
docker pull ghcr.io/e2engine/cli:latest

The container entrypoint is the e2engine executable, so CLI arguments are passed directly to the image.

For example:

Terminal window
docker run --rm \
ghcr.io/e2engine/cli:0.1.0 \
version

is equivalent to:

Terminal window
e2engine version

Other CLI commands work the same way:

Terminal window
docker run --rm \
ghcr.io/e2engine/cli:0.1.0 \
get environments

See CLI for the complete command reference.

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:

Terminal window
docker run --rm \
-v "$PWD/.e2engine:/data" \
-e E2ENGINE_DATA_DIR=/data \
ghcr.io/e2engine/cli:0.1.0 \
get environments

With the default database configuration, the database is persisted on the host as:

./.e2engine/e2engine.sqlite

The same data directory should be mounted for all commands that operate on the same E2Engine resources and executions.

Mount specification files when creating E2Engine resources:

Terminal window
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.yml

The same approach applies to Tests:

Terminal window
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.yml

and TestSuites:

Terminal window
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.yml

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.AccountService

The referenced file must be available inside the E2Engine container at the path resolved by E2Engine.

For example:

Terminal window
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 environments

When resource creation and execution use separate docker run --rm invocations, mount required external files for every invocation that may need them.

A custom configuration file can be mounted into the container:

Terminal window
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 environments

Configuration can also be supplied through supported E2ENGINE_ environment variables.

See Configuration for available settings.

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.

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 boundaries

Put the participating containers on the same user-defined Docker network:

Terminal window
docker network create e2engine-network

Container names can then be used as hostnames on that network.

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:50051

E2Engine 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:8083

0.0.0.0 makes these service boundaries reachable through the E2Engine container’s network interface.

Give the E2Engine execution container a stable name:

Terminal window
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-demo

Other 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:8081
ACCOUNT_SERVICE_ADDR=e2engine:8082
NOTIFICATION_SERVICE_ADDR=e2engine:8083

The resulting topology is:

Payment API
│
├── HTTP ──▶ e2engine:8081 ─────────────▶ mocked Fraud service
│
├── gRPC ──▶ e2engine:8082 ──▶ account:50051
│ real Account service
│
└── gRPC ──▶ e2engine:8083 ─────────────▶ mocked Notification service

For the real Account service, E2Engine sits between the system under test and the real dependency:

Payment API
│
▼
e2engine:8082
│
▼
E2Engine
│
▼
account:50051
│
▼
Account service

This 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:8081

makes 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:8081

and address it through the E2Engine container name:

e2engine:8081

Similarly, 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.

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.