Bedrock API is an HTTP service that coordinates Bedrock tracing workloads through REST APIs and internal event-driven communication.
It is responsible for:
- session lifecycle management
- distributed container orchestration through daemons
- trace log collection
- centralized state management
The system consists of four main components.
- API Server
- Docker Daemon
- File Manager Daemon
- Key-Value Storage
The API is the central coordinator of the platform.
Responsibilities:
- exposes RESTful endpoints
- owns the system state
- manages session lifecycle
- stores session metadata in key-value storage
- assigns DockerD workers using round-robin scheduling
API is the only component allowed to directly access persistent KV storage.
DockerD interacts with the host Docker daemon to execute tracing workloads.
Responsibilities:
- polls API through ZMQ
- receives sessions
- creates target containers
- creates tracer containers
- manages Docker volumes
- tracks container execution state
- reports state changes back to API
DockerD maps resources using a session-id.
FileMD transfers trace artifacts from DockerD hosts back to the API host.
Responsibilities:
- monitors Docker volumes
- waits until volumes are unlocked
- uploads trace logs
- removes uploaded artifacts
Persistent storage used by API for system state.
Stores:
- sessions
- status
- API receives a session creation/update requests
- API assigns a DockerD to new sessions
- API stores sessions in KV storage
- DockerD pulls its sessions through ZMQ using a unique id
- DockerD starts containers
- DockerD reports updates during pulls
- FileMD monitors the tracing volumes
- FileMD uploads logs after completion
- API updates the states using DockerD data
flowchart TD
Client[Client Request] --> API[Bedrock API]
API --> Scheduler
API --> KV[Key Value Storage]
DockerD[DockerD Node] <-->|ZMQ Events| API
DockerD --> DockerHost[Docker Host]
DockerHost --> Target[Target Container]
DockerHost --> Tracer[Tracer Container]
DockerHost --> Volume[Trace Volume]
FileMD[FileMD] --> Volume
FileMD --> API
API --> Client
DockerD periodically contacts API through ZMQ.
It sends:
- current running sessions
- local container status
API compares:
- DockerD reported state
- persisted KV state
Then API responds with:
- sessions of that DockerD instance
DockerD receives:
- container image
- command
- timeout (TTL)
Then DockerD:
- creates a volume
- locks the volume
- starts target container
- starts tracer container
- monitors lifecycle
A session can terminate because:
- timeout reached
- container exited normally
- container failed
- API requested stop
Cleanup phase:
- remove containers
- unlock volume
After unlock:
- FileMD uploads logs
- FileMD deletes local artifacts
Session
├── UUID
├── Request
│ ├── Docker Image
│ ├── Command
│ └── Timeout
├── Status
├── Created At
└── DockerD ID
- Pending: a session that is not sent to DockerD yet
- Running: a session that is sent to its DockerD
- Stopped: a session that is aborted by user
- Finished: a session that is done (container exit/timeout hit)
- Failed: a session that is failed (container exit with non zero)
stateDiagram-v2
[*] --> Pending
Pending --> Running : DockerD Create Success
Pending --> Failed : DockerD Create Failure
Pending --> Stopped : API Stop Request
Running --> Finished : Container Exit
Running --> Failed : Runtime Failure
Running --> Stopped : API Stop Request
POST /api/sessionsCreates:
- new session and assigns a DockerD
Request body (application/json):
{
"image": "<docker-image>",
"command": "<command-to-run>",
"ttl": "<duration> (e.g., 10s, 6m, 1h)"
}Fields:
- image (string) - Docker image to run (e.g. "nginx:stable").
- command (string) - space-separated command string that will be split on spaces and passed to the container as an argv list.
- ttl (string) - session time-to-live in duration; DockerD will stop the session after this duration if it hasn't finished.
Example: start a short-lived nginx session
{
"image": "nginx:stable",
"command": "nginx -g 'daemon off;'",
"ttl": "24h"
}Example curl (create session):
curl -X POST http://localhost:8080/api/sessions \
-H "Content-Type: application/json" \
-d "{
\"image\": \"nginx:latest\",
\"command\": \"nginx -g 'daemon off;'\",
\"ttl\": \"24h\"
}"PUT /api/sessions/:idCreates:
- patch event for DockerD
Request body (application/json):
{ "status": "<status>" }Notes:
- Only the
statusfield is read by the API for updates. Valid status values are:pending,running,stopped,finished,failed. - The server enforces a state-machine when applying status changes; invalid transitions will return HTTP 400.
Example: stop a running session
{ "status": "stopped" }Example curl (stop session):
curl -X PUT http://localhost:8080/api/sessions/<session-id> \
-H "Content-Type: application/json" \
-d '{"status":"stopped"}'GET /api/sessionsReturns all sessions from KV storage.
Request body: none
Response (application/json): array of Session objects. Each Session has the shape:
[
{
"id": "<uuid>",
"created_at": "<timestamp>",
"status": "<status>",
"image": "<docker-image>",
"command": "<command-string>",
"ttl": "<duration>"
}
]Example curl (list sessions):
curl -X GET http://localhost:8080/api/sessionsGET /api/sessions/:id/logsReturns session tracing logs.
Example curl (get session logs):
curl -X GET http://localhost:8080/api/sessions/<session-id>/logsPOST /api/sessions/:id/logsUploads session tracing logs. This endpoint is expected to be used by the FileMD service to accept file uploads (multipart/form-data) containing the logs/artifacts for the session.
Example curl (upload session logs):
curl -X POST http://localhost:8080/api/sessions/<session-id>/logs \
-F "file=@/path/to/log.tar.gz"- Docker
- Go 1.25
- build-essential
- libzmq3-dev
- libczmq-dev
- libsodium-dev
- pkg-config
sudo apt update
sudo apt install build-essential libzmq3-dev libczmq-dev libsodium-dev pkg-config -ymake build
touch config.yaml
./bedrock api
./bedrock dockerd- GitHub repository: Bedrock Tracer https://github.com/amirhnajafiz/bedrock-tracer