
# Docker by Zabbix agent 2

## Overview

The template to monitor Docker engine by Zabbix that work without any external scripts.
Most of the metrics are collected in one go, thanks to Zabbix bulk data collection.

Template `Docker by Zabbix agent 2` — collects metrics by polling zabbix-agent2.

## Requirements

Zabbix version: 7.0 and higher.

## Tested versions

This template has been tested on:
- Docker 23.0.3

## Configuration

> Zabbix should be configured according to the instructions in the [Templates out of the box](https://www.zabbix.com/documentation/7.0/manual/config/templates_out_of_the_box) section.

## Setup

Setup and configure Zabbix agent 2 compiled with the Docker monitoring plugin. The user by which the Zabbix agent 2 is running should have access permissions to the Docker socket.

Test availability: `zabbix_get -s docker-host -k docker.info`

### Macros used

|Name|Description|Default|
|----|-----------|-------|
|{$DOCKER.LLD.FILTER.CONTAINER.MATCHES}|
Filter of discoverable containers.
|`.*`|
|{$DOCKER.LLD.FILTER.CONTAINER.NOT_MATCHES}|
Filter to exclude discovered containers.
|`CHANGE_IF_NEEDED`|
|{$DOCKER.LLD.FILTER.IMAGE.MATCHES}|
Filter of discoverable images.
|`.*`|
|{$DOCKER.LLD.FILTER.IMAGE.NOT_MATCHES}|
Filter to exclude discovered images.
|`CHANGE_IF_NEEDED`|

### Items

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Ping||Zabbix agent|docker.ping
**Preprocessing**

- 
Discard unchanged with heartbeat: `10m`

|
|Get info||Zabbix agent|docker.info|
|Get containers||Zabbix agent|docker.containers|
|Get images||Zabbix agent|docker.images|
|Get data_usage||Zabbix agent|docker.data_usage|
|Containers total|
Total number of containers on this host.
|Dependent item|docker.containers.total
**Preprocessing**

- 
JSON Path: `$.Containers`

|
|Containers running|
Total number of containers running on this host.
|Dependent item|docker.containers.running
**Preprocessing**

- 
JSON Path: `$.ContainersRunning`

|
|Containers stopped|
Total number of containers stopped on this host.
|Dependent item|docker.containers.stopped
**Preprocessing**

- 
JSON Path: `$.ContainersStopped`

|
|Containers paused|
Total number of containers paused on this host.
|Dependent item|docker.containers.paused
**Preprocessing**

- 
JSON Path: `$.ContainersPaused`

|
|Images total|
Number of images with intermediate image layers.
|Dependent item|docker.images.total
**Preprocessing**

- 
JSON Path: `$.Images`

|
|Storage driver|
Docker storage driver.

https://docs.docker.com/storage/storagedriver/
|Dependent item|docker.driver
**Preprocessing**

- 
JSON Path: `$.Driver`

- 
Discard unchanged with heartbeat: `1d`

|
|Memory limit enabled||Dependent item|docker.mem_limit.enabled
**Preprocessing**

- 
JSON Path: `$.MemoryLimit`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Swap limit enabled||Dependent item|docker.swap_limit.enabled
**Preprocessing**

- 
JSON Path: `$.SwapLimit`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Kernel memory enabled||Dependent item|docker.kernel_mem.enabled
**Preprocessing**

- 
JSON Path: `$.KernelMemory`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Kernel memory TCP enabled||Dependent item|docker.kernel_mem_tcp.enabled
**Preprocessing**

- 
JSON Path: `$.KernelMemoryTCP`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|CPU CFS Period enabled|
https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
|Dependent item|docker.cpu_cfs_period.enabled
**Preprocessing**

- 
JSON Path: `$.CpuCfsPeriod`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|CPU CFS Quota enabled|
https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
|Dependent item|docker.cpu_cfs_quota.enabled
**Preprocessing**

- 
JSON Path: `$.CpuCfsQuota`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|CPU Shares enabled|
https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
|Dependent item|docker.cpu_shares.enabled
**Preprocessing**

- 
JSON Path: `$.CPUShares`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|CPU Set enabled|
https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
|Dependent item|docker.cpu_set.enabled
**Preprocessing**

- 
JSON Path: `$.CPUSet`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Pids limit enabled||Dependent item|docker.pids_limit.enabled
**Preprocessing**

- 
JSON Path: `$.PidsLimit`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|IPv4 Forwarding enabled||Dependent item|docker.ipv4_forwarding.enabled
**Preprocessing**

- 
JSON Path: `$.IPv4Forwarding`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Debug enabled||Dependent item|docker.debug.enabled
**Preprocessing**

- 
JSON Path: `$.Debug`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Nfd|
Number of used File Descriptors.
|Dependent item|docker.nfd
**Preprocessing**

- 
JSON Path: `$.NFd`

|
|OomKill disabled||Dependent item|docker.oomkill.disabled
**Preprocessing**

- 
JSON Path: `$.OomKillDisable`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Goroutines|
Number of goroutines.
|Dependent item|docker.goroutines
**Preprocessing**

- 
JSON Path: `$.NGoroutines`

|
|Logging driver||Dependent item|docker.logging_driver
**Preprocessing**

- 
JSON Path: `$.LoggingDriver`

- 
Discard unchanged with heartbeat: `1d`

|
|Cgroup driver||Dependent item|docker.cgroup_driver
**Preprocessing**

- 
JSON Path: `$.CgroupDriver`

- 
Discard unchanged with heartbeat: `1d`

|
|NEvents listener||Dependent item|docker.nevents_listener
**Preprocessing**

- 
JSON Path: `$.NEventsListener`

|
|Kernel version||Dependent item|docker.kernel_version
**Preprocessing**

- 
JSON Path: `$.KernelVersion`

- 
Discard unchanged with heartbeat: `1d`

|
|Operating system||Dependent item|docker.operating_system
**Preprocessing**

- 
JSON Path: `$.OperatingSystem`

- 
Discard unchanged with heartbeat: `1d`

|
|OS type||Dependent item|docker.os_type
**Preprocessing**

- 
JSON Path: `$.OSType`

- 
Discard unchanged with heartbeat: `1d`

|
|Architecture||Dependent item|docker.architecture
**Preprocessing**

- 
JSON Path: `$.Architecture`

- 
Discard unchanged with heartbeat: `1d`

|
|NCPU||Dependent item|docker.ncpu
**Preprocessing**

- 
JSON Path: `$.NCPU`

|
|Memory total||Dependent item|docker.mem.total
**Preprocessing**

- 
JSON Path: `$.MemTotal`

|
|Docker root dir||Dependent item|docker.root_dir
**Preprocessing**

- 
JSON Path: `$.DockerRootDir`

- 
Discard unchanged with heartbeat: `1d`

|
|Name||Dependent item|docker.name
**Preprocessing**

- 
JSON Path: `$.Name`

|
|Server version||Dependent item|docker.server_version
**Preprocessing**

- 
JSON Path: `$.ServerVersion`

- 
Discard unchanged with heartbeat: `1d`

|
|Default runtime||Dependent item|docker.default_runtime
**Preprocessing**

- 
JSON Path: `$.DefaultRuntime`

- 
Discard unchanged with heartbeat: `1d`

|
|Live restore enabled||Dependent item|docker.live_restore.enabled
**Preprocessing**

- 
JSON Path: `$.LiveRestoreEnabled`

- Boolean to decimal
- 
Discard unchanged with heartbeat: `1d`

|
|Layers size||Dependent item|docker.layers_size
**Preprocessing**

- 
JSON Path: `$.LayersSize`

|
|Images size||Dependent item|docker.images_size
**Preprocessing**

- 
JSON Path: `$.Images[*].Size.sum()`

|
|Containers size||Dependent item|docker.containers_size
**Preprocessing**

- 
JSON Path: `$.Containers[*].SizeRw.sum()`

|
|Volumes size||Dependent item|docker.volumes_size
**Preprocessing**

- 
JSON Path: `$.Volumes[*].UsageData.Size.sum()`

|
|Images available|
Number of top-level images.
|Dependent item|docker.images.top_level
**Preprocessing**

- 
JSON Path: `$.length()`

|

### Triggers

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|Docker: Service is down||`last(/Docker by Zabbix agent 2/docker.ping)=0`|Average|**Manual close**: Yes|
|Docker: Failed to fetch info data|
Zabbix has not received data for items for the last 30 minutes.
|`nodata(/Docker by Zabbix agent 2/docker.name,30m)=1`|Warning|**Manual close**: Yes
**Depends on**:

- Docker: Service is down
|
|Docker: Version has changed|
Docker version has changed. Acknowledge to close the problem manually.
|`last(/Docker by Zabbix agent 2/docker.server_version,#1)<>last(/Docker by Zabbix agent 2/docker.server_version,#2) and length(last(/Docker by Zabbix agent 2/docker.server_version))>0`|Info|**Manual close**: Yes|

### LLD rule Images discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Images discovery|
Discovery of images metrics.
|Zabbix agent|docker.images.discovery|

### Item prototypes for Images discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Image {#NAME}: Created||Dependent item|docker.image.created["{#ID}"]
**Preprocessing**

- 
JSON Path: `$[?(@.Id == "{#ID}")].Created.first()`

- 
Discard unchanged with heartbeat: `1d`

|
|Image {#NAME}: Size||Dependent item|docker.image.size["{#ID}"]
**Preprocessing**

- 
JSON Path: `$[?(@.Id == "{#ID}")].Size.first()`

|

### LLD rule Containers discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Containers discovery|
Discovery of containers metrics.

Parameter:

true  - Returns all containers

false - Returns only running containers
|Zabbix agent|docker.containers.discovery[false]|

### Item prototypes for Containers discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Container {#NAME}: Get stats|
Get container stats based on resource usage.
|Zabbix agent|docker.container_stats["{#NAME}"]|
|Container {#NAME}: CPU total usage per second||Dependent item|docker.container_stats.cpu_usage.total.rate["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.cpu_usage.total_usage`

- Change per second
- 
Custom multiplier: `1.0E-9`

|
|Container {#NAME}: CPU percent usage||Dependent item|docker.container_stats.cpu_pct_usage["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.cpu_usage.percent_usage`

|
|Container {#NAME}: CPU kernelmode usage per second||Dependent item|docker.container_stats.cpu_usage.kernel.rate["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.cpu_usage.usage_in_kernelmode`

- Change per second
- 
Custom multiplier: `1.0E-9`

|
|Container {#NAME}: CPU usermode usage per second||Dependent item|docker.container_stats.cpu_usage.user.rate["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.cpu_usage.usage_in_usermode`

- Change per second
- 
Custom multiplier: `1.0E-9`

|
|Container {#NAME}: Online CPUs||Dependent item|docker.container_stats.online_cpus["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.online_cpus`

|
|Container {#NAME}: Throttling periods|
Number of periods with throttling active.
|Dependent item|docker.container_stats.cpu_usage.throttling_periods["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.throttling_data.periods`

|
|Container {#NAME}: Throttled periods|
Number of periods when the container hits its throttling limit.
|Dependent item|docker.container_stats.cpu_usage.throttled_periods["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.throttling_data.throttled_periods`

|
|Container {#NAME}: Throttled time|
Aggregate time the container was throttled for in nanoseconds.
|Dependent item|docker.container_stats.cpu_usage.throttled_time["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.cpu_stats.throttling_data.throttled_time`

- 
Custom multiplier: `1.0E-9`

|
|Container {#NAME}: Memory usage||Dependent item|docker.container_stats.memory.usage["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.memory_stats.usage`

|
|Container {#NAME}: Memory maximum usage||Dependent item|docker.container_stats.memory.max_usage["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.memory_stats.max_usage`

|
|Container {#NAME}: Memory commit bytes||Dependent item|docker.container_stats.memory.commit_bytes["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.memory_stats.commitbytes`

|
|Container {#NAME}: Memory commit peak bytes||Dependent item|docker.container_stats.memory.commit_peak_bytes["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.memory_stats.commitpeakbytes`

|
|Container {#NAME}: Memory private working set||Dependent item|docker.container_stats.memory.private_working_set["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.memory_stats.privateworkingset`

|
|Container {#NAME}: Current PIDs count|
Current number of PIDs the container has created.
|Dependent item|docker.container_stats.pids_stats.current["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.pids_stats.current`

|
|Container {#NAME}: Networks bytes received per second||Dependent item|docker.networks.rx_bytes["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].rx_bytes.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks packets received per second||Dependent item|docker.networks.rx_packets["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].rx_packets.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks errors received per second||Dependent item|docker.networks.rx_errors["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].rx_errors.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks incoming packets dropped per second||Dependent item|docker.networks.rx_dropped["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].rx_dropped.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks bytes sent per second||Dependent item|docker.networks.tx_bytes["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].tx_bytes.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks packets sent per second||Dependent item|docker.networks.tx_packets["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].tx_packets.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks errors sent per second||Dependent item|docker.networks.tx_errors["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].tx_errors.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Networks outgoing packets dropped per second||Dependent item|docker.networks.tx_dropped["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.networks[*].tx_dropped.sum()`

⛔️Custom on fail: Set value to: `0`

- Change per second
|
|Container {#NAME}: Get info|
Return low-level information about a container.
|Zabbix agent|docker.container_info["{#NAME}",full]|
|Container {#NAME}: Created||Dependent item|docker.container_info.created["{#NAME}"]
**Preprocessing**

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1d`

|
|Container {#NAME}: Image||Dependent item|docker.container_info.image["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$[?(@.Names[0] == "{#NAME}")].Image.first()`

- 
Discard unchanged with heartbeat: `1d`

|
|Container {#NAME}: Restart count||Dependent item|docker.container_info.restart_count["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.RestartCount`

|
|Container {#NAME}: Status||Dependent item|docker.container_info.state.status["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Status`

- 
Discard unchanged with heartbeat: `1h`

|
|Container {#NAME}: Health status|
Container's `HEALTHCHECK`.
|Dependent item|docker.container_info.state.health["{#NAME}"]
**Preprocessing**

- 
JavaScript: `The text is too long. Please see the template.`

- 
In range: `1 -> 4`

⛔️Custom on fail: Set value to: `4`

|
|Container {#NAME}: Health failing streak||Dependent item|docker.container_info.state.health.failing["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Health.FailingStreak`

⛔️Custom on fail: Discard value

- 
Discard unchanged with heartbeat: `1h`

|
|Container {#NAME}: Running||Dependent item|docker.container_info.state.running["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Running`

- Boolean to decimal
|
|Container {#NAME}: Paused||Dependent item|docker.container_info.state.paused["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Paused`

- Boolean to decimal
|
|Container {#NAME}: Restarting||Dependent item|docker.container_info.state.restarting["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Restarting`

- Boolean to decimal
|
|Container {#NAME}: OOMKilled||Dependent item|docker.container_info.state.oomkilled["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.OOMKilled`

- Boolean to decimal
|
|Container {#NAME}: Dead||Dependent item|docker.container_info.state.dead["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Dead`

- Boolean to decimal
|
|Container {#NAME}: Pid||Dependent item|docker.container_info.state.pid["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Pid`

- 
Discard unchanged with heartbeat: `1d`

|
|Container {#NAME}: Exit code||Dependent item|docker.container_info.state.exitcode["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.ExitCode`

- 
Discard unchanged with heartbeat: `1d`

|
|Container {#NAME}: Error||Dependent item|docker.container_info.state.error["{#NAME}"]
**Preprocessing**

- 
JSON Path: `$.State.Error`

- 
Discard unchanged with heartbeat: `1d`

|
|Container {#NAME}: Started at||Dependent item|docker.container_info.started["{#NAME}"]
**Preprocessing**

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1d`

|
|Container {#NAME}: Finished at|
Time at which the container last terminated.
|Dependent item|docker.container_info.finished["{#NAME}"]
**Preprocessing**

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1d`

|

### Trigger prototypes for Containers discovery

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|Docker: Container {#NAME}: Health state container is unhealthy|
Container health state is unhealthy.
|`count(/Docker by Zabbix agent 2/docker.container_info.state.health["{#NAME}"],2m,,2)>=2`|High||
|Docker: Container {#NAME}: Container has been stopped with error code||`last(/Docker by Zabbix agent 2/docker.container_info.state.exitcode["{#NAME}"])>0 and last(/Docker by Zabbix agent 2/docker.container_info.state.running["{#NAME}"])=0`|Average|**Manual close**: Yes|
|Docker: Container {#NAME}: An error has occurred in the container|
Container {#NAME} has an error. Acknowledge to close the problem manually.
|`last(/Docker by Zabbix agent 2/docker.container_info.state.error["{#NAME}"],#1)<>last(/Docker by Zabbix agent 2/docker.container_info.state.error["{#NAME}"],#2) and length(last(/Docker by Zabbix agent 2/docker.container_info.state.error["{#NAME}"]))>0`|Warning|**Manual close**: Yes|

## Feedback

Please report any issues with the template at [`https://support.zabbix.com`](https://support.zabbix.com)

You can also provide feedback, discuss the template, or ask for help at [`ZABBIX forums`](https://www.zabbix.com/forum/zabbix-suggestions-and-feedback)

