Prometheus can scrape metrics from containerd, but it’s not a built-in feature of containerd itself. You need a separate component to expose containerd’s internal metrics in a Prometheus-compatible format.

Let’s see how this actually works. Imagine you have a container running, and you want to monitor its CPU usage, memory, network traffic, and disk I/O. Containerd, as the container runtime, is tracking all this information. However, it doesn’t expose it directly for Prometheus to pull.

Here’s a basic setup:

  1. Containerd: Running your containers.
  2. containerd-exporter (or similar): A small, dedicated service that queries containerd’s API for metrics and exposes them on an HTTP endpoint (e.g., /metrics).
  3. Prometheus: Configured to scrape the /metrics endpoint of the containerd-exporter.

Here’s a simplified example of a containerd-exporter configuration and how Prometheus would scrape it.

containerd-exporter Configuration (example config.yaml):

listen-address: "0.0.0.0:9321" # The address the exporter will listen on
metrics-path: "/metrics"      # The HTTP path for metrics
containerd-address: "/run/containerd/containerd.sock" # Path to containerd's Unix socket

Prometheus Configuration (prometheus.yml):

scrape_configs:
  - job_name: 'containerd'
    static_configs:
      - targets: ['localhost:9321'] # Assuming exporter runs on the same host

Once set up, Prometheus will periodically send HTTP GET requests to http://localhost:9321/metrics. The containerd-exporter will then query containerd for metrics like container_cpu_usage_seconds_total, container_memory_working_set_bytes, and expose them.

The core problem this solves is bridging the gap between containerd’s internal state and Prometheus’s pull-based monitoring model. Containerd manages containers, but it doesn’t speak Prometheus. The exporter acts as a translator.

Internally, the containerd-exporter likely uses containerd’s GRPC API to subscribe to events or periodically poll for container stats. For instance, it might call containerd.services.tasks.v1.Tasks.ListTasks and then containerd.services.tasks.v1.Tasks.Stats for each running task. The collected data is then formatted into Prometheus exposition format.

The exact metrics available depend on the exporter you choose. Common ones include:

  • container_cpu_usage_seconds_total: Cumulative CPU time spent by a container.
  • container_memory_working_set_bytes: Current memory usage of a container.
  • container_network_receive_bytes_total: Total bytes received by a container’s network interfaces.
  • container_network_transmit_bytes_total: Total bytes transmitted by a container’s network interfaces.
  • container_fs_usage_bytes: Disk usage by a container’s filesystem.

You control the scraping frequency and which jobs Prometheus monitors via the prometheus.yml configuration. The exporter itself typically has minimal configuration, often just pointing to the containerd socket and the desired listen address.

The most surprising thing is that containerd doesn’t have a native, built-in Prometheus exporter. You’re almost always relying on a third-party project like containerd-exporter or prom/node-exporter with its containerd collector enabled, which means you have an extra component to manage and ensure is running correctly.

To effectively use these metrics, you’ll want to explore dashboarding solutions like Grafana, which can query Prometheus and visualize these container-specific metrics, allowing you to build dashboards for resource utilization, performance, and potential issues.

Want structured learning?

Take the full Containerd course →