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
- As an admin open Settings > Integrations.
- Switch on Prometheus export. Leave Require an API token on (recommended).
- Open Profile > API tokens, create a token with the permission Prometheus metrics (and nothing else) and copy it.
- Copy the scrape config from the card into your
prometheus.ymland put the token into the file named incredentials_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.
| Metric | Meaning |
|---|---|
containly_info{version,edition} | Version and edition (free or pro) |
containly_endpoint_up{endpoint} | 1 when the host is reachable |
containly_host_cpu_percent | Host CPU usage in percent |
containly_host_memory_used_bytes, containly_host_memory_total_bytes | Host memory |
containly_host_disk_used_bytes, containly_host_disk_total_bytes | Docker data disk |
containly_host_sample_timestamp_seconds | Time 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_restarts | Docker restart count (starts again at 0 when the container is recreated) |
containly_container_cpu_percent | CPU of a running container in percent of one CPU |
containly_container_memory_bytes | Memory 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.