Monitoring Linux servers & Cisco switches using Zabbix in Docker via SNMP — Part 1 of 2

Scott Ooi
6 min readNov 2, 2020
ls -al showing ownership of directories in /var/lib inside the MySQL container.
I honestly think the CLI is pretty.

I had to set this up for work and could not find an all-in-one tutorial for it, so I’m hoping this write-up benefits somebody else. Do let me know if I missed anything, or of any suggestions of improvements — this is my first attempt at Docker.

This tutorial is not so much about Zabbix itself as it is about getting containerised Zabbix up and running so you can start using it. Note that you can use Zabbix without Docker, but this tutorial does deal with the containerised version.

Table of Contents

Start here

1.0 — Container #1: MySQL

1.1 — How to persist data…

1.2 — …by setting the right permissions

2.0 — Container #2: Zabbix server

3.0 — Container #3: Zabbix web interface

3.1 — Enable/disable HTTPS

TL;DR

Start with:

  • A Linux server for hosting Zabbix (Ubuntu, at my workplace)
  • Docker installed on said server (Ubuntu instructions here, or the script that I use: GitHub)

I’ll do this by giving you the script I used to spin up Zabbix and then walk you through it: GitHub. Note that I run my scripts with root privileges, which is necessary for Docker anyway.

Zabbix needs 3 containers:

  • A database (this tutorial uses MySQL)
  • The Zabbix server itself (this tutorial uses the MySQL variant)
  • The Zabbix web interface (this tutorial uses the Apache variant)

i.e. the 3 sets of docker run commands in the script.

There is a Zabbix server variant for use with PostgreSQL and there are Zabbix web interface variants in Apache and Nginx for each of those databases! Depending on your cup of tea, these other variants are on the Zabbix Docker Hub.

1.0 — Container #1: MySQL

Spin up a MySQL container for Zabbix

LINE 1–4 avoids hardcoding passwords in plaintext in scripts / exposing passwords passed as arguments in ~/.bash_history!

LINE 6 creates a directory for “persisting” data, as explained in 1.1 below.

LINE 7 sets permissions to allow data to be written to said directory, for reasons explained in 1.2 below.

LINE 9 creates a “network” in Docker so the 3 containers can actually talk to each other — one of the reasons for containerisation is isolation to begin with!

LINE 11–21 starts the MySQL container:

  • --name is not just a placeholder — later containers reference it.
  • The -e flags configure the username(s) and password(s) for the MySQL database, among other options (see Environment Variables on the MySQL Docker Hub). MYSQL_ROOT_PASSWORD is the only mandatory variable, if you are so inclined.
  • --network specifies the Docker “network” to join.
  • The -v flag “persists”data, as explained in 1.1 below.
  • --restart specifies the “restart policy” i.e. the container’s behaviour on exit.
  • The -d flag runs containers in “detached” mode (“backgrounds” it), otherwise the first container will “take over” your terminal after it is spun up!
  • The last few options (lines 20 & 21) come from the Zabbix documentation. The Zabbix server container will fail to start if these are left out.

1.1 — How to persist data…

Data sits inside its container and will disappear when (not “if”!) the container is replaced/removed (e.g. when you eventually update it). This is very not useful for a database, so we need to “persist” the data.

The -v flag mounts a directory from the host (i.e. Linux) as a specific directory inside the container so any data that is written to said directory will exist outside the container as well. When the container is replaced/removed, the external directory will still exist, together with the data in it.

Note that I said: “specific” directory. Docker containers have specific “volumes” for mounting, detailed in their documentation. I mounted random paths out of curiosity and curious things ensued…

The syntax for the -v flag is:

-v directory-on-host:directory-in-container:[OPTIONS]

So, in this tutorial, I want to persist the data into /mnt/data/mysql of the Linux host. Looking up the MySQL Docker Hub, the directory inside the container with the data is /var/lib/mysql (you won’t find this in /var/lib of the host!) so the command becomes:

-v /mnt/data/mysql:/var/lib/mysql

1.2 — …by setting the right permissions

I think this is fixed now, but I’ll keep the section just for awareness.

Having said all that in 1.1 above, you still will not see any data in /mnt/data/mysql though if you ran the script as is with root privileges, but without the chown line. This is because, if you access the MySQL container via shell with

docker exec -it mysql-server /bin/bash

and check the ownership of /var/lib/mysql, you will find that it was created by mysql:mysql. This is compared to /mnt/data/mysql which will belong to root:root (if you ran the script as it with root privileges). The user “mysql” cannot write to /mnt/data/mysql!

ls -al showing ownership of directories in /var/lib inside the MySQL container.
The mysql directory was created by mysql rather than root!

There are any number of ways to deal with this — I just decided to deal with it in one line within the script by setting the ownership of /mnt/data/mysql to 999:999. I got this UID:GID by checking /etc/passwd and /etc/group inside the container (which, again, will be different to the host’s!). This way, the mysql user will be able to write to /mnt/data/mysql.

I can think of “better” ways to deal with this, but for the purpose, it works. Feel free to offer suggestions though!

cat /etc/passwd | grep mysql inside the container shows a UID:GID of 999:999.
The mysql user has a UID:GID of 999:999.

2.0 — Container #2: Zabbix server

Spin up the MySQL variant of the Zabbix server container

I’ll only explain lines that haven’t already been covered in 1.0.

LINE 2 references the MySQL container that was created first.

LINE 8 exposes port 10051 of the host to port 10051 of the container, which is the default port that Zabbix agents use, should you choose to use them (I prefer SNMP).

Containers are isolated, so container ports need to be explicitly mapped to ports on the host. The syntax for the -p flag is:

-p host-port:container-port

3.0 — Container #3: Zabbix web interface

Spin up the Apache variant of the MySQL variant of the Zabbix web interface container

I’ll only explain lines that haven’t already been covered in 1.0 or 2.0.

LINE 10 sets the time-zone. This is not mandatory, but makes sense.

LINE 12 exposes port 443 of the host to port 8443 of the container for HTTPS.

LINE 1 & 13 creates a directory on the host and mounts it for the container to receive ssl.key & ssl.crt to enable HTTPS. The directory is mounted read-only as the container is not expected to write to it.

touch test.txt in /etc/ssl/apache2 inside the container returns a “Read-only file system” error.
touch test.txt in /etc/ssl/apache2 inside the container returns a “Read-only file system” error.

3.1 — Enable/disable HTTPS

The script exposes the web interface container to only port 443. You will also need to place your SSL/TLS key and certificate as ssl.key & ssl.crt in /etc/ssl/apache2 of the host. Once that is done, restart all containers with docker restart $(docker ps -aq).

Of course, you could skip all that and replace -p 443:8443 with -p 80:8080 if you really wanted to…

TL;DR

  1. Start a Ubuntu server.
  2. git clone https://github.com/scottooi/zabbix-docker-scripts.git
  3. sudo sh zabbix-docker-scripts/install_docker_ubuntu.sh
  4. sudo sh zabbix-docker-scripts/docker_zabbix_mysql_apache.sh
  5. Place ssl.key & ssl.crt in /etc/ssl/apache2 of the Ubuntu host.
  6. Restart all containers with docker restart $(docker ps -aq).
  7. Navigate to your server IP in your web browser.
  8. Login using Username: “Admin” & Password: “zabbix” (and change it!).

Containerised Zabbix is up and running! The second part is configuring SNMP so you actually get data into it.

--

--

Scott Ooi

Ex-petroleum geologist. Fell in love with Linux and the CLI. Became a sysadmin. Fell in love with information security. Tech keeps me curious, humble, learning.