Translate

понеділок, 7 березня 2016 р.

Puppet Masterless Setup. Heartbeat Configuration


Puppet - це одна із найбільш популярних систем управління конфігурацією. Декілька років тому я вже описував її основні ідеї, а цього разу розповім про masterless-конфігурацію та, як приклад її роботи, продемонструю налаштування та роботу кластеру Heartbeat.

Якщо ви лише плануєте використовувати подібні системи - то раджу звернути увагу на Ansible. Він більш дружній до початківців, має менше недоліків та і може виконувати ту ж роботу з аналогічним успіхом.

Класична система роботи Puppet - клієнт-серверна (standalone). Певні проміжки часу (по замовчуванню кожні 30 хвилин) Puppet-клієнт запитує дані щодо власної конфігурації в Puppet-сервера, сервер компілює їх в проміжний результат та віддає клієнту. Вузьке місце такої системи - це сам Puppet-сервер: у разі виходу його із ладу, одразу всі клієнти не зможуть отримати зміни конфігурації. Також з часом ймовірно необхідно буде масштабувати сервер, адже потужностей сервера може бути недостатньо.

Тож задля підвищення рівня доступності варто звернути увагу на інший варіант роботи Puppet - masterless, тобто архітектуру без Puppet-сервера. У такому разі всі файли конфігурації будуть зберігатись в репозиторії, а кожен клієнт певні проміжки часу буде запитувати зміни з репозиторію і локально їх застосовувати. У якості репозиторію модулів/маніфестів Puppet краще всього підійдуть системи контролю версій, наприклад Git.

Перейдемо до суті. Як я вже говорив розбиратись із masterless конфігурацією ми будемо на прикладі автоматичної конфігурації Heartbeat. Це можливо не найтривіальніший приклад, проте досить цікавий. Суть роботи Heartbeat полягає в міграції (переміщенні) IP адреси з непрацюючого серверу кластера на працюючий і, таким чином, підвищувати рівень доступності. З деталями використання Heartbeat можна ознайомитись на офіційній сторінці проекту:

http://www.linux-ha.org/doc/users-guide/users-guide.html

Про щось подібне я також вже писав раніше. Для конфігурації Heartbeat кластеру необхідно як мінімум дві ноди та 3 вільні IP-адреси однієї мережі. У якості ОС я обрав Ubuntu 14.04, а серверам призначив такі адреси та хостнейми:

192.168.1.21 - hb1.me
192.168.1.22 - hb2.me

192.168.1.20 - віртуальний IP (VIP), що буде мігрувати на робочу ноду у разі падіння попередньої.

Отже, очевидно, перше, що необхідно зробити - це встановити puppet на кожний із перерахованих вузлів. Для установки скористаємось офіційними репозиторіями, що додаються після установки пакету від PuppetLabs:

# cd /tmp
# wget http://apt.puppetlabs.com/puppetlabs-release-trusty.deb
# dpkg -i puppetlabs-release-trusty.deb

# apt-get update
# apt-get install puppet git-core

Виконаємо базову конфігурацію Puppet сервісу. Видалимо параметр templatedir та все, що відноситься до секції [master]. В результаті /etc/puppet/puppet.conf має виглядати наступним чином:

# vim /etc/puppet/puppet.conf

[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$confdir/facter

Створимо новий модуль cron-puppet:

# cd /etc/puppet/modules
# mkdir -p cron-puppet/manifests cron-puppet/files

Новий модуль буде відповідати за створення post-merge скрипта та установку cron-задачі з отриманням оновлень з віддаленого репозиторію, що буде запускатись кожні 15 хвилин:

# vim cron-puppet/manifests/init.pp

class cron-puppet {
    file { 'post-hook':
        ensure  => file,
        path    => '/etc/puppet/.git/hooks/post-merge',
        source  => 'puppet:///modules/cron-puppet/post-merge',
        mode    => 0755,
        owner   => ubuntu,
        group   => ubuntu,
    }

    cron { 'puppet-apply':
        ensure  => present,
        command => "cd /etc/puppet ; /usr/bin/git pull",
        user    => ubuntu,
        minute  => '*/15',
        require => File['post-hook'],
    }
}

post-merge скрипт буде виконуватись лише у разі виникнення нових змін у віддаленому репозиторії.

# vim cron-puppet/files/post-merge

#!/bin/bash -e
## Run Puppet locally using puppet apply
/usr/bin/sudo /usr/bin/puppet apply /etc/puppet/manifests/site.pp

## Log status of the Puppet run
if [ $? -eq 0 ]
then
    /usr/bin/sudo /usr/bin/logger -i "Puppet has run successfully" -t "puppet-run"
    exit 0
else
    /usr/bin/sudo /usr/bin/logger -i "Puppet has ran into an error, please run Puppet manually" -t "puppet-run"
    exit 1
fi

Створимо другий модуль, що безпосередньо стосується наших планів, - heartbeat:

# cd /etc/puppet/modules
# mkdir -p heartbeat/manifests heartbeat/templates

Файл ініціалізації модулю має наступний вигляд:

# vim heartbear/manifests/init.pp

# Manage Heartbeat
class heartbeat {

    package { 'heartbeat':
        ensure => installed,
    }

    service {'heartbeat':
        ensure  => running,
        enable  => true,
        require => Package['heartbeat'],
    }

    exec { 'reload-heartbeat':
        command     => '/usr/sbin/service heartbeat reload',
        refreshonly => true,
    }

    file { '/etc/ha.d/authkeys':
        content => "auth 1\n1 sha1 TopSecret",
        mode    => '0600',
        require => Package['heartbeat'],
        notify  => Exec['reload-heartbeat'],
    }
}

Тож спочатку буде встановлено пакет heartbeat, сервіс якого буде додано в автозавантаження у разі, коли пакет присутній (require => Package['heartbeat']). Далі, якщо пакет heartbeat установлено, відбудеться створення файлу /etc/ha.d/authkeys з даними необхідними для авторизації вузла в кластері. Щоразу при зміні цього файлу  буде виконаний ресурс reload-heartbeat, що відповідно призведе до перевантаження heartbeat сервісу (notify  => Exec['reload-heartbeat']). refreshonly вказує, що ресурс можна виконати лише звернувшись через notify іншого ресурсу.

Створимо інший маніфест vip.pp для цього ж модуля:

# vim heartbear/manifests/vip.pp

# Manage a specific VIP with Heartbeat
class heartbeat::vip($node1,$node2,$ip1,$ip2,$vip,$interface='eth0:1') {

    include heartbeat

    file { '/etc/ha.d/haresources':
        content => "${node1} IPaddr::${vip}/${interface}\n",
        notify  => Exec['reload-heartbeat'],
        require => Package['heartbeat'],
    }

    file { '/etc/ha.d/ha.cf':
        content => template('heartbeat/vip.ha.cf.erb'),
        notify  => Exec['reload-heartbeat'],
        require => Package['heartbeat'],
    }
}

Ці ж інструкції можна було б включити в init.pp, проте для зручності ми винесли їх окремо. Клас для роботи потребує хостнейм кожного майбутнього вузла кластеру, IP для кожного вузла відповідно та віртуальний IP, що матиме можливість мігрувати. Для параметра $interface вже одразу вказано значення по-замовчуванню, проте воно може бути змінене при виконанні класу.

vip.pp включає в себе клас heartbeat (include heartbeat, тобто все що описано в init.pp). Потім створюється файл /etc/ha.d/haresources з вмістом, що зазначений у параметрі content. Для роботи ресурсу file { '/etc/ha.d/haresources'...} необхідно наявність уже установленого пакету heartbeat. З кожною зміною файлу /etc/ha.d/haresources буде викликатись перевантаження сервісу heartbeat (notify  => Exec['reload-heartbeat']).

Ресурс file { '/etc/ha.d/ha.cf':...} працює за подібною логікою. Він створює конфігураційний файл /etc/ha.d/ha.cf, використовуючи шаблон, що має наступний вигляд:

# vim heartbear/templates/vip.ha.cf.erb

use_logd yes
udpport 694
autojoin none
ucast eth0 <%= @ip1 %>
ucast eth0 <%= @ip2 %>
keepalive 1
deadtime 10
warntime 5
auto_failback off
node <%= @node1 %>
node <%= @node2 %>

Змінні ip1, ip2, node1, node2, як я вже говорив, передаються параметрами до класу heartbeat::vip.

Підключимо ці 2 класи до новостворених нод в site.pp:

# vim /etc/puppet/manifests/site.pp

node 'hb1'{
    include cron-puppet
    class { 'heartbeat::vip':
        ip1   => '192.168.1.21',
        ip2   => '192.168.1.22',
        node1 => 'hb1.me',
        node2 => 'hb2.me',
        vip   => '192.168.1.20/24',
    }
}

node 'hb2'{
    include cron-puppet
    class { 'heartbeat::vip':
        ip1   => '192.168.1.21',
        ip2   => '192.168.1.22',
        node1 => 'hb1.me',
        node2 => 'hb2.me',
        vip   => '192.168.1.20/24',
    }
}

Кінцева структура директорія Puppet виглядає наступним чином:

# tree .
.
├── environments
│   └── example_env
│       └── README.environment
├── manifests
│   └── site.pp
├── modules
│   ├── cron-puppet
│   │   ├── files
│   │   │   └── post-merge
│   │   └── manifests
│   │       └── init.pp
│   └── heartbeat
│       ├── manifests
│       │   ├── init.pp
│       │   └── vip.pp
│       └── templates
│           └── vip.ha.cf.erb
├── puppet.conf
└── README.md

10 directories, 9 files

Наразі створимо Git-репозиторій, в якому будемо зберігати всі модулі та маніфести. Процедура його створення може бути різною. Наприклад, якщо провайдером репозиторію є Github, необхідно попередньо створити сам репозиторій в межах свого акаунту та прив'язати свій публічний ключ в налаштуваннях. Припустимо, що посилання на репозиторій, яку видав Github - github.com:ipeacocks/puppet-modules.git. Далі ініціюємо локальний репозиторій

# echo "# puppet-modules" >> README.md
# git init
# git add README.md
# git commit -m "first commit"

Та заливаємо всі створені вище модулі:

# git remote add origin git@github.com:ipeacocks/puppet-modules.git
# git push -u origin master

Нагадаю, що публічні репозиторії зовсім не місце для паролів та інших ключів авторизації.

Задеплоїмо всі ці налаштування на кожний вузол Heartbeat кластеру (hb1.me та hb2.me), попередньо зайшовши на кожен сервер по ssh:

# cd /etc
# sudo mv puppet/ puppet-bak
# git clone https://github.com/ipeacocks/puppet-modules.git /etc/puppet

Ліпше за все вузлам надати право лише читати репозиторій, без можливості вносити і комітити зміни. Це стандартне поводження Github репозиторію через https: задля виконання push Github буде вимагати пароль/логін.

Щоб додати Puppet в cron для автоматичного виконання кожні 15 хвилин, спершу необхідно запустити puppet вручну на кожному з вузлів:

# sudo puppet apply /etc/puppet/manifests/site.pp

У моєму випадку для користувача ubuntu запуск команд від sudo можливий без паролю.

Отже, перевіримо інтерфейси на кожному із вузлів після запуску puppet:

ubuntu@hb1:/etc/puppet$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:b1:ac:04 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.21/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.1.20/24 brd 192.168.1.255 scope global secondary eth0:0
       valid_lft forever preferred_lft forever

ubuntu@hb2:/etc/puppet$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:57:32:0f brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.22/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever

З виводу видно, що віртуальний IP прив'язаний до першого серверу кластера. Відповідно, у разі втрати зв'язку з ним, віртуальний IP мігрує на сервер hb2.me.

У наступній статті я розповім про установку та налаштування Foreman, панелі адміністрування Puppet.

Посилання:
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-masterless-puppet-environment-on-ubuntu-14-04
https://www.packtpub.com/networking-and-servers/puppet-3-cookbook
https://www.digitalocean.com/community/tutorials/how-to-install-puppet-to-manage-your-server-infrastructure
http://www.example42.com/tutorials/PuppetTutorial/

Немає коментарів:

Дописати коментар