Our Blog

Ultimate Guide: Kubernetes Monitoring with Zabbix, Grafana & Skedler


Kubernetes is a powerful platform for running scalable, distributed applications, but its complexity makes monitoring challenging. Therefore, without proper visibility, issues can go unnoticed and degrade performance and availability.

Now, enter Zabbix, Grafana, and Skedler (ZGS) together, they form a powerful trio that provides an end-to-end observability and reporting solution for Kubernetes.

Why Monitor Kubernetes with Zabbix?

Zabbix is a powerful open-source monitoring solution for infrastructure, including Kubernetes clusters. It helps teams:

  • Detect pod failures and service slowdowns
  • Send real-time alerts
  • Maintain system uptime and performance

However, Zabbix’s native dashboards and reporting features are limited. At this point, Grafana and Skedler step in.

The Ideal Stack: Zabbix + Grafana + Skedler (ZGS Stack)

Zabbix for Data Collection

Zabbix monitors pods, nodes, and services with deep metrics.

Grafana for Visualization

Grafana complements Zabbix by adding:

  • Interactive dashboards
  • Custom visualizations per stakeholder
  • Unified views from multiple sources (Zabbix, Prometheus, MySQL, etc.)

Skedler for Reporting

Grafana OSS lacks built-in reporting. Skedler bridges that gap with:

  • Scheduled PDF, Excel, or HTML reports
  • No coding required
  • Role-based access
  • Audit-ready reports  for compliance

Get Started with Skedler for
Automated Kubernetes Monitoring

Get Started Today

Therefore, this stack equips you with full observability and automated insights.

Kubernetes Monitoring Architecture with Zabbix, Grafana, and Skedler (ZGS)

Step-by-Step: Kubernetes Monitoring Setup

In this article, we’ll guide you through monitoring a Kubernetes cluster using Zabbix. Then, we’ll explore how to query relevant metrics and build powerful visualizations in Grafana. Step by step, you’ll learn how to collect and process Kubernetes data, integrate it into Grafana for interactive dashboards, and finally, use Skedler to automate report generation. 

As a result, you’ll end up with a full-fledged monitoring and reporting solution that leverages Zabbix, Grafana, and Skedler for clear and actionable insights into your Kubernetes environment.

Install Zabbix Monitoring for Kubernetes

1. Prerequisites

  • kubectl installed
  • helm installed
  • Docker installed
  • Kubernetes cluster running (example: minikube)

2. Download the Zabbix Helm repository

Add the Zabbix chart repository to your local Helm setup with the following commands:


cd ~
git clone https://git.zabbix.com/scm/zt/kubernetes-helm.git
cd kubernetes-helm

3. Zabbix Configuration Setup

Accordingly, based on your setup, a few configurations may be necessary—usually just setting environment variables for the Zabbix Agent and Proxy


nano $kubernetes-helm/values.yaml

By default, the Zabbix Helm chart deploys the Zabbix Proxy with SQLite3, which works fine for testing or small setups. However, the Zabbix Server does not support SQLite3; it requires a full-featured SQL database like MySQL, MariaDB, or PostgreSQL.

If you want the proxy to work with a Zabbix Server that uses a SQL database, it’s best to update the Zabbix Proxy configuration to use MySQL or PostgreSQL as well.

In this setup, I’m using MySQL as the backend database for Zabbix. Instead of deploying MySQL within the same Helm release as the Zabbix Proxy or Server, I’ve opted to run MySQL as a standalone deployment. As a result, this offers better separation of concerns and greater flexibility in managing database persistence and scaling independently.

Below is the “zabbix-mysql-server.yaml” manifest used to deploy the MySQL service and deployment in the Kubernetes cluster:


apiVersion: v1
kind: Service
metadata:
  name: zabbix-mysql-server
spec:
  selector:
    app: zabbix-mysql
  ports:
    - port: 3306
      targetPort: 3306
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: zabbix-mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: zabbix-mysql
  template:
    metadata:
      labels:
        app: zabbix-mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0.30
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: root
            - name: MYSQL_DATABASE
              value: zabbix
          ports:
            - containerPort: 3306

Zabbix Proxy

Additionally, I’ve configured the Zabbix Proxy to connect to this external MySQL service by updating their database connection details according.


zabbixProxy:
  enabled: true
  serviceAccount:
    create: false
    name: zabbix-service-account
  containerSecurityContext: {}
  resources: {}
  image:
    repository: zabbix/zabbix-proxy-mysql
    tag: alpine-7.0-latest
    pullPolicy: IfNotPresent
    pullSecrets: []
  env:
    - name: DB_SERVER_HOST
      value: zabbix-mysql-server
    - name: MYSQL_DATABASE
      value: zabbix
    - name: MYSQL_USER
      value: root
    - name: MYSQL_PASSWORD
      value: root
    - name: ZBX_PROXYMODE
      value: "0"
    - name: ZBX_HOSTNAME
      value: zabbix-proxy
    - name: ZBX_SERVER_HOST
      value: "192.168.1.35:10051"
    - name: ZBX_DEBUGLEVEL
      value: "3"
    - name: ZBX_CACHESIZE
      value: 128M
    - name: ZBX_PROXYCONFIGFREQUENCY
      value: "10"

Zabbix Agent

As part of this setup, I’m configuring the agent’s passive server environment variable so that it can accept connections from any IP address. Consequently, this allows for greater connectivity flexibility. Additionally, for the proxy, I’m specifying the server host that the proxy can reach, along with a custom (non-default) port. 


zabbixAgent:
  enabled: true
  resources: {}
  securityContext: {}
  containerSecurityContext: {}
  hostNetwork: false
  dnsConfig: {}
  hostPID: true
  hostRootFsMount: true
  extraHostVolumeMounts: []
  image:
    repository: zabbix/zabbix-agent2
    tag: alpine-7.0-latest
    pullPolicy: IfNotPresent
    pullSecrets: []
  env:
    - name: ZBX_PASSIVE_ALLOW
      value: "true"
    - name: ZBX_ACTIVE_ALLOW
      value: "false"
    - name: ZBX_DEBUGLEVEL
      value: "4"
    - name: ZBX_TIMEOUT
      value: "4"
    - name: ZBX_PASSIVESERVERS
      value: "0.0.0.0/0"

RBAC Setup

As part of the RBAC (Role-Based Access Control) configuration, I’ve assigned the necessary permissions to a Kubernetes ServiceAccount. Consequently, this ServiceAccount is linked to a service token, which the Zabbix server uses to authenticate and access the Kubernetes API for monitoring purposes.

Later, we’ll cover how to retrieve the service account token (typically via a Secret or by mounting it in a Pod) and how to configure Zabbix to use this token for secure communication with the Kubernetes API server.


rbac:
  create: true
  additionalRulesForClusterRole:
    - apiGroups: [""]
      resources: ["*"]
      verbs: ["*"]
    - apiGroups: ["apps"]
      resources: ["*"]
      verbs: ["*"]
    - apiGroups: ["batch"]
      resources: ["*"]
      verbs: ["*"]
    - apiGroups: ["extensions"]
      resources: ["*"]
      verbs: ["*"]
    - apiGroups: ["apps", "rbac.authorization.k8s.io"]
      resources: ["*"]
      verbs: ["*"]

serviceAccount:
  create: true
  name: zabbix-service-account

4. Create a Namespace (if not already)

You can also optionally add a namespace. 


kubectl create namespace monitoring

5. Deploy Zabbix Helm Chart


helm install zabbix . --dependency-update -f $kubernetes-helm/values.yaml -n monitoring

Wait until everything is up and running. You can check the status using this command:


kubectl get pods -n monitoring




Now everything is set up, the next step is to add hosts in Zabbix for your Kubernetes cluster. But before we do that, we need one more thing, the access token.

6. Get the Token (for Api & Access)

Get the access token that was created with the service account during the Helm chart installation. To do this, run the following command using the service account’s name:


kubectl get secret zabbix-service-account -n monitoring -o jsonpath={.data.token} | base64 -d

This command retrieves the secret linked to the service account and extracts the token from it. Be sure to save the token you’ll need later.

You’ll also need the Kubernetes API address. Usually, you can access it through the built-in proxy in your cluster instead of connecting directly to the server or using an external proxy. In that case, use the service DNS name:


https://kubernetes.default.svc.cluster.local:443/api

If that doesn’t work for your setup, you can run this command to find the right address:


kubectl cluster-info

7. Deploying Zabbix Server Locally with Docker Compose

Now that your Zabbix Proxy and Agent are up and running inside your Kubernetes cluster, the next step is to deploy the Zabbix Server, which will receive and process monitoring data.

For flexibility, you can set up the Zabbix Server on your local machine, a VM, or inside Docker. In this example, we’ll use Docker Compose to quickly spin up the full Zabbix stack, including the server, web UI, and MySQL database.

Here’s a basic docker-compose.yml to get started


version: '3'

services:
  zabbix-mysql-server:
    image: mysql:8.0.30
    container_name: zabbix-mysql-server
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: root
      MYSQL_PASSWORD: root         # ⚠️ Use a strong password in production
      MYSQL_DATABASE: zabbix
    networks:
      - zabbix-network
    volumes:
      - mysql-data:/var/lib/mysql

  zabbix-server:
    image: zabbix/zabbix-server-mysql:alpine-7.0-latest
    container_name: zabbix-server
    environment:
      DB_SERVER_HOST: zabbix-mysql-server
      MYSQL_DATABASE: zabbix
      MYSQL_USER: root
      MYSQL_PASSWORD: root
    ports:
      - "10051:10051"              # Zabbix server listening port
    networks:
      - zabbix-network

  zabbix-web:
    image: zabbix/zabbix-web-nginx-mysql:latest
    container_name: zabbix-web
    environment:
      DB_SERVER_HOST: zabbix-mysql-server
      MYSQL_DATABASE: zabbix
      MYSQL_USER: root
      MYSQL_PASSWORD: root
    ports:
      - "8080:8080"                # Web UI accessible at http://localhost:8080
    networks:
      - zabbix-network

networks:
  zabbix-network:

volumes:
  mysql-data:
  • All containers are connected through an isolated Docker network (zabbix-network) for secure internal communication
  • The MySQL database persists data using a named volume (mysql-data).
  • Ports:
    • 10051 → Zabbix Server (used by proxies and agents to send data)
    • 8080 → Zabbix Web UI (use your browser to access it)
  • Make sure the database credentials match across all services.

Once you run this with:


docker-compose up -d

Zabbix should be accessible via http://localhost:8080. From there, you can log in to the web UI, connect your proxy, and begin monitoring your Kubernetes infrastructure

8. Adding the Proxy and Setting Up Monitoring

First, go to the Zabbix UI and navigate to: Administration → Proxies

  • Click Create Proxy

Since this is an active proxy, all you need to do is enter a name. If you didn’t change anything in the Helm chart, the default name will be `zabbix-proxy`. If you want to use a different name, you can set it using the `zbx_hostname` environment variable in the Helm chart. For now, we’ll use the default. Type the name and click Add. After a few minutes, you should see that the proxy has connected.

Next, we’ll organise Kubernetes-related hosts:

  • Go to Configuration → Host groups, and create a new group called Kubernetes.

Then create a new host:

  • Go to Configuration → Hosts, and click Create Host.
  1. Name it “Kubernetes Nodes”.
  2. Assign it to the “Kubernetes” group you just made.
  3. Attach the template named “Kubernetes nodes by HTTP”.
  4. Set “Monitored by proxy” to the proxy you created earlier (e.g., `zabbix-proxy`).

Now configure some macros:

  1. Click the Macros tab and choose “Inherited and host macros
  2. Set `{KUBE.API.ENDPOINT.URL}` to your Kubernetes API URL — for example:

           `https://kubernetes.default.svc.cluster.local:443/api`

  1. Set the token macro to the API token you got earlier from the command line.
  2. Click Add.

After a few minutes, Zabbix will begin collecting data. Consequently, you’ll start to see metrics appear under “Latest Data,” and shortly thereafter, new hosts will show up for each Kubernetes node.

9. Creating Another Host for Kubernetes Cluster State

Now let’s create one more host to monitor the overall state of the Kubernetes cluster using the Kubernetes API and kube-state-metrics.

  • Go to Configuration → Hosts and click Create Host again.
  1. Name the host: ”Kubernetes Cluster State”.
  2. Add it to the same “Kubernetes” host group.
  3. Attach the template called “Kubernetes Cluster State by HTTP”.
  4. Under “Monitored by proxy“, select the same proxy you created earlier.

Now go to the Macros tab:

  1. Set `{KUBE.API.ENDPOINT.URL}` to: `https://kubernetes.default.svc.cluster.local:443`

(Note: don’t include `/api` at the end this time.)

  1. Set the API token just like you did for the previous host.
  2. Once that’s done, click Add.

If everything’s set up correctly, Zabbix will start pulling cluster-level data soon.


Integrate Zabbix with Grafana & Create Dashboard

1. Install & Enable the Zabbix Plugin in Grafana

  • Log in to your Grafana instance.
  • Go to “Administration” → “Plugins”.
  • Search for Zabbix.
  • Click the “Zabbix” plugin by Alexey Kalachev and then click Install.
  • Once installed click on Enable

2. Add Zabbix as a Data Source

  • Go to “Configuration” → “Data Sources” → “Add data source”.
  • Select Zabbix
  • Fill out the following details:
    • Name: Zabbix
    • URL: http://<zabbix-server-host>/api_jsonrpc.php.
    • Access: Server (default)
    • Zabbix API Details:
      • Username: Zabbix frontend user (e.g. Admin)
      • Password: Corresponding password
  • Click Save & Test to validate the connection.

3. Create a Custom Dashboard

  • Go to “Create” → “Dashboard” 
  • Click “Add new panel”
  • In the Query section, select:
    • Data source: Zabbix
    • Group: The Zabbix host group (e.g., Kubernetes Nodes)
    • Host: The target host
    • Item: The metric you want (e.g., CPU Load, Memory Usage)
  • Choose a visualisation type (graph, gauge, table, etc.).
  • Customise titles, thresholds, and legends as needed.
  • Click Apply.


Repeat this process to add more panels and build a full dashboard.

4. Save Your Dashboard

  • Click the disc icon or “Save dashboard” button.
  • Give it a name (e.g., Zabbix Kubernetes Monitoring).
  • Optionally, select a folder to organise your dashboards.
  • Click Save.

Creating & Scheduling Reports in Skedler for Grafana Dashboards

Moreover, Skedler allows you to generate rich, formatted PDF, Excel, and HTML reports with minimal configuration—perfect for sharing insights with teams or stakeholders.

For a detailed, step-by-step guide, be sure to visit the official Skedler blog and tutorial video:

https://www.skedler.com/blog/grafana-pdf-report-export-guide/

Final Thoughts

If you’re running Kubernetes, monitoring is non-negotiable.

Overall, the Zabbix + Grafana + Skedler (ZGS Stack) provides a cost-effective, scalable, and elegant solution for monitoring, visualizing, and reporting on your Kubernetes environment.  

Ready to Try It Out?

First, deploy the stack and customize your dashboards. Then, let Skedler handle reporting. As a result, your SRE and compliance teams will thank you.

Automate Your Grafana Reports

No Code, No Manual Work.

Get Started Today
Copyright © 2026 Guidanz Inc
Translate »