Running the Elastic Distribution of OpenTelemetry (EDOT) Collector in Docker gives observability engineers a disposable collector for checking receiver, processor, and exporter behavior before changing a shared host, gateway, or Kubernetes rollout. The Docker run uses Elastic's elastic-agent image in OpenTelemetry mode and a mounted Collector configuration file, so the test stays close to the supported EDOT packaging without installing a host service.
Elastic's Docker quickstart runs EDOT through the elastic/elastic-agent container image with ELASTIC_AGENT_OTEL=true and a mounted Collector config. For a local smoke test, the Collector listens on OTLP/HTTP port 4318 and sends received traces to the debug exporter instead of using Elastic credentials or a production endpoint.
Use the debug exporter only for a short validation run because detailed output can include service names, attributes, request paths, and other telemetry content. Replace the exporter with the Elastic output path after the local receiver and mounted config behavior are proven, and publish only the listener ports that real clients need.
receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 processors: batch: exporters: debug: verbosity: detailed service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [debug]
The debug exporter prints received telemetry to container logs. Use verbosity: basic when detailed span attributes should not be printed.
Tool: OpenTelemetry Collector Config Generator
$ docker run --detach --name edot-collector \ --publish 127.0.0.1:4318:4318 \ --env ELASTIC_AGENT_OTEL=true \ --volume "$PWD/otelcol.yml:/etc/otelcol-config.yml:ro" \ elastic/elastic-agent:9.4.2 \ --config /etc/otelcol-config.yml 7b49d38512289eacf6a0d1ef6de4738c1fd93ac2497aee1b8b9f5b0b7de49f64
The 127.0.0.1 host bind keeps the OTLP listener local to the Docker host. Use a broader host bind only when network clients must reach this collector and firewall rules already limit access.
$ docker logs edot-collector
Starting elastic-otel-collector... {"Version": "9.4.2"}
Starting HTTP server {"otelcol.component.id": "otlp", "endpoint": "[::]:4318"}
Everything is ready. Begin running and processing data.
The Collector log shows the listener inside the container as [::]:4318. Docker still restricts host-side access to 127.0.0.1 because of the published port mapping.
{
"resourceSpans": [
{
"resource": {
"attributes": [
{
"key": "service.name",
"value": {
"stringValue": "edot-docker-demo"
}
}
]
},
"scopeSpans": [
{
"scope": {
"name": "manual-smoke-test"
},
"spans": [
{
"traceId": "0af7651916cd43dd8448eb211c80319c",
"spanId": "b7ad6b7169203331",
"name": "docker-smoke-test",
"kind": 1,
"startTimeUnixNano": "1718179200000000000",
"endTimeUnixNano": "1718179201000000000",
"attributes": [
{
"key": "http.method",
"value": {
"stringValue": "GET"
}
}
]
}
]
}
]
}
]
}
The payload uses neutral service and span names so the debug exporter output can be copied into a ticket or runbook without exposing application identifiers.
$ curl --silent --show-error \
--output otlp-response.json \
--write-out "%{http_code}\n" \
--header "Content-Type: application/json" \
--data @otlp-trace.json \
http://localhost:4318/v1/traces
200
A 200 response confirms that the receiver accepted the OTLP/HTTP request. It does not prove export to Elastic because this local config uses the debug exporter.
$ docker logs edot-collector
##### snipped #####
Traces {"otelcol.component.id": "debug", "otelcol.signal": "traces", "resource spans": 1, "spans": 1}
Resource attributes:
-> service.name: Str(edot-docker-demo)
InstrumentationScope manual-smoke-test
Span #0
Trace ID : 0af7651916cd43dd8448eb211c80319c
ID : b7ad6b7169203331
Name : docker-smoke-test
Kind : Internal
Attributes:
-> http.method: Str(GET)
The trace fields in the debug exporter output prove that Docker port publishing, the mounted config file, the OTLP receiver, and the traces pipeline are all active.
$ docker rm --force edot-collector edot-collector