Вернёмся к нашим баранам. В прошлой статье мы представили, что у нас есть 2 физических сервера и поставили на них puppetmaster и puppetdb. В этой статье, попробуем так же по-пацански (aka best practice) правильно настроить hiera, “напишем” наш первый модуль и установим нормальный из реп форджа. Ну, поехали…
Теория
Что такое hiera? Это просто структурирование хранилище key/value в текстовом виде в файлах. Чтоб не расплываться в воде красивых и бесполезных слов теории как это любят делать разработчики в своей документации, скажу лишь, что мы будет использовать её для объявления классов в пределах хостов (нод, на языке puppet) и передачи чего-либо в переменные для этих классов. Кто мало-мальски знаком с программированием поймёт о чём речь.
Зачем нам нужны модули и при чём они тут вообще? По-сути, грубо говоря, модуль – это просто класс которым удобно управлять с точки зрения разработчика. Вообще классы можно писать в любой точке любого манифеста и объявлять их там же, но это вносит путаницу. Ну и так просто “правильно” по мнению разработчиков puppet, по-этому будем делать именно так. Например, puppetdb который мы ставили в прошлой статье, это тоже всего лишь модуль содержащий один одноимённый класс с кучей зависимостей, подклассов, функций и т.д.
Вообще, наш puppet-сервис может уже работать и без hiera, все старые его версии именно так и делают, в них hiera выступает не обязательным модулем всего лишь, но с недавних пор она стала обязательной части puppet’a. Ну ок, пусть будет обязательной, раз мы взялись воспроизводить best practice, значит будет делать от и до, чтоб по-пацански. Вот как в итоге всё будет работать.
Практика
Запускаем наши хосты puppet и puppetdb. По возможности обновляем их (Обновлять свои сервера лучше вообще как можно чаще. Мы противники устаревшего софта. Фу-фу-фу) и проверяем что наши демоны успешно стартовали.
puppet # ps ax | grep pupp 804 ? Ssl 2:34 /usr/bin/java -Xms4g -Xmx4g -XX:MaxPermSize=1g -XX:OnOutOfMemoryError=kill -9 %p -Djava.security.egd=/dev/urandom -cp /opt/puppetlabs/server/apps/puppetserver/puppet-server-release.jar clojure.main -m puppetlabs.trapperkeeper.main --config /etc/puppetlabs/puppetserver/conf.d -b /etc/puppetlabs/puppetserver/bootstrap.cfg 11088 pts/2 S+ 0:00 grep --color=auto pupp puppetdb # ps ax | grep pupp 822 ? Ssl 1:53 /usr/bin/java -Xmx2g -XX:OnOutOfMemoryError=kill -9 %p -Djava.security.egd=/dev/urandom -cp /opt/puppetlabs/server/apps/puppetdbpuppetdb.jar clojure.main -m puppetlabs.puppetdb.main --config /etc/puppetlabs/puppetdb/conf.d -b /etc/puppetlabs/puppetdb/bootstrap.cfg 5823 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53518) idle 5825 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53520) idle 5826 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53522) idle 5827 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53524) idle 5828 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53526) idle 5829 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53528) idle 5830 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53530) idle 5831 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53532) idle 5832 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53534) idle 5840 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53536) idle 5842 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53538) idle 5843 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53540) idle 5844 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53542) idle 5845 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53544) idle 5846 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53546) idle 5847 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53548) idle 5848 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53550) idle 5849 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53552) idle 5850 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53554) idle 5858 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53556) idle 5860 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53558) idle 5861 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53560) idle 5862 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53562) idle 5863 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53564) idle 5864 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53566) idle 5865 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53568) idle 5866 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53570) idle 5867 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53572) idle 5868 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53574) idle 5869 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53576) idle 5870 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53578) idle 5871 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53580) idle 5872 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53582) idle 5873 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53584) idle 5884 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53586) idle 5885 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53588) idle 5886 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53590) idle 5887 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53592) idle 5888 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53594) idle 5889 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53596) idle 5890 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53598) idle 5891 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53600) idle 5892 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53602) idle 5893 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53604) idle 5894 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53606) idle 5895 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53608) idle 5902 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53610) idle 5904 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53612) idle 5905 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53614) idle 5906 ? Ss 0:00 postgres: puppetdb puppetdb 192.168.0.2(53616) idle 5934 pts/0 S+ 0:00 grep --color=auto pupp
Можно ещё логи почитать для верности, но мне лень, я уверен у нас всё норм.
Приступим. Начнём с простого: Установим какой-нить простенький модуль и заюзаем его на ноде puppetdb с помощью hiera. Модуль поставим как в официальной доке – ntp.
puppet # puppet module install puppetlabs-ntp Notice: Preparing to install into /etc/puppetlabs/code/environments/production/modules ... Notice: Downloading from https://forgeapi.puppetlabs.com ... Notice: Installing -- do not interrupt ... /etc/puppetlabs/code/environments/production/modules L-T puppetlabs-ntp (v4.2.0) L-- puppetlabs-stdlib (v4.11.0)
Смотрим список для пущей убедительности
puppet # puppet module list /etc/puppetlabs/code/environments/production/modules +-- puppetlabs-apt (v2.2.2) +-- puppetlabs-concat (v2.1.0) +-- puppetlabs-firewall (v1.8.0) +-- puppetlabs-inifile (v1.5.0) +-- puppetlabs-ntp (v4.2.0) +-- puppetlabs-postgresql (v4.7.1) +-- puppetlabs-puppetdb (v5.1.2) +-- puppetlabs-stdlib (v4.11.0) /etc/puppetlabs/code/modules (no modules installed) /opt/puppetlabs/puppet/modules (no modules installed)
Отлично! Теперь давайте протестируем наш модуль, но пока без использования hiera, как это делали все нормальные люди раньше.
Создаём файл в котором мы объявим все наши ноды /etc/puppetlabs/code/environments/production/manifests/site.pp если он ещё не был создан. Вообще, название файла роли не играет, по-сути мы создаём обычный манифест, любой манифест помещённый в директорию манифестов будет прочитан и выполнен в рамках текущего environment, но раз уж мы решили следовать букве best practice, будем называть всё своими именами.
Помещаем в него строки:
node 'puppetdb.my.domain' { class { "ntp": servers => [ '0.ru.pool.ntp.org iburst','1.ru.pool.ntp.org iburst','2.ru.pool.ntp.org iburst','3.ru.pool.ntp.org iburst'], autoupdate => false, restrict => [], } }
Всё, с этого момента он вступает в силу, не нужно ничего перезапускать и перечитывать какие-то конфиги. Мастер не запоминает их (манифесты) в память, но обращается к ним в момент обращения клиента к нему.
Запускаем на puppetdb клиент и наблюдаем.
puppetdb # puppet agent --no-daemonize --onetime --verbose Info: Using configured environment 'production' Info: Retrieving pluginfacts Info: Retrieving plugin Info: Loading facts Info: Caching catalog for puppetdb.my.domain Info: Applying configuration version '1467304459' Notice: /Stage[main]/Ntp::Config/File[/etc/ntp.conf]/ensure: defined content as '{md5}30c98a829448d2b680bb48abd595887f' Info: Class[Ntp::Config]: Scheduling refresh of Class[Ntp::Service] Info: Class[Ntp::Service]: Scheduling refresh of Service[ntp] Notice: /Stage[main]/Ntp::Service/Service[ntp]: Triggered 'refresh' from 1 events Notice: Applied catalog in 0.17 seconds
Всё получилось! Удивительно!
Теперь давайте то же самое сделаем при помощи hiera. Для этого правим /etc/puppetlabs/code/hiera.yaml приведя файл к следующему виду
--- :backends: - yaml :yaml: :datadir: "/etc/puppetlabs/code/environments/%{environment}/hieradata" :hierarchy: - "nodes/%{::trusted.certname}" - "nodes/%{::hostname}" - common
Создаём необходимые директории
mkdir -p /etc/puppetlabs/code/environments/production/hieradata/nodes/
Создаём конфиг нашей ноды puppetdb /etc/puppetlabs/code/environments/production/hieradata/nodes/puppetdb.my.domain.yaml и пишем в нём:
# /etc/puppetlabs/code/environments/production/hieradata/nodes/puppetdb.my.domain.yaml --- # Declare our classes classes: ntp # After declare, work with it, we can transfer any var that supports to it ntp::restrict: - ntp::autoupdate: false ntp::enable: true ntp::servers: - 0.jp.pool.ntp.org iburst - 1.jp.pool.ntp.org iburst - 2.jp.pool.ntp.org iburst - 3.jp.pool.ntp.org iburst
Теперь поправим наш /etc/puppetlabs/code/environments/production/manifests/site.pp
node 'puppetdb.my.domain' { hiera_include('classes') }
Сим действом, мы заставляем мастера обращаться к hiera и искать там все значения с ключём classes. Ключ может быть любой, но опять же, совершенно надуманно, разработчики просят называть его именно classes, просто потому что они так захотели… пардон, потому что так правильно. Ну ок, удовлетворим их желание.
Запускаем клиент на puppetdb
puppetdb # puppet agent --no-daemonize --onetime --verbose Info: Using configured environment 'production' Info: Retrieving pluginfacts Info: Retrieving plugin Info: Loading facts Info: Caching catalog for puppetdb.my.domain Info: Applying configuration version '1467305326' Info: Computing checksum on file /etc/ntp.conf Info: /Stage[main]/Ntp::Config/File[/etc/ntp.conf]: Filebucketed /etc/ntp.conf to puppet with sum 30c98a829448d2b680bb48abd595887f Notice: /Stage[main]/Ntp::Config/File[/etc/ntp.conf]/content: content changed '{md5}30c98a829448d2b680bb48abd595887f' to '{md5}f65100dd021d444720d9c0442594c8c8' Info: Class[Ntp::Config]: Scheduling refresh of Class[Ntp::Service] Info: Class[Ntp::Service]: Scheduling refresh of Service[ntp] Notice: /Stage[main]/Ntp::Service/Service[ntp]: Triggered 'refresh' from 1 events Notice: Applied catalog in 0.20 seconds
Смех смехом и кажется что всё очень просто и логично, но это лишь потому, что это объясняю я. Чтоб достичь этого результата я потратил уйму своего времени. Всё потому, что в их дурацкой документации 1000 строк описания того “как это работает” aka теории и 1 строка с примером которую ещё надо найти. Я не разработчик и мне, как быдлоадмину, абсолютно это не интересно и я был бы рад 1000 примерам и одной строке теории, но увы. Ну да ладно, а то чёт у меня бомбить снова начинает…
Следующий наш шаг – напишем какой-нибудь простенький свой модуль, чтоб поместить туда необходимую нам логику. Есть несколько путей: Правильный и Быстрый. При правильном нас учат собирать свой модуль с нуля, упаковывать его, заливать на репу, поддерживать и ставить с помощью module install. Но как мы не девелоперы, а админы всего лишь, так мы выбираем быстрый: “Херак-херак и в продакшн” (с)
Существуют модули глобальные, действующие на все environment’ы, и локальные, соответственно работающие только в том environment’е, в какой вы его установите. Мы будем делать локальный. Создаём директорию содержащую название модуля, у нас он будет называться tm (Сокр. Test Module):
mkdir /etc/puppetlabs/code/environments/production/modules/tm
Очень важна иерархия директорий. Модули подчиняются той же иерархии что и environment’ы – манифесты в manifests, файлы в files, шаблоны в templates и т.п. Нам понадобится только manifests. Создаём её:
mkdir /etc/puppetlabs/code/environments/production/modules/tm/manifests
И помещаем туда наш единственный файлик init.pp содержащий
# Class: tm # class tm ($parameter_one = "default text") { file {'/tmp/test_module': ensure => file, content => $parameter_one, } }
И тут же проверяем наши модули:
puppet # puppet module list /etc/puppetlabs/code/environments/production/modules +-- puppetlabs-apt (v2.2.2) +-- puppetlabs-concat (v2.1.0) +-- puppetlabs-firewall (v1.8.0) +-- puppetlabs-inifile (v1.5.0) +-- puppetlabs-ntp (v4.2.0) +-- puppetlabs-postgresql (v4.7.1) +-- puppetlabs-puppetdb (v5.1.2) +-- puppetlabs-stdlib (v4.11.0) L-- tm (???) /etc/puppetlabs/code/modules (no modules installed) /opt/puppetlabs/puppet/modules (no modules installed)
Видим что у нас появился новый модуль со знаками вопросов в скобках. Это потому что он сделан не очень правильно и не содержит версии, но это не страшно, для тестов самое то.
Переписываем /etc/puppetlabs/code/environments/production/hieradata/nodes/puppetdb.my.domain.yaml
# /etc/puppetlabs/code/environments/production/hieradata/nodes/puppetdb.my.domain.yaml --- # Declare our classes classes: - ntp - tm # After declare, work with it, we can transfer any var that supports to it ntp::restrict: - ntp::autoupdate: false ntp::enable: true ntp::servers: - 0.ch.pool.ntp.org iburst - 1.ch.pool.ntp.org iburst - 2.ch.pool.ntp.org iburst - 3.ch.pool.ntp.org iburst # Here is example our module "Test Module" via /etc/puppetlabs/code/environments/production/modules/tm tm::parameter_one: "There is no other way, and there never was. I lost in this place. Pls, i beg u, help me if u can"
Запускаем клиент на puppetdb
puppetdb # puppet agent --no-daemonize --onetime --verbose Info: Using configured environment 'production' Info: Retrieving pluginfacts Info: Retrieving plugin Info: Loading facts Info: Caching catalog for puppetdb.my.domain Info: Applying configuration version '1467306854' Notice: /Stage[main]/Ntp::Config/File[/etc/ntp.conf]/ensure: defined content as '{md5}f65100dd021d444720d9c0442594c8c8' Info: Class[Ntp::Config]: Scheduling refresh of Class[Ntp::Service] Info: Class[Ntp::Service]: Scheduling refresh of Service[ntp] Notice: /Stage[main]/Ntp::Service/Service[ntp]: Triggered 'refresh' from 1 events Notice: /Stage[main]/Tm/File[/tmp/test_module]/ensure: defined content as '{md5}ef4186a646a01838b0427bdffeae7cc6' Notice: Applied catalog in 0.18 seconds
Похоже что-то получилось. Давайте посмотрим содержимое /tmp/test_module
puppetdb # cat /tmp/test_module There is no other way, and there never was. I lost in this place. Pls, i beg u, help me if u can
В точности то, что мы писали в нашем конфиге. Если не передавать параметр parameter_one , будет браться параметр по-умолчанию из класса.
Таким нехитрым образом, можно штамповать модули пачками, пихая туда всё что угодно, и применять их к определённым нодам благодаря иерархии. Ну, надеюсь было интересно. Увидимся когда увидимся.
Sayonara.
Be First to Comment