How to: Use the Zino Docker image¶
The repository includes a Dockerfile and a docker-compose.yml file for
building and running Zino as a Docker container.
Building the image¶
Build the image locally from the Zino source tree:
docker compose build
This builds the image and tags it zino:latest.
Running the container¶
docker compose up
This starts Zino using the settings in docker-compose.yml.
Configuration files¶
The compose file mounts the current directory (./) into /zino inside the
container, which is also Zino’s working directory. The current directory must
contain the configuration files Zino needs: zino.toml,
polldevs.cf and secrets.
Why host networking is required¶
Zino identifies an incoming SNMP trap by its source IP address: it looks up the sending device by that address and ignores the trap if it doesn’t match a device Zino polls.
This has an important consequence under Docker. With the default bridge
networking and published ports (-p 162:162/udp), Docker rewrites the source
address of incoming UDP packets to the bridge gateway (e.g. 172.17.0.1).
Zino then sees every trap as coming from the gateway, matches none of them to a
device, and silently drops them all — the tell-tale symptom is a Zino that polls
correctly but never reacts to traps.
The bundled docker-compose.yml therefore uses host networking
(network_mode: host): the container shares the host’s network stack with no
NAT, so Zino sees the real trap source addresses. Host networking also means
the container binds host ports directly, so there is no ports: section —
ports 162 (traps), 8000 (the uptime agent) and 8001/8002 (the APIs) are served
on the host as-is.
If host networking is not an option, receive traps through an SNMP trap
multiplexer such as nmtrapd running on the host, outside Docker: the
multiplexer binds port 162 and forwards traps — with their original source
address — to Zino. Point Zino at it with the [snmp.trap] source setting
(see Configuring trap reception).
Running as your own user¶
Binding the privileged trap port 162 requires starting as root, so the container
starts as root and then drops privileges to the built-in unprivileged zino
user — it never keeps running as root. To instead drop to your own host user,
so the mounted configuration and the state files Zino writes stay owned by (and
writable by) you, set HOST_UID and HOST_GID when starting it:
HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose up
The compose file passes these to Zino’s --user option, which drops to that
numeric UID/GID once port 162 is bound. Whichever user Zino drops to must be
able to write the mounted directory, where it keeps its state file.
Using a different trap port¶
Zino listens on port 162 by default. To use another port, add --trap-port
to the command in the compose file, keeping the --user part:
command: "--user ${HOST_UID:-0}:${HOST_GID:-0} --trap-port 1162"
Using the pre-built image¶
To use the pre-built image from the GitHub Container Registry instead of
building locally, comment out the build and image: zino:latest lines in
the compose file and uncomment:
image: ghcr.io/uninett/zino:latest