Tuesday, April 29, 2025

Automating Zabbix Installations Using Ansible: A Comprehensive Guide

 

Introduction

In the realm of IT infrastructure, automation is not just a luxury but a necessity. Ansible, a powerful automation tool, combined with Zabbix, an open-source monitoring solution, provides a robust framework for managing and monitoring IT environments. This guide will walk you through the process of automating the installation and configuration of Zabbix using Ansible, leveraging the provided YAML configurations.


Why Use Ansible with Zabbix

Ansible is a simple yet powerful tool for automating IT tasks, including configuration management, application deployment, and orchestration. It uses a declarative language to describe system configurations.

Zabbix is a comprehensive monitoring solution for networks and applications. It provides capabilities such as real-time monitoring, alerting, and trending. By automating Zabbix installation with Ansible roles, you can ensure consistent deployments across multiple environments, reducing manual errors and saving time.

Now, let’s proceed with the breakdown of all the configuration files required to automate an install of Zabbix on RHEL 9 or CentOS 9.

Configuration FileDescription
install_zabbix.ymlThe main playbook that orchestrates the installation of Zabbix on all specified hosts using the ansible-zabbix-install role.
inventory.ymlDefines the inventory of Zabbix nodes, specifying hostnames and their corresponding IP addresses.
defaults/main.ymlContains default variables for the Ansible role, including Zabbix version, RHEL version, database passwords, and repository URLs.
handlers/main.ymlDefines handlers to restart or reload services (like Zabbix, Apache, and PostgreSQL) when changes occur during the playbook execution.
tasks/main.ymlIncludes various task files necessary for setting up Zabbix, such as PostgreSQL, network configuration, SSL setup, SELinux configuration, and frontend installation.
tasks/network.ymlConfigures firewall settings and SELinux policies to ensure proper access for Zabbix, PostgreSQL, and Apache.
tasks/postgresql.ymlHandles the installation and configuration of PostgreSQL, including user creation, database setup, and remote access configuration.
tasks/selinux.ymlInstalls SELinux policy utilities and creates custom SELinux modules to allow PHP to allocate executable memory.
tasks/zabbix.ymlInstalls the Zabbix server, frontend, and agent, and configures the database and user permissions.
tasks/ssl.ymlManages the creation of SSL directories and self-signed certificates for secure communication.
tasks/frontend.ymlInstalls and configures Apache and PHP for the Zabbix frontend, ensuring all necessary services are started and enabled.

Prerequisites

Before we begin, ensure you have the following:

  • Two Servers/Virtual Machines (VMs): We recommend at least two servers to follow along with this article.
  • Sudo Admin Privileges: You will need administrative privileges to perform the installation and configuration steps.
  • Subscription to Red Hat: If you are using RHEL instances, ensure you have an active subscription to access necessary repositories and updates.

For demonstration purposes, we’ve configured our Linux nodes as follows (2 nodes, 1 ansible-ctl, 1 for zabbix install):

HostnamesRAM (GB)CoresOperating System (OS)
ansible-ctl.dev.naijalabs.net42Red Hat Enterprise Linux release 9.4 (Plow)
zbx-node1.dev.naijalabs.net42Red Hat Enterprise Linux release 9.4 (Plow)

Copy and paste the following entries in the /etc/hosts file on each node (replace IP addresses and hostnames with your actual settings):

# Ansible Zabbix Hosts
192.168.1.22  ansible-ctl.dev.naijlabs.net ansible-ctl
192.168.1.218 zbx-node1.dev.naijalabs.net
Automating Zabbix Installations Using Ansible

Photo by admingeek from Infotechys

Automating Zabbix Installations Using Ansible: A Step-by-Step Guide

On your Ansible node, create a directory named ansible and another one named inventory that will house all your inventory files. Then,  navigate into the ansible directory:
$ mkdir -p ansible; mkdir -p inventory; cd ansible

If you don’t already have Ansible installed, install it with the following command:

$ sudo dnf install ansible -y

Then, run the following command to create the directory structure for the ansible-zabbix-install role.

$ ansible-galaxy init ansible-zabbix-install
- Role ansible-zabbix-install was created successfully

Next, run the tree command to view the directory structure:

$ tree
.
└── ansible-zabbix-install
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

9 directories, 8 files

Your directory structure should look similar to the output above. In the next section, we’ll breakdown all of the configuration files belonging to each sub-directory.


Breakdown of Configuration Files

install_zabbix.yml

This playbook is the entry point for the Ansible role ansible-zabbix-install, which sets up Zabbix on all specified hosts.

---
- hosts: all
  become: yes
  roles:
    - ansible-zabbix-install

inventory/zabbix_inventory.yml

Defines the Zabbix nodes and their respective IP addresses.

---
zabbix_nodes:
  hosts:
    zbx-node1.dev.naijalabs.net:
      ansible_host: 192.168.1.218

defaults/main.yml

Contains default variables for the Ansible role, such as Zabbix and RHEL versions, database passwords, and repository URLs.

---
# defaults file for ansible-zabbix-install
playbook_dir: "~/ansible/ansible-zabbix-install"
zabbix_version: 6.4
rhel_version: 9
postgresql_password: postgres
zabbix_db_password: zabbix
zabbix_server_ip: 192.168.1.218
timezone: Etc/UTC
zabbix_repo_url: "https://repo.zabbix.com/zabbix/{{ zabbix_version }}/rhel/{{ rhel_version }}/x86_64/zabbix-release-latest.el{{ rhel_version }}.noarch.rpm"

handlers/main.yml

Defines handlers to restart or reload services when changes occur.

---
# handlers file for ansible-zabbix-install to restart services
- name: Restart Zabbix Server
  systemd:
    name: zabbix-server
    state: restarted

- name: Restart Zabbix Agent
  systemd:
    name: zabbix-agent
    state: restarted

- name: Restart Apache
  systemd:
    name: httpd
    state: restarted

- name: Restart PHP-FPM
  systemd:
    name: php-fpm
    state: restarted

- name: Reload firewalld
  service:
    name: firewalld
    state: reloaded

- name: Reload PostgreSQL
  systemd:
    name: postgresql
    state: reloaded

- name: Restart PostgreSQL
  systemd:
    name: postgresql
    state: restarted

tasks/main.yml

Includes various task files necessary for setting up Zabbix.

---
# tasks file for ansible-zabbix-install
- include_tasks: postgresql.yml
- include_tasks: zabbix.yml
- include_tasks: network.yml
- include_tasks: ssl.yml
- include_tasks: selinux.yml
- include_tasks: frontend.yml

tasks/network.yml

Configures firewall settings and SELinux for Zabbix.

---
# Firewall tasks section
- name: Open necessary firewall ports for Zabbix, PostgreSQL, and Apache
  firewalld:
    port: "{{ item }}"
    permanent: yes
    state: enabled
  with_items:
    - "10050/tcp"  # Zabbix server port
    - "10051/tcp"  # Zabbix server port
    - "5432/tcp"   # PostgreSQL port
    - "443/tcp"    # HTTPS/SSL port for Apache
  notify:
    - Reload firewalld

# SELinux configuration section
- name: Configure SELinux for Zabbix frontend access
  command: setsebool -P httpd_can_network_connect on
  when: ansible_selinux.status == "enabled"

tasks/postgresql.yml

Handles the installation and configuration of PostgreSQL.

---
# Install PostgreSQL
- name: Install PostgreSQL packages
  dnf:
    name:
      - postgresql-server
      - postgresql-contrib
    state: present

# Initialize PostgreSQL database
- name: Initialize PostgreSQL Database
  command: postgresql-setup --initdb
  args:
    creates: /var/lib/pgsql/data/PG_VERSION

# Start and enable PostgreSQL
- name: Start and enable PostgreSQL
  systemd:
    name: postgresql
    state: started
    enabled: yes

# Install Python Pip
- name: Install Python pip
  dnf:
    name: python3-pip
    state: present

# Install Python Library (psycopg2)
- name: Install psycopg2 Python library
  pip:
    name: psycopg2-binary
    state: present

# Set PostgreSQL password for user 'postgres'
- name: Set PostgreSQL password for 'postgres' user
  become_user: postgres
  postgresql_user:
    name: postgres
    password: "{{ postgresql_password }}"

# Ensure PostgreSQL Remote Access
- name: Ensure PostgreSQL Remote Access
  lineinfile:
    path: /var/lib/pgsql/data/postgresql.conf
    regexp: '^#listen_addresses ='
    line: "listen_addresses = '*'"
    backup: yes
    state: present
  notify:
    - Restart PostgreSQL

tasks/selinux.yml

Configures SELinux policies for Zabbix.

---
- name: Install SELinux policy utilities
  dnf:
    name: policycoreutils-python-utils
    state: present
  become: yes

- name: Create custom SELinux module file for PHP PCRE JIT
  copy:
    dest: /tmp/php_jit.te
    content: |
      module php_jit 1.0;

      require {
          type httpd_t;
          class process execmem;
      }

      # Allow PHP to allocate executable memory
      allow httpd_t self:process execmem;

- name: Compile the custom SELinux module
  shell: |
    checkmodule -M -m -o /tmp/php_jit.mod /tmp/php_jit.te
    semodule_package -o /tmp/php_jit.pp -m /tmp/php_jit.mod
    semodule -i /tmp/php_jit.pp
  args:
    creates: /tmp/php_jit.pp

tasks/zabbix.yml

Installs and configures Zabbix server, frontend, and agent.

---
# Disable EPEL repository if it exists
- name: Remove epel-release package if it exists
  ansible.builtin.package:
    name: epel-release
    state: absent
  ignore_errors: yes

# Install Zabbix repository
- name: Install Zabbix repository
  dnf:
    name: "{{ zabbix_repo_url }}"
    state: present
    disable_gpg_check: yes

# Install Zabbix server, frontend, agent, and dependencies
- name: Install Zabbix server, frontend, and agent packages
  dnf:
    name:
      - zabbix-server-pgsql
      - zabbix-web-pgsql
      - zabbix-web
      - zabbix-web-deps
      - zabbix-sql-scripts
      - zabbix-selinux-policy
      - zabbix-apache-conf
      - zabbix-agent
    state: present

# Create Zabbix database and user
- name: Create Zabbix user in PostgreSQL
  become_user: postgres
  postgresql_user:
    name: zabbix
    password: "{{ zabbix_db_password }}"
    state: present

- name: Create Zabbix database
  become_user: postgres
  postgresql_db:
    name: zabbix
    owner: zabbix

- name: Grant privileges to Zabbix database
  become_user: postgres
  postgresql_query:
    db: zabbix
    query: "GRANT ALL PRIVILEGES ON DATABASE zabbix TO zabbix;"

# Import Zabbix schema
- name: Import Zabbix schema into PostgreSQL
  ansible.builtin.shell: |
    zcat /usr/share/zabbix-sql-scripts/postgresql/server.sql.gz | sudo -u zabbix psql zabbix
  changed_when: false

- name: Update Zabbix Server Configuration with Database Credentials
  blockinfile:
    path: /etc/zabbix/zabbix_server.conf
    marker: "# {mark} MANAGED BLOCK"
    block: |
      DBPassword={{ zabbix_db_password }}
    state: present

# Configure PostgreSQL to Allow Database Connections
- name: Modify PostgreSQL configuration for Zabbix
  ansible.builtin.shell: |
    sed -i 's/ident/md5/' /var/lib/pgsql/data/pg_hba.conf
  changed_when: false

# Configure PostgreSQL to Allow Database Connections
- name: Ensure pg_hba.conf allows connections from localhost
  lineinfile:
    path: /var/lib/pgsql/data/pg_hba.conf
    regexp: '^host\s+zabbix\s+zabbix\s+127.0.0.1/32\s+md5'
    line: 'host    zabbix          zabbix          127.0.0.1/32            md5'
    state: present
  notify: Reload PostgreSQL

tasks/ssl.yml

Handles the creation of SSL directories and self-signed certificates.

---
- name: Ensure SSL directories exist
  file:
    path: "{{ item }}"
    state: directory
    mode: '0700'
  with_items:
    - /etc/pki/tls/private
    - /etc/pki/tls/certs

- name: Check if SSL key exists
  stat:
    path: /etc/pki/tls/private/self_signed.key
  register: ssl_key_stat

- name: Check if SSL certificate exists
  stat:
    path: /etc/pki/tls/certs/self_signed.crt
  register: ssl_crt_stat

- name: Generate self-signed SSL certificate if cert and key don't exist
  command: openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/pki/tls/private/self_signed.key -out /etc/pki/tls/certs/self_signed.crt -subj "/C=US/ST=State/L=City/O=Organization/OU=OrgUnit/CN=localhost"
  when: not (ssl_key_stat.stat.exists and ssl_crt_stat.stat.exists)

- name: Output a message if the SSL certificate and key already exist
  debug:
    msg: "SSL certificate and key already exist; skipping generation."
  when: ssl_key_stat.stat.exists and ssl_crt_stat.stat.exists

tasks/frontend.yml

Installs Apache and PHP, and configures them for Zabbix.

---
# Install Apache and PHP
- name: Install Apache and PHP packages
  dnf:
    name:
      - httpd
      - php
      - php-pgsql
      - mod_ssl
    state: present

# Start and enable Apache and PHP services
- name: Start and enable Apache and PHP-FPM services
  systemd:
    name: "{{ item }}"
    state: started
    enabled: yes
  loop:
    - httpd
    - php-fpm

# Update Zabbix.conf for PHP-FPM
- name: Update Zabbix Configuration for PHP-FPM
  lineinfile:
    path: /etc/php-fpm.d/zabbix.conf
    regexp: '^php_value\[date.timezone\]'
    line: 'php_value[date.timezone] = {{ timezone }}'
    state: present

# Configure PHP timezone for Zabbix
- name: Configure PHP timezone for Zabbix
  template:
    src: php.ini.j2
    dest: /etc/php.ini
  notify: Restart PHP-FPM

# Ensure all Zabbix Services are Started and Enabled
- name: Ensure all Zabbix Services are Started and Enabled
  ansible.builtin.shell: |
    systemctl enable --now zabbix-server zabbix-agent httpd php-fpm
  changed_when: false

Breakdown of Jinja2 Template Files

Jinja2 is a powerful templating engine that allows users to create dynamic configuration files by incorporating variables, control structures (like loops and conditionals), and filters. These templates enable the generation of customized content based on the specific needs of the deployment environment. When processed, the placeholders in the .j2 files are replaced with actual values, resulting in fully formed configuration files that can be deployed to servers. This approach enhances flexibility and maintainability in configuration management.

templates/php.ini.j2

Configures time zone settings for PHP.

[Date]
date.timezone = {{ timezone }}

Automating Zabbix Installations Using Ansible: Playbook Execution

Having reviewed each configuration file in the ansible-zabbix-install role, we are now prepared to run the playbook. It’s advisable to perform a dry run first to ensure everything is set up correctly before executing it for real.
$ ansible-playbook -i ~/ansible/inventory/zabbix_inventory.yml ~/ansible/install_zabbix.yml -K --check
BECOME password:

Enter your sudo credentials to continue:

Automating Zabbix Installations Using Ansible

Photo by admingeek from Infotechys

If the playbook run completes without errors or failed tasks, run it again for real without the --check option.

Verify the Deployment

After execution, verify the Zabbix setup by accessing the web interface at:  https://<zabbix_server_ip>/zabbix

Automating Zabbix Installations Using Ansible

Photo by admingeek from Infotechys

Finally, log on to the Zabbix frontend using the default credentials:

  • Username: Admin
  • Password: zabbix

Quick Tips & Command-Line (CLI) Examples

Here are a few more Ansible CLI examples:  

Check Ansible Version:

$ ansible --version

List Available Hosts:

$ ansible-inventory --list -i inventory/zabbix_inventory.yml

Run the Playbook with Verbose Output:

$ ansible-playbook -i inventory/zabbix_inventory.yml install_zabbix.yml -K -v

No comments:

Post a Comment

HTTP Appache Server LAB 7

 Apache HTTP Server (httpd) Configuration,