Skip to content
Containly

Prometheus and Grafana

Since Containly 2.7.3 Containly exposes /metrics for Prometheus: endpoint up, host CPU, memory and disk, container state, health, restarts, CPU and memory. Free, off by default, protected by a metrics token. Scrape config, metric list and Grafana queries.

Containly 2.7.3 can export its host and container metrics in the Prometheus text format. One scrape covers every host Containly manages. It is Free and off by default.

Switch it on

  1. As an admin open Settings > Integrations.
  2. Switch on Prometheus export. Leave Require an API token on (recommended).
  3. Open Profile > API tokens, create a token with the permission Prometheus metrics (and nothing else) and copy it.
  4. Copy the scrape config from the card into your prometheus.yml and put the token into the file named in credentials_file.
scrape_configs:
  - job_name: containly
    scrape_interval: 60s
    scheme: https
    metrics_path: /metrics
    authorization:
      type: Bearer
      credentials_file: /etc/prometheus/containly.token
    static_configs:
      - targets: ['containly.example.com']

Containly samples once per minute, so scrape_interval: 60s is enough; shorter intervals simply return the same values (a scrape never asks Docker, it reads Containly's cache).

Check it by hand:

curl -H "Authorization: Bearer $TOKEN" https://containly.example.com/metrics

Without the export switched on /metrics answers 404, without a token 401, with a token lacking the metrics permission 403. Only if /metrics can be reached from a trusted network alone, you may switch off Require an API token: then anyone who reaches Containly can read container names and resource usage.

Metrics

Labels: endpoint (host name in Containly), stack (Compose project, empty for standalone containers), container (name), image (reference without digest). No container IDs, so recreating a container does not create new series; at most 500 containers per host are listed.

MetricMeaning
containly_info{version,edition}Version and edition (free or pro)
containly_endpoint_up{endpoint}1 when the host is reachable
containly_host_cpu_percentHost CPU usage in percent
containly_host_memory_used_bytes, containly_host_memory_total_bytesHost memory
containly_host_disk_used_bytes, containly_host_disk_total_bytesDocker data disk
containly_host_sample_timestamp_secondsTime of the last host sample
containly_containers{endpoint,state}Number of containers per state
containly_container_state{...,state}1 for the current state (running, exited, restarting, paused, created, dead)
containly_container_health{...,health}1 for healthy, unhealthy, starting or none (no health check)
containly_container_restartsDocker restart count (starts again at 0 when the container is recreated)
containly_container_cpu_percentCPU of a running container in percent of one CPU
containly_container_memory_bytesMemory of a running container
containly_containers_dropped{endpoint}Containers left out above 500 per host

Grafana

Add Prometheus as a data source, then build panels with these queries:

  • Hosts down: containly_endpoint_up == 0
  • Host CPU: containly_host_cpu_percent
  • Host memory in percent: 100 * containly_host_memory_used_bytes / containly_host_memory_total_bytes
  • Disk in percent: 100 * containly_host_disk_used_bytes / containly_host_disk_total_bytes
  • Unhealthy containers: containly_container_health{health="unhealthy"} == 1
  • Not running: containly_container_state{state!="running"} == 1
  • Top CPU: topk(10, containly_container_cpu_percent)
  • Memory per stack: sum by (endpoint, stack) (containly_container_memory_bytes)
  • Restarts in the last hour: delta(containly_container_restarts[1h]) > 0

An alert rule example:

groups:
  - name: containly
    rules:
      - alert: ContainerUnhealthy
        expr: containly_container_health{health="unhealthy"} == 1
        for: 5m
        labels: {severity: warning}
        annotations:
          summary: "{{ $labels.container }} on {{ $labels.endpoint }} is unhealthy"

Privacy

The export is inbound only: Prometheus connects to Containly, Containly sends nothing anywhere. In the public demo the export is shown switched off.