Skip to content

Docker

The OpenSearch Observability Stack runs as a Docker Compose project and uses the OpenTelemetry Collector to gather container metrics and logs. You can use the same approach to monitor your own Docker-based applications alongside the stack.

graph LR
    subgraph Docker Host
        C1[App Container 1]
        C2[App Container 2]
        DS[Docker Socket]
        OC[OTel Collector]
    end

    C1 -->|stdout/stderr| OC
    C2 -->|stdout/stderr| OC
    DS -->|container stats| OC
    OC -->|traces, logs| DP[Data Prepper]
    OC -->|metrics| P[Prometheus]
    DP --> OS[OpenSearch]
  • Docker Engine 20.10 or later
  • Docker Compose v2
  • A running OpenSearch Observability Stack instance

The Observability Stack runs the following core services:

ServicePortDescription
opensearch9200Search and analytics engine
opensearch-dashboards5601Visualization and dashboards UI
otel-collector4317, 4318, 8888OpenTelemetry Collector (gRPC, HTTP, metrics)
data-prepper21890Trace and log ingestion pipeline
prometheus9090Metrics scraping and storage

The OTel Collector uses the Docker Stats receiver to collect container-level metrics from the Docker daemon.

Add the following to your OTel Collector configuration:

receivers:
docker_stats:
endpoint: unix:///var/run/docker.sock
collection_interval: 10s
timeout: 20s
api_version: 1.24
metrics:
container.cpu.usage.total:
enabled: true
container.memory.usage.total:
enabled: true
container.memory.usage.limit:
enabled: true
container.network.io.usage.rx_bytes:
enabled: true
container.network.io.usage.tx_bytes:
enabled: true
container.blockio.io_service_bytes_recursive.read:
enabled: true
container.blockio.io_service_bytes_recursive.write:
enabled: true

In your docker-compose.yml, mount the Docker socket into the OTel Collector container:

services:
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
ports:
- "4317:4317"
- "4318:4318"
- "8888:8888"

The Docker Stats receiver exports the following key metrics:

MetricTypeDescription
container.cpu.usage.totalcumulativeTotal CPU time consumed
container.cpu.percentgaugeCPU usage percentage
container.memory.usage.totalgaugeCurrent memory usage in bytes
container.memory.usage.limitgaugeMemory limit in bytes
container.memory.percentgaugeMemory usage percentage
container.network.io.usage.rx_bytescumulativeBytes received
container.network.io.usage.tx_bytescumulativeBytes transmitted
container.blockio.io_service_bytes_recursive.readcumulativeBytes read from disk
container.blockio.io_service_bytes_recursive.writecumulativeBytes written to disk

Use the Filelog receiver to tail container log files from the Docker log directory:

receivers:
filelog/docker:
include:
- /var/lib/docker/containers/*/*.log
include_file_path: true
operators:
- type: json_parser
id: docker_parser
timestamp:
parse_from: attributes.time
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
- type: move
from: attributes.log
to: body
- type: move
from: attributes.stream
to: attributes["log.iostream"]

Mount the Docker log directory into the collector:

services:
otel-collector:
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro

To monitor your own application alongside the Observability Stack, add it to the same Docker Compose file or use a shared network:

services:
my-app:
image: my-app:latest
environment:
OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4318
OTEL_SERVICE_NAME: my-app
OTEL_RESOURCE_ATTRIBUTES: deployment.environment.name=development
networks:
- observability
networks:
observability:
external: true

If your application runs in a separate Compose file, create an external network and connect both projects:

Terminal window
# Create a shared network
docker network create observability
# Start the Observability Stack
docker compose -f observability-stack/docker-compose.yml up -d
# Start your application
docker compose -f my-app/docker-compose.yml up -d

A complete OTel Collector config that collects Docker metrics and logs, then routes them to the appropriate backends:

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
docker_stats:
endpoint: unix:///var/run/docker.sock
collection_interval: 10s
filelog/docker:
include:
- /var/lib/docker/containers/*/*.log
operators:
- type: json_parser
timestamp:
parse_from: attributes.time
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
processors:
batch:
timeout: 5s
send_batch_size: 1024
resourcedetection:
detectors: [docker]
timeout: 5s
exporters:
otlphttp/data-prepper:
endpoint: http://data-prepper:21890
otlphttp/prometheus:
endpoint: http://prometheus:9090/api/v1/otlp
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, resourcedetection]
exporters: [otlphttp/data-prepper]
metrics:
receivers: [otlp, docker_stats]
processors: [batch, resourcedetection]
exporters: [otlphttp/prometheus]
logs:
receivers: [otlp, filelog/docker]
processors: [batch, resourcedetection]
exporters: [otlphttp/data-prepper]
  1. Check that the OTel Collector is receiving Docker stats:
Terminal window
curl -s http://localhost:8888/metrics | grep container_cpu
  1. Verify metrics in Prometheus:
Terminal window
curl -s http://localhost:9090/api/v1/query?query=container_memory_usage_total | jq .
  1. Check logs in OpenSearch Dashboards at http://localhost:5601.