This document covers Docker requirements, setup, and usage for benchmarkoor.
- Requirements
- Running Benchmarkoor in Docker
- How Docker is Used
- Container Lifecycle
- Network Configuration
- Volume Management
- Resource Limits
- Container Labels
- Cleanup
- Troubleshooting
Benchmarkoor requires Docker Engine to run Ethereum execution clients. The minimum supported version is Docker 20.10+.
# Check Docker version
docker --version
# Verify Docker daemon is running
docker infoThe user running benchmarkoor must have permission to interact with the Docker daemon:
# Option 1: Add user to docker group (recommended)
sudo usermod -aG docker $USER
# Log out and back in for changes to take effect
# Option 2: Run benchmarkoor with sudo (not recommended for production)
sudo benchmarkoor run --config config.yamlBenchmarkoor connects to Docker via the standard socket at /var/run/docker.sock. If using a custom socket location, set the DOCKER_HOST environment variable:
export DOCKER_HOST=unix:///path/to/docker.sock
benchmarkoor run --config config.yamlBenchmarkoor itself can run inside a Docker container. This is useful for CI/CD pipelines or isolated environments.
# Build with default settings
docker build -t benchmarkoor .
# Build with version info
docker build \
--build-arg VERSION=1.0.0 \
--build-arg COMMIT=$(git rev-parse HEAD) \
--build-arg DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-t benchmarkoor .When running benchmarkoor in a container, it needs access to the Docker socket to manage client containers (Docker-in-Docker pattern using sibling containers):
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-v $(pwd)/results:/app/results \
benchmarkoor run --config /app/config.yamlIf using pre-populated data directories, mount them into the container:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-v $(pwd)/results:/app/results \
-v /data/snapshots:/data/snapshots:ro \
benchmarkoor run --config /app/config.yamlIf using the overlayfs or zfs datadir method, the container needs privileged mode:
docker run --rm --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-v $(pwd)/results:/app/results \
-v /data/snapshots:/data/snapshots:ro \
benchmarkoor run --config /app/config.yamlIf using drop_memory_caches, mount the proc filesystem and run with appropriate permissions:
docker run --rm --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /proc/sys/vm/drop_caches:/host/drop_caches \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-v $(pwd)/results:/app/results \
benchmarkoor run --config /app/config.yamlThen configure in your config.yaml:
global:
drop_caches_path: /host/drop_cachesBenchmarkoor uses Docker to:
- Run Ethereum clients - Each client instance runs in its own container
- Isolate test environments - Each benchmark run gets fresh containers and volumes
- Manage networking - Containers communicate via a dedicated Docker network
- Collect metrics - Resource usage is collected via Docker Stats API or cgroups
| Type | Purpose | Naming Pattern |
|---|---|---|
| Init container | Initialize client data directory (e.g., geth init) | benchmarkoor-{runID}-{instanceID}-init |
| Client container | Run the Ethereum client | benchmarkoor-{runID}-{instanceID} |
For each benchmark run, benchmarkoor follows this lifecycle:
1. Pull image (based on pull_policy)
↓
2. Create Docker volume (if not using datadir)
↓
3. Run init container (if required and not using datadir)
↓
4. Create and start client container
↓
5. Wait for RPC endpoint to be ready
↓
6. Execute benchmark tests
↓
7. Stop and remove container
↓
8. Remove volume
Some clients (like Erigon) require an initialization step before starting. The init container:
- Uses the same image as the main container
- Runs the client's init command (e.g.,
erigon init) - Has access to the same volumes
- Must complete successfully before the main container starts
Init containers are skipped when:
- Using pre-populated data directories (
datadirsconfig) - No genesis file is configured
| Policy | Behavior |
|---|---|
always (default) |
Always pull the latest image |
if-not-present |
Only pull if image doesn't exist locally |
never |
Never pull, fail if image doesn't exist |
Benchmarkoor creates a dedicated Docker bridge network for container communication.
global:
container_network: benchmarkoor # default- Network is created automatically on first run (if it doesn't exist)
- All containers in a benchmark run join this network
- Containers can communicate via container name or IP
- Network persists between runs for efficiency
- Use
cleanup_on_start: trueto remove the network on startup
Client containers expose the following ports (internal to the Docker network):
| Client | RPC Port | Engine Port | Metrics Port |
|---|---|---|---|
| Geth | 8545 | 8551 | 6060 |
| Nethermind | 8545 | 8551 | 9091 |
| Besu | 8545 | 8551 | 9545 |
| Erigon | 8545 | 8551 | 6060 |
| Nimbus | 8545 | 8551 | 9091 |
| Reth | 8545 | 8551 | 9001 |
Ports are not mapped to the host by default. Benchmarkoor communicates with containers via their internal Docker network IP.
When not using pre-populated data directories, benchmarkoor creates a Docker volume for each run:
- Name pattern:
benchmarkoor-{runID}-{instanceID} - Labels: Include instance ID, client type, run ID for identification
- Lifecycle: Created before init container, removed after benchmark completes
For stateful benchmarks, you can provide pre-populated data directories instead of Docker volumes. See Data Directories in the configuration reference.
Docker resource limits control CPU and memory allocation for client containers.
client:
config:
resource_limits:
# Option 1: Random CPU selection (different CPUs each run)
cpuset_count: 4
# Option 2: Specific CPUs
cpuset: [0, 1, 2, 3]The cpuset_count option uses Fisher-Yates shuffle to randomly select CPUs, providing variation between runs while maintaining consistent CPU count.
client:
config:
resource_limits:
memory: "16g"
swap_disabled: trueWhen swap_disabled: true:
memory-swapis set equal tomemory(no swap available)memory-swappinessis set to 0
Resource limits can be overridden per instance:
client:
config:
resource_limits:
cpuset_count: 4
memory: "16g"
instances:
- id: besu-latest
client: besu
resource_limits:
cpuset_count: 8 # Besu gets more CPUs
memory: "32g" # and more memoryAll benchmarkoor-managed containers and volumes are labeled for identification:
| Label | Description |
|---|---|
benchmarkoor.managed-by |
Always benchmarkoor |
benchmarkoor.instance |
Instance ID from config |
benchmarkoor.client |
Client type (geth, nethermind, etc.) |
benchmarkoor.run-id |
Unique run identifier |
benchmarkoor.type |
Container type (init for init containers) |
These labels are used by the cleanup command to identify orphaned resources.
Benchmarkoor automatically cleans up containers and volumes after each run. If a run is interrupted, resources may be left behind.
Use the cleanup command to remove orphaned resources:
# List resources that would be removed
benchmarkoor cleanup
# Remove resources (with confirmation)
benchmarkoor cleanup
# Remove resources without confirmation
benchmarkoor cleanup --forceThe cleanup command removes:
- Docker containers with
benchmarkoor.managed-by=benchmarkoorlabel - Docker volumes with
benchmarkoor.managed-by=benchmarkoorlabel - Orphaned ZFS clones and snapshots (if using ZFS datadir method)
- Orphaned overlayfs mounts (if using overlayfs datadir method)
Enable automatic cleanup at startup:
global:
cleanup_on_start: trueThis removes any leftover resources before starting a new benchmark run.
Error: creating docker manager: Cannot connect to the Docker daemon
Solutions:
- Ensure Docker daemon is running:
sudo systemctl start docker - Check socket permissions:
ls -la /var/run/docker.sock - Add user to docker group:
sudo usermod -aG docker $USER
Error: pulling image: pull access denied
Solutions:
- Check image name is correct
- Login to registry if private:
docker login - Check network connectivity
- Try
pull_policy: neverif image exists locally
Error: starting container: OCI runtime error
Solutions:
- Check container logs:
docker logs benchmarkoor-{runID}-{instanceID} - Verify resource limits are within system capacity
- Check if ports are already in use
- Ensure sufficient disk space
Error: container not connected to network
Solutions:
- Remove and recreate network:
docker network rm benchmarkoor - Check for network conflicts:
docker network ls - Enable
cleanup_on_start: truein config
Error: cpuset_count (16) exceeds available CPUs (8)
Solutions:
- Reduce
cpuset_countto available CPU count - Use
cpusetwith specific valid CPU IDs - Check available CPUs:
nprocorlscpu
Error: failed to create shim: mount failed
Solutions:
- Ensure source directory exists and is readable
- Check SELinux/AppArmor policies
- For overlayfs: ensure running as root or with proper permissions
- For bind mounts: verify absolute paths are used