Привет всем, возможно вы читали прошлый пост об использовании puppet. И там в качестве первого примера мы писали модуль, который ставит zabbix-агентов на хосты.
Там есть нюанс, этот модуль будет работать только с rhel-based операционными системами, а что если у нас огород из Debian/Ubuntu и Rhel? - Для решения этой задачи модифицируем ранее написанный модуль, добавим так сказать кроссплатформености.
Готовим новый хост
Для тестов, к текущей инфраструктуре добавил новую ноду на ubuntu22.04 (puppet-node03). Подготовим новую ноду, и заинставим на нее puppet-агента.
Сначала подключаем репозиторий puppet:
sadmin@puppet-node03:~$ wget https://apt.puppetlabs.com/puppet8-release-jammy.deb
sadmin@puppet-node03:~$ sudo dpkg -i puppet8-release-jammy.deb
Ну с ставим puppet-агента:
sadmin@puppet-node03:~$ sudo apt-get update && sudo apt-get install puppet-agent
В конфигурационном файле puppet-агента, добавляем настройки для подключения к серверу:
sadmin@puppet-node03:~$ sudo vim /etc/puppetlabs/puppet/puppet.conf
---
[main]
server = puppet-master.nixhub.ru
certname = puppet-node03.nixhub.ru
runinterval = 30
Ну и запускаем агента:
sadmin@puppet-node03:~$ sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
---
Notice: /Service[puppet]/ensure: ensure changed 'stopped' to 'running'
service { 'puppet':
ensure => 'running',
enable => 'true',
provider => 'systemd',
}
Подключаемся на puppet-server, и подписываем сертификат нового puppet-клиента:
[root@puppet-master ~]# puppetserver ca sign --certname puppet-node03.nixhub.ru
---
Successfully signed certificate request for puppet-node03.nixhub.ru
Модифицируем модуль (Первый способ)
Итак, теперь в подчинении у puppet два сервера на AlmaLinux и один сервер на Ubuntu. Модифицируем модуль установки zabbix-agent. Состав модуля такой:
[root@puppet-master production]# tree
.
|-- data
|-- environment.conf
|-- hiera.yaml
|-- manifests
| `-- site.pp
`-- modules
`-- setup_zbx_agent
|-- files
| `-- zabbix.repo
|-- manifests
| |-- init.pp
| `-- install.pp
`-- templates
`-- zabbix_agentd.erb
В манифестах у нас имеется две инструкции, первое описание устанавливаем zabbix-агента, второй манифест применяет конфигурацию агента. Разобьем задачу по установке на два манифеста:
|-- manifests
|-- install_debian.pp
|-- install_redhat.pp
В соответсвии с названием, каждый из манифестов будет ставить агента на соответствующую OS.
Манифест для Debian-совместимых
Добавим новый шаблон, из которого будет собиратся файл репозитория для ubuntu. Создаем новый шаблон:
[root@puppet-master production]# vim modules/setup_zbx_agent/templates/zabbix_ubuntu_repo.erb
---
# Zabbix main repository
deb https://repo.zabbix.com/zabbix/6.0/ubuntu <%= @release_name %> main
deb-src https://repo.zabbix.com/zabbix/6.0/ubuntu <%= @release_name %> main
В значение переменной @release_name
, будет подставляется имя релиза.
Затем собираем все вместе в файле - install_debian.pp
:
[root@puppet-master production]# vim modules/setup_zbx_agent/manifests/install_debian.pp
--
class setup_zbx_agent::install_debian (
$zbx_package = 'zabbix-agent',
$zbx_listen_port = 10050,
$release_name = "${facts['os']['distro']['codename']}"
) {
file { '/etc/apt/sources.list.d/zabbix.list':
content => template('setup_zbx_agent/zabbix_ubuntu_repo.erb'),
}
package { "$zbx_package":
ensure => 'present',
require => File['/etc/apt/sources.list.d/zabbix.list'],
}
exec { 'ufw':
path => '/bin/',
command => "ufw allow ${zbx_listen_port}",
require => Package["$zbx_package"],
}
}
В этом классе, ресурс file
из шаблона zabbix_ubuntu_repo.erb
собирает репозиторий zabbix. В шаблон подставляется значение из переменной, кодовое слово релиза ubuntu. Затем через ресурс package
ставится пакет zabbix-agent. Ну и в конце через exec
, добавляется порт на фаерволе. Обратите внимание, что каждый ресурс зависим от предыдущего.
Манифест для rhel-совместимых
Пишем второй манифест для rhel совместимых:
[root@puppet-master production]# vim modules/setup_zbx_agent/manifests/install_redhat.pp
---
class setup_zbx_agent::install_redhat (
$zbx_package = 'zabbix-agent',
$zbx_listen_port = 10050,
){
file { '/etc/yum.repos.d/zabbix.repo':
ensure => 'present',
source => "puppet:///modules/setup_zbx_agent/zabbix.repo",
}
package { "$zbx_package":
ensure => 'present',
require => File['/etc/yum.repos.d/zabbix.repo'],
}
exec { 'firewall':
path => '/bin/',
command => "firewall-cmd --add-port=${zbx_listen_port}/tcp --permanent && firewall-cmd --reload",
onlyif => "firewall-cmd --list-all | grep 10050 >/dev/null && echo False || echo True",
require => Package["$zbx_package"],
}
}
Этот класс аналогично делает все тоже самое. За исключением файла репозитория, репозиторий просто копируется из файлов.
Обновляем init.pp
Модифицируем файл манифеста init.pp
:
[root@puppet-master production]# cat modules/setup_zbx_agent/manifests/init.pp
---
class setup_zbx_agent (
$zbx_server = 'localhost',
$zbx_host = "${facts['networking']['fqdn']}",
){
case $facts['os']['family'] {
'Debian': {
class {'setup_zbx_agent::install_debian':}
}
'RedHat': {
class {'setup_zbx_agent::install_redhat':}
}
}
file { '/etc/zabbix/zabbix_agentd.conf':
content => template('setup_zbx_agent/zabbix_agentd.erb'),
owner => 'zabbix',
group => 'zabbix',
}
service { 'zabbix-agent':
ensure => 'running',
subscribe => File['/etc/zabbix/zabbix_agentd.conf']
}
}
Здесь добавляем выражение case
, в условии которого из фактов попадает значение с семейством дистрибутива (Debian или Redhat). Затем в зависимости от значения, инключится нужный манифест.
После установки, собирается из шаблона файл конфигурации агента и перезапускается служба.
Модифицируем модуль (Второй способ, через параметры)
На мой взгляд второй способ мне показался более локаничный, и меньше повторяющего кода. Файл репозитория для rhel-совместимых операционок я перенес в шаблоны, но какие либо переменные не включал в его состав. B теперь каталог с шаблонами выглядит так:
`-- templates
|-- zabbix_agentd.erb
|-- zabbix_rhel_repo.erb
`-- zabbix_ubuntu_repo.erb
zabbix_agentd.erb
- шаблон для заббикс-агента;zabbix_rhel_repo.erb
- шаблон файла репозитория для rhel-дистрибутивов;zabbix_ubuntu_repo.erb
- шаблон файла репозитория для ubuntu совместимых.
Меняем init.pp
Менять модуль начнем в обратно последовательности, и сначала поменять init.pp
:
[root@puppet-master manifests]# vim init.pp
---
class setup_zbx_agent (
# Zabbix agent package:
$zbx_package = $setup_zbx_agent::params::zbx_params,
# Zabbix config parameters:
$zbx_server = $setup_zbx_agent::params::zbx_server,
$zbx_port = $setup_zbx_agent::params::zbx_port,
$zbx_host = $setup_zbx_agent::params::zbx_host,
# Zabbix repo path:
$zbx_repo_path = $setup_zbx_agent::params::zbx_repo_path,
$zbx_repo_temp = $setup_zbx_agent::params::zbx_repo_temp,
# Host firewall settings:
$fwd_type = $setup_zbx_agent::params::fwd_type,
$fwd_command = $setup_zbx_agent::params::fwd_command,
$fwd_command_path = $setup_zbx_agent::params::fwd_command_path,
) inherits setup_zbx_agent::params {
class {'setup_zbx_agent::install':} ->
class {'setup_zbx_agent::configure':}
}
Описание класса setup_zbx_agent
, мы начинаем с объявления переменных. Значения этих переменных будут взяты из другого манифеста (params), который мы напишем позже. Для указания ссылки на переменную в другом манифесте используется такой синтаксис:
<имя_модуля>::<имя_манифеста>::<имя_переменной>
В данном классе используются переменные:
$zbx_package
- имя пакета zabbix-агента;$zbx_server
,$zbx_port
,$zbx_host
- в этих переменных будут содержаться данные ip zabbix-сервера, затем имя хоста и порт на котором будет запускаться агент.$zbx_repo_path
- в значение этой переменной мы помещаем путь, по которому будет создаваться файл репозитория на хостах.$zbx_repo_temp
- здесь в значение помещаем имя шаблона, который будет использоваться.$fwd_type
,$fwd_command
,$fwd_command_path
- а значениях этих переменных кладем тип используемого фаервола (Например: ufw или firewalld). Так как правило в фаере добавляем через ресурсexec
, соответственно в переменной$fwd_command
- shell команда на добавление правила. В последней переменной путь к утилите.
Так скажем контекст исполнения, начинается с указания наследования класса -> inherits setup_zbx_agent::params
. И в самом контексте включены два других манифеста.
setup_zbx_agent::install
- в этот манифест вынесены все ресурсы по установке zabbix-агента,setup_zbx_agent::configure
- тут перечеслены ресурсы по конфигурации агента.
Оператор ->
между классами, говорит нам о том, что перед выполнением класса setup_zbx_agent::configure
, сначала будет выполнен класс setup_zbx_agent::install
.
Пишем манифест с параметрами
Далее логичнее будет описать класс с параметрами:
[root@puppet-master manifests]# vun params.pp
---
class setup_zbx_agent::params {
$zbx_package = 'zabbix-agent'
$zbx_server = 'localhost'
$zbx_port = '10050'
$zbx_host = "${facts['networking']['fqdn']}"
$release_name = "${facts['os']['distro']['codename']}"
case "${facts['os']['family']}" {
'Debian': {
$zbx_repo_temp = 'zabbix_ubuntu_repo'
$zbx_repo_path = '/etc/apt/sources.list.d/zabbix.list'
$fwd_type = "ufw"
$fwd_command = "ufw allow ${zbx_port}"
$fwd_command_pre = ""
$fwd_command_path = "/usr/sbin/"
}
'RedHat': {
$zbx_repo_temp = 'zabbix_rhel_repo'
$zbx_repo_path = '/etc/yum.repos.d/zabbix.repo'
$fwd_type = "firewalld"
$fwd_command = "firewall-cmd --add-port=${zbx_port}/tcp --permanent && firewall-cmd --reload"
$fwd_command_pre = ''
$fwd_command_path = "/bin/"
}
}
}
По сути в этом классе описываются только переменные. Вначале идут, так скажем, общие переменные. Далее уже знакомое нам выражение case
, в зависимости от семейства операционных систем будет выполняться условие и определятся группа других переменных.
Отдельные классы install/configure
Пишем манифест на установку агента:
[root@puppet-master manifests]# vim install.pp
---
class setup_zbx_agent::install {
file { $setup_zbx_agent::zbx_repo_path:
content => template("setup_zbx_agent/${setup_zbx_agent::zbx_repo_temp}.erb")
}
package { "$setup_zbx_agent::zbx_package":
ensure => 'present',
require => File["${setup_zbx_agent::zbx_repo_path}"],
}
exec { "$setup_zbx_agent::fwd_type":
path => "${setup_zbx_agent::fwd_command_path}",
command => "${setup_zbx_agent::fwd_command}",
require => Package["${setup_zbx_agent::zbx_package}"],
}
}
В этом классе содержатся знакомые нам ресурсы:
file
- на создание файла репозитория из шаблона,package
- для установки пакета,exec
- для выполнения команды на добавления правила в firewall. Атрибуты к ресурсам строятся из импортированных переменных главного класса.
И наконец напишем манифест, на конфигурирование агента:
class setup_zbx_agent::configure {
file { '/etc/zabbix/zabbix_agentd.conf':
content => template('setup_zbx_agent/zabbix_agentd.erb'),
owner => 'zabbix',
group => 'zabbix',
}
service { 'zabbix-agent':
ensure => 'running',
subscribe => File['/etc/zabbix/zabbix_agentd.conf']
}
}
Тут нечего не поменялось, также собирается конфиг агента, и перезапускается служба.
Обновляем шаблоны
Шаблоны тоже притерпели изменения, к сожалению простое указание переменных через стандартный оператор не привело к успеху.
[root@puppet-master manifests]# cat ../templates/zabbix_agentd.erb
---
# --
# Managment via Puppet
# --
# Pid location
PidFile=/var/run/zabbix/zabbix_agentd.pid
# Log's patametres
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
# Zabbix-server hostname/ip
Server=<%= scope.lookupvar("setup_zbx_agent::zbx_server") %>
ServerActive=<%= scope.lookupvar("setup_zbx_agent::zbx_server") %>
# Zabbix-agent hostname
Hostname=<%= scope.lookupvar("setup_zbx_agent::zbx_host") %>
# Includes extentions:
Include=/etc/zabbix/zabbix_agentd.d/*.conf
В ответах на stack overflow нашел метод указания переменных в шаблоне через вызов метода - scope.lookupvar()
, который предопределяет область видимости. И это сработало.
Итак мы попробовали оба метода, вариант со вторым методом выложу в Gitlab.