src/go/plugin/go.d/discovery/sdext/discoverer/dockersd/README.md
Kind: docker
Netdata can automatically discover running Docker containers on the local Docker daemon and generate collector jobs for the services running inside them. The discoverer queries the Docker API on a fixed interval, builds one target per container port, and applies your services: rules to render collector job YAML — typically picking the right go.d module from the container image (nginx, postgres, redis, …).
This page covers Docker-specific setup. For the broader Service Discovery model and the shared template-helper reference, see Service Discovery.
Each discovery cycle, the discoverer:
ContainerList on the Docker API at the configured address.(container, network, port) triple for every container that has at least one network and at least one published port. Containers running in network: host mode are intentionally skipped — those are picked up by the net_listeners discoverer instead..Name, .Image, .Command, .Labels, .PrivatePort, .PublicPort, .PublicPortIP, .PortProtocol, .NetworkMode, .NetworkDriver, .IPAddress, .Address (the convenience IPAddress:PrivatePort).services: rules against each target. The default stock conf carries curated rules for ~40 popular images (nginx, postgres, redis, rabbitmq, etc.) keyed on .Image patterns.network: host mode are not produced as Docker targets. Configure the net_listeners discoverer to pick them up via the host's process table.-p mapping still produces a target via its private port and network IP.You can configure the docker discoverer in two ways:
| Method | Best for | How to |
|---|---|---|
| UI | Fast setup without editing files | Go to Collectors -> go.d -> ServiceDiscovery -> docker, then add a discovery pipeline. |
| File | File-based configuration or automation | Edit /etc/netdata/go.d/sd/docker.conf and define the discoverer: and services: blocks. |
The Netdata Agent must be able to reach the Docker daemon. The default address is unix:///var/run/docker.sock. If you run Netdata in a container, mount the socket: -v /var/run/docker.sock:/var/run/docker.sock:ro. The Netdata user (or the container) must have read access to the socket.
The stock conf at /etc/netdata/go.d/sd/docker.conf ships with disabled: no and a curated set of services: rules covering ~40 popular images. To turn discovery off, set disabled: yes at the top of the file.
The configuration file has two top-level blocks: discoverer: (the options below) and services: (rules that turn discovered containers into collector jobs — see Service Rules).
After editing the file, restart the Netdata Agent to load the updated discovery pipeline.
| Option | Description | Default | Required |
|---|---|---|---|
| address | Docker daemon address. | unix:///var/run/docker.sock | no |
| timeout | Maximum time to wait for a Docker API response (per request). | 2s | no |
<a id="option-address"></a>
Supports both Unix-socket (unix:///var/run/docker.sock) and TCP (tcp://hostname:2375) endpoints.
If unset, Netdata also honors the DOCKER_HOST environment variable when present.
Collectors -> go.d -> ServiceDiscovery -> docker.Define the discovery pipeline in /etc/netdata/go.d/sd/docker.conf.
The file has two top-level blocks: discoverer: (the options above) and services: (rules that turn discovered targets into collector jobs — see Service Rules).
After editing the file, restart the Netdata Agent to load the updated discovery pipeline.
Use the default local Docker socket and the stock services rules.
disabled: no
discoverer:
docker:
address: unix:///var/run/docker.sock
services:
# See the stock conf for the full curated rule set.
- id: skip
match: |
{{ or (eq .NetworkMode "host") (not (eq .PortProtocol "tcp")) (empty .PrivatePort) }}
- id: nginx
match: '{{ match "sp" .Image "nginx nginx:*" }}'
config_template: |
name: docker_{{.Name}}
url: http://{{.Address}}/stub_status
Point the discoverer at a remote Docker daemon. TLS is not yet wired into the discoverer; either expose the daemon on a trusted internal network or use a stunnel/socat proxy.
disabled: no
discoverer:
docker:
address: tcp://docker.internal:2375
timeout: 5s
services:
- id: skip
match: '{{ or (eq .NetworkMode "host") (not (eq .PortProtocol "tcp")) (empty .PrivatePort) }}'
- id: redis
match: '{{ match "sp" .Image "redis redis:* */redis */redis:*" }}'
config_template: |
name: docker_{{.Name}}
address: redis://@{{.Address}}
A services: rule turns each discovered container target into one or more collector jobs. Most rules match on .Image (using the match "sp" simple-pattern helper for the typical image image:* */image */image:* family), some also gate on .PrivatePort, and a few use .Labels to honor user intent.
The shared rule model — function reference (match, glob, sprig, toYaml), config_template rendering rules, and the missingkey=error failure semantics — lives on the Service Discovery hub page. The notes below are Docker-specific.
Quick reference — see Rule evaluation semantics on the hub page for the full model.
match "sp" — The simple-patterns matcher (match "sp" .Image "nginx nginx:* */nginx */nginx:*") is the idiomatic way to handle the four-form image family (bare, tagged, namespaced, namespaced-tagged). Use glob if you only need shell-style globbing without the simple-patterns engine.id: <module-name> (e.g. id: nginx) so the rendered job inherits the module name automatically. Use a different id only when you also include module: explicitly in the template.Available inside both match expressions and config_template bodies for Docker targets.
| Variable | Type | Description |
|---|---|---|
.Name | string | Container name (without the leading slash). |
.Image | string | Container image as reported by Docker (e.g. nginx:1.25, myorg/redis:6). |
.Command | string | Container command line. |
.Labels | map | All container labels. Use index .Labels "key" or hasKey .Labels "key" to read individual entries. |
.IPAddress | string | IP of the container on the matched network. |
.Address | string | Convenience IPAddress:PrivatePort — the canonical address used in most stock rule templates. |
.PrivatePort | string | Container-side port. |
.PublicPort | string | Host-side port (empty when the container does not publish a host mapping for this port). |
.PublicPortIP | string | Host IP that the container port is bound to (empty when no public mapping). |
.PortProtocol | string | Port protocol — tcp or udp. Stock rules typically gate on eq .PortProtocol "tcp". |
.NetworkMode | string | Container network mode (bridge, host, overlay, custom network names, …). The stock skip rule drops host mode. |
.NetworkDriver | string | Driver of the matched network. |
.ID | string | Container ID (full hex). |
Each example shows one or more entries from the services: array. Order matters — see How rules are evaluated.
The first rule in the stock conf. Drops host networking (those are local-listener targets), non-TCP ports, ports without a private side, and IPv6-mapped public IPs. Place it first.
- id: skip
match: |
{{ $netNOK := eq .NetworkMode "host" -}}
{{ $protoNOK := not (eq .PortProtocol "tcp") -}}
{{ $portNOK := empty .PrivatePort -}}
{{ $addrNOK := or (empty .IPAddress) (glob .PublicPortIP "*:*") -}}
{{ or $netNOK $protoNOK $portNOK $addrNOK }}
Match the four common image-name forms with match "sp". id: nginx makes the module name infer to nginx automatically — no module: line needed in the template.
- id: nginx
match: '{{ match "sp" .Image "nginx nginx:*" }}'
config_template: |
- name: docker_{{.Name}}
url: http://{{.Address}}/stub_status
- name: docker_{{.Name}}
url: http://{{.Address}}/basic_status
- name: docker_{{.Name}}
url: http://{{.Address}}/nginx_status
- name: docker_{{.Name}}
url: http://{{.Address}}/status
When the rule id is something other than the target module name, set module: explicitly inside the rendered job.
- id: postgres
match: '{{ or (eq .PrivatePort "5432") (match "sp" .Image "postgres postgres:* */postgres */postgres:* */postgresql */postgresql:*") }}'
config_template: |
module: postgres
name: docker_{{.Name}}
dsn: postgres://netdata:postgres@{{.Address}}/postgres
Use container labels to override behaviour without changing rules — e.g. opt a container in or out of monitoring, or pick a non-default endpoint. The example below requires the operator to set the label netdata.go.d/module=mymodule on the container.
- id: label-routed
match: '{{ and (hasKey .Labels "netdata.go.d/module") (eq (index .Labels "netdata.go.d/module") "mymodule") }}'
config_template: |
module: mymodule
name: docker_{{.Name}}
url: http://{{.Address}}/metrics
After enabling the discoverer, confirm it is finding containers and producing jobs.
Watch the agent log for Docker discoverer messages. With systemd:
journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep "discoverer=docker"
On a healthy daemon you should see the agent successfully calling ContainerList. If the log shows error on creating docker client or permission errors, the agent cannot reach /var/run/docker.sock.
In the Netdata UI go to Collectors -> go.d -> <module> for whatever modules your service rules target (nginx, redis, postgres, …) — each container that matched a rule should appear as a docker_<container-name> job.
If a job was created but no charts appear, the rendered config_template produced a config the collector module rejected (wrong DSN, unreachable URL, missing credential). Check the collector's log.
The Netdata user must be able to read the Docker socket. On a typical Linux host:
sudo usermod -aG docker netdata
systemctl restart netdata
In containers, mount the socket read-only and verify the file is readable from inside.
host networkinghost-mode containers are intentionally skipped by the Docker discoverer. Enable the net_listeners discoverer instead — it picks up locally-listening processes, which includes host-mode containers.
Stock rules match on .Image patterns. Custom forks or in-house image names won't match. Add a rule above the stock catch-alls keyed on your own image name (match "sp" .Image "myorg/nginx myorg/nginx:*") or use a .Labels-driven rule.
Common causes: the rendered URL is not reachable from the agent (different network, firewall); credentials baked into the template are wrong; the module's port is not the one Docker reported. Check the rendered job YAML in the agent's debug output.