Installing zabbix-server with ansible

ansible_logo_black_squarezabbix_logo

Not only I have an puppet module which can be freely used from the forge, I also have some Ansible roles for Zabbix. This page will describe installing the zabbix-server with the dj-wasabi.zabbix-server role. If you want to know how you install the zabbix-agent, please check this page.

You can find the role and some information on this page: https://galaxy.ansible.com/list#/roles/2070

This role works on the 3 main Linux operating systems:

  • RedHat
  • Debian
  • Ubuntu

So, if your server has one of these operating system, you can continue. If you have however an other operating system and have some Ansible knowledge, please add some improvements and create an Pull Request on Github. I always accept Pull Requests related to the Ansible roles.

When you want to install this role, you only have to execute the following command:

ansible-galaxy install dj-wasabi.zabbix-server

Now we need to setup everything, but before we do anything we need to know what kind of database server is going to be used. Zabbix Server can work with several different databases as backend. This Ansible role only works with the following databases:

  • PostgreSQL
  • MySQL

Before we see the examples, there is one main parameter which is always needed: zabbix_url

This is the url on which the zabbix interface is available and should be an fqdn. Default it will create an Apache Virtual Host configuration file with this FQDN as ServerName. If you set this parameter as this:

zabbix_url: zabbix.example.com

the web interface will be available at: http://zabbix.example.com

PostgreSQL

Default the PostgreSQL is used as backend and before we can use this role, we need to find and download an Ansible role for PostgreSQL which can be used on your operating system. In this example we are using the following role: ‘galaxyprojectdotorg.postgresql’

The following is an example of an playbook for installing the ‘zabbix-server’ with an PostgreSQL database:

--- 
- hosts: zabbix-server
  roles: 
    - role: galaxyprojectdotorg.postgresql
      postgresql_pg_hba_conf: 
        - "host all all 127.0.0.1/32 trust"
        - "host all all ::1/128 trust"
      postgresql_pg_hba_local_ipv4: false
      postgresql_pg_hba_local_ipv6: false
    - role: dj-wasabi.zabbix-server
      zabbix_url: zabbix.example.com
      zabbix_version: 2.4
      server_dbuser: zabbix-server
      server_dbpassword: zabbix-server

This is the minimum configuration to use for this role with an PostgreSQL as database. What might help to secure everything is to use an more difficult to guess password for the ‘server_dbuser’ 😉

MySQL

Lets use MySQL as backend now. The following example is used with the following role: ‘geerlingguy.mysql’:

---
- hosts: localhost
  roles:
    - role: geerlingguy.mysql
    - role: ansible-zabbix-server
      zabbix_url: zabbix.example.com
      zabbix_version: 2.4
      database_type: mysql
      database_type_long: mysql
      server_dbuser: zabbix-server
      server_dbpassword: zabbix-server

Same as for the example with PostgreSQL, use an different value for the server_dbpassword.

Other configurations

Don’t think that what you just saw with configuring this role is everything. There are a lot of other configuration parameters that can be set. Keep in mind, that all configuration options you’ll normally find in the ‘zabbix_server.conf’ configuration file, can also be set with this role.

Lets give an example:

When we need to set the StartPollers to value 10, we can update the MySQL playbook to look like this:

---
- hosts: localhost
  roles:
    - role: geerlingguy.mysql
    - role: ansible-zabbix-server
      zabbix_url: zabbix.example.com
      zabbix_version: 2.4
      database_type: mysql
      database_type_long: mysql
      server_dbuser: zabbix-server
      server_dbpassword: zabbix-server
      server_startpollers: 10

When the role is executed on the ‘zabbix-server’, we see the following in the configuration file:

### option: startpollers
#	number of pre-forked instances of pollers.
#
StartPollers=10

Keep in mind to lower the property setting and prefix it with ‘server_’ and you’ll have the property for this Ansible role.

As this Ansible role isn’t perfect, please let me know if you encounter any issues by creating an issue. Pull Request for bugs or new features are always welcome!

Advertisements

wdijkerman-zabbix version 1.7.0 puppet module released

Puppet LogoZabbix Logo

I just released an new version of the wdijkerman-zabbix puppet module: 1.7.0.

This is an “Pull requests” release, as this release only contains pull requests created by users of this module. 🙂

The change log for this release:

  • misspelled parameter path #116 (By pull request: karolisc (Thanks!))
  • Update template.pp #121 (By pull request: claflico (Thanks!))
  • add support for CloudLinux #122 (By pull request: bastelfreak (Thanks!))
  • Fping wrong path in debian #124 (By pull request: Oyabi (Thanks!))
  • refactoring of repo.pp #126 (By pull request: bastelfreak (Thanks!))
  • Added supporting new Zabbix params #128 (By pull request: akostetskiy (Thanks!))
  • Generalise the zabbix_url #129 (By pull request: DjxDeaf (Thanks!))

The “#<NUM>” is a reference to an Github issue. The release can now also be found on and downloaded from the forge.

If you find an bug or have an improvement for this Zabbix puppet module, please create pull requests!

Zabbix nodata trigger, really a lifesaver

Zabbix has a lot of triggers you can use for your environment. But when it comes to the most important checks, I’ll update the current trigger and create an “or” statement with the “nodata” trigger.

It happened for me a few times when Zabbix didn’t notify me about some checks that went into PROBLEM while the service/program wasn’t responding. In all of these cases, I had it configures with the “last” trigger. All of them said it was ok, but the latest update was at least 30 minutes ago (Some even longer!). I slept well though, but my start of the day wasn’t really good. 🙂

I did find that most of these kind of checks were items that used scripts which were created by myself or by my colleagues. These were simple scripts in bash or python, which had no proper way of exiting due to an timeout.

So the first and most easy way is to update the trigger with the “nodata” configuration. I use an “default” of 5 minutes, if I don’t have any data the trigger can be fired. An good example is the trigger for the zabbix-agent:

{Template App Zabbix Agent:agent.ping.nodata(5m)}=1

When there is no data retrieved in the last 5 minutes, it will be fired. So I’ve updated the trigger for my Apache template like this:

{Template Apache:apache.run.status[{HOST.NAME},'localhost'].last()}=0 or {Template Apache:apache.run.status[{HOST.NAME},'localhost'].nodata(5m)}=1

If the last value of the item apache.run.status is 0 or there is no data retrieved in the last 5 minutes, then we can assume Apache is down.

But these scripts needs to be able to exit within the TimeOut parameter in the configuration file. So each script should have an timeout and when this timeout occurs, it should print some information which Zabbix can handle. (Not an python stacktrace for example. 🙂 )

I know the “nodata” trigger has an few drawbacks. It do add some extra load on the server for these checks. I believe the “nodata” triggers are checked every 30 seconds, but I try to use the nodata only for those critical (Or Disaster in Zabbix terms 🙂 ) triggers.

Another one, but happens (hopefully) not that much, when the Zabbix-server is in some kind of maintenance or had some problems (Or when you have an Zabbix proxy which doesn’t send the data to the server) a lot of triggers are fired when the times has past. So you just updated the Zabbix-server with the latest (linux/kernel) patches and after say 10 minutes the Zabbix-server is up and running again, all of those nodata triggers are fired. 🙂

But anyways, it is an lifesaver! 🙂

Installing zabbix-agent with Ansible

ansible_logo_black_squarezabbix_logo

Not only I have an puppet module for installing Zabbix, I also have some Ansible roles for this. At the moment there are 4 roles:

In this blog item, we talk about the “zabbix-agent” role. The latest version is 0.2.0.

Defaults

Installing this role is very easy:


ansible-galaxy install dj-wasabi.zabbix-agent

It will be installed in your roles directory. Default is “/etc/ansible/roles” or whatever you have configured in the ansible.cfg file. After installation there is only 1 (or 2 when you make use of active items) parameters needed for making this role work:

agent_server: <IP_-_FQDN_OF_ZABBIX_SERVER>
agent_serveractive: <IP_-_FQDN_OF_ZABBIX_SERVER>

This will need the ip address or the FQDN of the “zabbix-server”.

OS?

This role works on several operating systems/families:

  • RedHat
  • Debian
  • Ubuntu
  • OpenSuse

If you have an operating system/family which isn’t in the list above, you can create an issue at the Github page and please fill in the request. I can’t make any guarantee that it will come, but I can try it. Or if you do have some Ansible skills, please create an Pull request and I would be happy to accept it. 🙂

Playbook

So, how does the playbook looks like? Like this:

- hosts: all
  sudo: yes
  roles:
   - role: dj-wasabi.zabbix-agent
     agent_server: <IP_-_FQDN_OF_ZABBIX_SERVER>
     agent_serveractive: <IP_-_FQDN_OF_ZABBIX_SERVER>

As you see it is very basic and does the job very good. This only installs the agent on the specific server and configures the configuration file. But we really want to automate everything right?

Cove

Few weeks ago I found this pull requests for the “ansible-modules-extra” repository. This pull requests had an few ansible modules which made sure that you can use the Zabbix API to create or update hosts configuration. In the pull requests there were something like 5 modules, but this Ansible role only use 3 of them. With this role, you can create the following:

  • host groups
  • Host itself.
  • Macros for the host

For now, when the host is created, it will only create the “zabbix interface”. Maybe with the next release I’ll make sure you can also create SNMP, JMX and IPMI interfaces.

How do we have to configure it? Something like this. You will have to change it to your environment.

- hosts: wdserver00
  roles:
     - role: zabbix-agent
       agent_server: 192.168.1.1
       agent_serveractive: 192.168.1.1
       zabbix_url: http://zabbix.example.com
       zabbix_api_use: true
       zabbix_api_user: Admin
       zabbix_api_pass: Zabbix
       zabbix_create_host: present
       zabbix_host_groups:
         - Linux servers
       zabbix_link_templates:
         - Template OS Linux
       zabbix_macros:
         - macro_key: apache_type
           macro_value: reverse_proxy

I’ll skip the first 2 parameters, as these are described earlier on this page.

zabbix_url: The url on which the Zabbix web interface is available.
zabbix_api_user: The username which will connect to the API.
zabbix_api_pass: The password for the “zabbix_api_user” user.
zabbix_create_host: present if we want to create the host, absent if we want to delete it.
zabbix_host_groups: List of hostgroup where this host belongs to.
zabbix_link_templates: List of templates which will be linked to the host.
zabbix_macros: key, value pair of macros that will be used by the host. 

When we run Ansible, we will see at the end of the run:

.. <skip> ..
TASK: [zabbix-agent | Create hostgroups] **************************************
ok: [wdserver00 -> 127.0.0.1]

TASK: [zabbix-agent | Create a new host or update an existing host's info] ****
changed: [wdserver00 -> 127.0.0.1]

TASK: [zabbix-agent | Updating host configuration with macros] ****************
changed: [wdserver00 -> 127.0.0.1] => (item={'macro_key': 'apache_type', 'macro_value': 'reverse_proxy'})

Nice! If you check the Web interface, you’ll see that the host is created with the correct host groups and templates. If not, you’ll see some error messages in the Ansible output which will say what went wrong.

This role isn’t perfect, so if you encounter an bug or found/have and enhancement, please create an Pull request at Github and I’ll accept it. We can all make this role beter. 🙂

Side note:

There are more parameters which can be overridden, please check the “defaults/main.yml” file or the README.

Zabbix agent installation and configuration with puppet exported resources

puppet zabbix_logo

Who doesn’t like to automate tasks when this is easy and can save a lot of time/troubles. When you are just starting with Zabbix, it seems that the only thing you can automate is installing the components with rpm/deb packages on the servers/clients. After installation of the packages, you’ll still need to create the host in the web interface which takes some time (And boring to if you have a lot of hosts to configure..). There is an possibility to use (auto) discovery rules, but this requires some configuration in the web interface and this only works once when the host isn’t configured in the web interface (Initial setup only).

Luckily, the Zabbix has an API which can be used for some tasks that can be automated, like creating hosts! The wdijkerman-zabbix module can use this API for the following tasks:

  • Create host
  • Update host with Templates

There is an requirement when you want to do this: Puppet Master needs the PuppetDB configured. If you want to configure an PuppetDB, please use Google for this as I won’t discuss this here.

Idea

The idea is that when an installation is done via the “zabbix::agent” class on the agent, it send some information via puppet to the PuppetDB. This is some basic information like ipaddress, name of the host and the hostgroups for this host. When the puppet agent on the “zabbix-server” runs, it will retrieve the information from the PuppetDB and will create via the Zabbix API the host(s). With this setup, everything is automated and you don’t have to worry for forgetting something.
So, how do you have to configure the zabbix module?
class { 'zabbix':
  zabbix_url       => 'zabbix.example.com',
  manage_resources => true,
}

This is an very basic configuration method mentioned above which will automatically configure the hosts in the web interface when a new “zabbix-agent” is installed. You don’t have to do anything else (yes ok, you’ll have to run some puppet runs on several machines. :-).)

This assumes that the password for the “Admin” user is still “zabbix”. You can override this of course, just like the database credentials which are default set to “zabbix-server”. (Don’t forget to change it to something non default 😉 )

Userparameters

There is an other nice feature in the “wdijkerman-zabbix” module which uses the Zabbix API. The “zabbix::userparameters” define can make use of the API. The goal for this define is installing an UserParameters file in the zabbix-agent includedir. This file consists of 1 or more UserParameter entries which explains what commands needs to be executed for an key.

An example:

zabbix::userparameters { 'Exim':
 content => 'UserParameter=exim.mailq,sudo /usr/sbin/exim -bpc',
}

There is an item in a template which executes the “sudo /usr/sbin/exim -pbc” command with the “exim.mailq” key. When the above 3 lines are in the exim puppet module and this module installs the UserParameter file, you still need to update the host in the web interface to make sure the “Template Exim” is assigned.

But stop, we can use it like the following now:

zabbix::userparameters { 'Exim':
 content  => 'UserParameter=exim.mailq,sudo /usr/sbin/exim -bpc',
 template => 'Template Exim',
}

We also supply the name of the Zabbix Template in this “user::parameters” define. When configured we first have to execute an puppet run on the agent, so it sends some data to the PuppetDB.

When the Puppet Agent runs on the “zabbix-server”, it first checks if the hosts exits and then it will assign the template “Template Exim” to the host automatically. Off course when the template does not exists, the Puppet run will fail.

Woot! 🙂

One node vs multi node setup zabbix module zabbix-proxy

zabbix_logo

With the previous post I showed you how you can use the zabbix-server on one or multiple machines with my wdijkerman-zabbix puppet module. At the end I said that you could also do this with the zabbix-proxy. So this blog item is showing how to setup the zabbix-proxy on 1 or 2 nodes. I don’t know if people are using it like this, but when I was busy for the zabbix-server, I thought that I also had to do this for the zabbix-proxy. 🙂

So sit back and watch the show. 🙂

Single node

PostgreSQL

So, we first show you have to do this with the PostgreSQL as backend.

node 'proxy.example.com'
 class { 'postgresql::server': }

 class { 'zabbix::proxy':
   zabbix_server_host => '192.168.20.11',
   zabbix_server_port => '10051',
 }
}

As you see in this manifests file, we have configured to use the postgresql-server class and the zabbix-proxy class. This zabbix-proxy class needs 1 parameter: ‘zabbix_server_host’. This is the ip address or fqdn of the zabbix-server host. The parameter ‘zabbix_server_port’ is optional, you only have to use this parameter when the zabbix-server is running on a different port than 10051.

MySQL

Okay, so you want to use MySQL as database backend? No worries, take a look at this:

node 'proxy.example.com'
 class { 'mysql::server': }

 class { 'zabbix::proxy':
   zabbix_server_host => '192.168.20.11',
   zabbix_server_port => '10051',
   database_type      => 'mysql',
 }
}

Like the zabbix-server, the zabbix-proxy uses the PostgreSQL as default database. So we have to use the ‘database_type’ parameter for specifying mysql.

Multi node

With the following example, we have 2 servers:

  • server11.example.com, which will be running the zabbix-proxy.
  • server12.example.com, which will be running the database.

MySQL

Lets start the manifests file again with the MySQL as ‘database_type’:

node 'server11.example.com' {
# My ip: 192.168.30.11
  class { 'mysql::client': }
  class { 'zabbix::proxy':
    zabbix_server_host => '192.168.20.11',
    manage_database    => false,
    database_host      => 'server12.example.com',
    database_type      => 'mysql',
  }
}

node 'server12.example.com' {
# My ip: 192.168.30.12
  class { 'mysql::server':
    override_options => {
      'mysqld'       => {
        'bind_address' => '192.168.30.12',
      },
    },
  }
  class { 'zabbix::database':
    database_type     => 'mysql',
    zabbix_type       => 'proxy',
    zabbix_proxy      => 'server11.example.com',
    database_name     => 'zabbix-proxy',
    database_user     => 'zabbix-proxy',
    database_password => 'zabbix-proxy',
  }
}

On the node of the zabbix-proxy, we had to add a new parameter: ‘manage_database’. We had to set it to false, the proxy class isn’t responsible for creating the database and loading the files. Thats what the ‘zabbix::database’ will do on the 2nd host.

PostgreSQL

Now with the PostgreSQL as ‘database_type’:

node 'server11.example.com' {
# My ip: 192.168.30.11
  class { 'postgresql::client': }
  class { 'zabbix::proxy':
    zabbix_server_host => '192.168.20.11',
    manage_database    => false,
    database_host      => 'server12.example.com',
  }
}

node 'server12.example.com' {
# My ip: 192.168.30.12
  class { 'postgresql::server':
    listen_addresses => '192.168.30.12'
  }
  class { 'zabbix::database':
    zabbix_type       => 'proxy',
    zabbix_proxy_ip   => '192.168.30.11',
    database_name     => 'zabbix-proxy',
    database_user     => 'zabbix-proxy',
    database_password => 'zabbix-proxy',
  }
}

With the above setup for both MySQL as PostgreSQL as ‘database_type’, we had to use the ‘database_name’ and ‘database_password’ parameters. The default values for the ‘zabbix::database’ class is for both parameters ‘zabbix-server’. Which is a kind of strange for the proxy. 🙂

Note

With the default installation on both the single as the multi node setup, the password for the database is ‘zabbix-server’. I would strongly recommend that you use the parameter: ‘database_password’ and give it a nice password.

One node vs multi node setup zabbix module zabbix-server

zabbix_logo
So it was quiet the last few months for posting stuff on the site, so I’ll try to do it now. I also moved the wordpress.com instead of hosting the site myself.
At the moment on writing this blog item, the wdijkerman-zabbix puppet module is at release 1.1.0. One of the biggest changes which came with release 1.0.0, is that you can choose whether your want everything one to run on a single host (Single Node, Like most of us) or running it on different servers (Multi node).

 

Up to release 1.0.0 you could only use the wdijkerman-zabbix puppet module if everything was running on the same host. Yes, from release > 0.5.0 you could even with some ‘hacking’ run the database on an other host, but that was not something I would document let alone it was a little bit confusing to do.

 

First, we start with the Single node setup. Apache, Zabbix-web, Zabbix-server and the database is installed on 1 system.

Single node

PostgreSQL

So, lets install the zabbix-server on one host:
node 'zabbix.example.com'
  class { 'apache':
    mpm_module => 'prefork',
  }
  include apache::mod::php
 
  class { 'postgresql::server': }
 
  class { 'zabbix':
    zabbix_url    => 'zabbix.example.com',
  }
}
With this manifest setup, you have configured an complete zabbix-server on one host.

 

It will install and configure Apache, postgresql (Default database for zabbix) and both zabbix components zabbix-web and zabbix-server. There is only one parameter needed for zabbix-server and it is the ‘zabbix_url’. This is the url on which the zabbix web interface is available, the rest of the parameters are optional.

MySQL

Oh, you want to run it on MySQL? No problem, this would be an very basic setup to begin with:
node 'zabbix.example.com'
  class { 'apache':
    mpm_module => 'prefork',
  }
  include apache::mod::php

  class { 'mysql::server': }

  class { 'zabbix':
    zabbix_url    => 'zabbix.example.com',
    database_type => 'mysql',
  }
}

multi node

Now, the multi node setup. This example consists of 3 nodes:
  • server01.example.com, which will be running Apache and the zabbix-web component.
  • server02.example.com, which will be running the zabbix-server component
  • server03.example.com, which will be running the database.

First we give an example of using this setup with the MySQL database.

MySQL

The following example will be given with the usage of MySQL as database backend. You can also choose to use the PostgreSQL database, but  than you have to change the setup a little bit. This will be described after the example:
node 'server01.example.com' {
  # My ip: 192.168.20.11
  class { 'apache':
    mpm_module => 'prefork',
  }
  class { 'apache::mod::php': }
  class { 'zabbix::web':
    zabbix_url => 'zabbix.example.com',
    zabbix_server => 'server02.example.com',
    database_host => 'server03.example.com',
    database_type => 'mysql',
  }
}

node 'server02.example.com' {
  # My ip: 192.168.20.12
  class { 'mysql::client': }
  class { 'zabbix::server':
    database_host => 'server03.example.com',
    database_type => 'mysql',
  }
}

node 'server03.example.com' {
  # My ip: 192.168.20.13
  class { 'mysql::server':
    override_options => {
      'mysqld' => {
      'bind_address' => '192.168.20.13',
      },
    },
  }
  class { 'zabbix::database':
  database_type => 'mysql',
    zabbix_server => 'server02.example.com',
    zabbix_web => 'server01.example.com',
  }
}
We have to fill in some ip’s or hostnames for this setup. Both the zabbix-web and -server needs to know where the database is and the zabbix-web needs to know where to find the zabbix-server.

PostgreSQL

When you want to use the PostgreSQL as backend in an multinode setup, you can use something like this:
node 'server01.example.com' {
# My ip: 192.168.20.11
 class { 'apache':
   mpm_module => 'prefork',
 }
 class { 'apache::mod::php': }
 class { 'zabbix::web':
   zabbix_url => 'zabbix.example.com',
   zabbix_server => 'server02.example.com',
   database_host => 'server03.example.com',
   database_type => ‘postgresql',
 }
}

node 'server02.example.com' {
# My ip: 192.168.20.12
 class { 'postgresql::client': }
 class { 'zabbix::server':
   database_host => 'server03.example.com',
   database_type => ‘postgresql',
 }
}

node 'server03.example.com' {
# My ip: 192.168.20.13
 class { 'postgresql::server':
   listen_addresses => '192.168.20.13'
 }
 class { 'zabbix::database':
   database_type => ‘postgresql',
   zabbix_web_ip => '192.168.20.12',
   zabbix_server_ip => '192.168.20.13',
 }
}
The PostgreSQL class accepts different values than MySQL: PostgreSQL accepts ipaddresses and MySQL accepts fqdn.

 

On a next item, I’ll go into the zabbix-proxy component. Like the zabbix-server, this can also be installed on a single node or multi node.

Note

With the default installation on both the single as the multi node setup, the password for the database is ‘zabbix-server’. I would strongly recommend that you use the parameter: ‘database_password’ and give it a nice password.