Puppet Forge on Puppetlabsin tarjoama repo Puppet-moduuleille. Forge-moduuleja voi asentaa "puppet module install"-komennolla, mutta niihin voi viitata myös r10k:n tai librarian-puppetin Puppetfilessä. Nykyisin Puppet Forge on ensimmäinen paikka, josta katson, onko joku muu jo ratkaissut käsilläni olevan ongelman Puppetilla - pyörää kun on toisinaan turha keksiä uudelleen.

Olen itse käyttänyt vuosia Git Submoduleja, koska niiden avulla Puppet-moduuleihin ulkopuolelta tulevat muutokset on helppo tarkistaa Gitin lokeista ja diffeistä. Niiden käyttö menee kuitenkin kankeaksi kun moduulien määrä kasvaa suureksi: sekä päärepo että submodulet vaativat jatkuvaa paapomista. Tuloksena on turhanpäiväisiä, samankaltaisina toistuvia commit-viestejä kuten "Update Git submodule pointers", joilla ei ole mitään muuta käytännön merkitystä kuin Gitin pitäminen tyytyväisenä.

Moduulien säilömisestä Forgessa on eräs etu käytettäessä Puppetfileä: librarian-puppet osaa ladata moduulien metadata.json:issa määritetyt riippuvuudet automaattisesti, mutta vain jos riippuvuudet löytyvät Forgesta. Tai kääntäen: Gitissä olevia riippuvuuksia ei ladata automaattisesti, vaan ne pitää määritellä yrityksen ja erehdyksen kautta käsin. Tämä paisuttaa Puppetfileä huomattavasti ja tekee sen ylläpidosta työlästä. Kyseessä on Puppetin oma version riippuvuushelvetistä. Valitettavasti r10k ei osaa ladata riippuvuuksia automaattisesti - mitään selkeää syytä tähän ei ole.

Moduulien saaminen Puppet Forgeen ei ole kovin vaikeaa. Ensin luodaan käyttäjätili Puppet Forgeen. Käyttäjätunnuksen ja moduulin metadata.json:in "name"-kohdan tulisi täsmätä. Esimerkiksi jos metadata.json sisältää

"name": "puppetfinland-os",

niin Puppet Forge-käyttäjätunnuksen tulisi olla "puppetfinland". Ilmeisesti tämä ei ole ehdoton vaatimus, mutta sen noudattaminen lienee selkeyden takia järkevää.

Forgeen voi viedä moduuleja käsin, mutta se on erittäin työlästä kun moduuleja on paljon. Seuraava askel onkin puppet-blacksmithin asennus. Tässä vaiheessa haasteeksi tulee se, mihin Gem-polkuun puppet-blacksmith asennetaan. Itse suosin asentamista /opt/puppetlabs/puppet -hakemiston alle:

$ /opt/puppetlabs/puppet/bin/gem install puppet-blacksmith

Sitten luodaan Blacksmithin konfiguraatiotiedosto, ~/.puppetforge.yml, johon laitetaan Puppet Forgen käyttäjätunnus ja salasana tähän tapaan:

---
 url: https://forgeapi.puppetlabs.com
 username: myuser
 password: mypassword
 

Tämän jälkeen voidaanin siirtyä jo itse moduuliin muokkaamiseen paremmin Forgen kanssa yhteensopivaksi. Tämä kannattaa tehdä Puppetin moduulikehitystyökaluilla eli Puppet PDK:lla, joka asennetaan näitä ohjeita seuraamalla. Vaikka virallista Debian GNU/Linux -tukea ei olekaan, PDK:n Ubuntu-versio asentuu myös Debianiin. Olemassa olevaan moduuliin saadaan PDK:lla lisättyä tukku "best practices"-läskiä helposti:

$ cd <moduulin-hakemisto>
 $ pdk convert

PDK:n muunnoskomento lisää moduuliin mm. rspec-testejä sekä Travis CI- ja Appveyor -integraatioita

Seuraavaksi PDK:n luomaan Rakefileen lisätään riippuvuus puppet-blacksmithin:

require 'puppet_blacksmith/rake_tasks'

Tämän jälkeen rakella (Rubyn "make") voidaan ajaa puppet-blacksmithin komentoja, jotka on hyvin esitelty sen virallisesta dokumentaatiosta.

Mikäli moduuliin tehdyt muutokset halutaan testata automaattisesti Travis CI:llä (mikä on ehdottoman järkevää), pitää Gemfileen lisäksi tehdä pieni lisäys:

group :development do
 --- snip ---
 gem "puppet-blacksmith"
 end

Ilman tätä muutosta Travis-ajot epäonnistuvat ("Build failed"), koska Rakefileen yllä määriteltyä puppet-blacksmith riippuvuutta ei löydy:

LoadError: cannot load such file -- puppet_blacksmith/rake_tasks

Traviksen kanssa kannattaa myös varmistua siitä, että metadata.jsonissa määritelty ohjelmistolisenssin nimi vastaa sen virallista tunnistetta ("Identifier"), jonka voi etsiä esimerkiksi täältä. Muutoin Traviksen ajama metadata_lint -testi epäonnistuu:

(WARN) license: License identifier BSD license is not in the SPDX list: http://spdx.org/licenses/
 Warnings found in metadata.json
 
 The command "bundle exec rake $CHECK" exited with 1.

Tässä vaiheessa kaikki Git-repossa olevat muutokset kannattaa kommitoida.

Nyt puppet-blacksmithin pitäisi olla jo toimintakykyinen. On kuitenkin järkevää ensin tarkistaa, että Traviksen ajamat testit menevät läpi pushaamalla muutokset Gitiin:

$ git push

Jos testit näyttävät vihreää, voidaan moduulista julkaista uusi versio. Teoriassa komennon "rake module:release" pitäisi hoitaa koko julkaisuprosessi, mutta siinä olevan bugin takia prosessi on valitettavasti vähemmän suoraviivainen. Ensin muutetaan moduulin versio metadata.jsonissa ja kommitoidaan muutokset:

$ rake module:bump_commit:patch
 Bumping version from 0.1.5 to 0.1.6

Sitten luodaan metadata.jsonin versiota vastaava Git tag ja pushataan se:

$ rake module:tag
 $ git push --tags

Lopuksi julkaistaan moduuli Puppet Forgessa:

$ rake module:clean
 $ rake module:push
 Uploading to Puppet Forge puppetfinland/systemd

Komento "module:clean" varmistaa, että Forgeen ladataan uusin versio.

Mikäli muutosten tekeminen Puppet-koodiin ja Hieraan suoraan puppetmasterilla tuntuu liian kevyeltä ja helpolta, voi Puppet-työnkulusta tehdä asteittain vaikeammaksi oman sietokyvyn mukaan lisäämällä palettiin lisää komponentteja. Esimerkiksi ns. control repon ja r10k:n käyttö Puppetin environmentien ylläpitoon lisää heti useita vaiheita aiemmin yksinkertaiseen työnkulkuun. Toki tällä saavutetaan myös ihan oikeita etuja, joista lisää tuonnempana.

Control repo - tästä lähtien osin suomennettuna "hallintarepo" - on käytännössä Git repository, jonka jokaisesta haarasta (branch) luodaan (tai ainakin voidaan luoda) dynaamisesti Puppet masterille vastaava Puppet-environment. Hallintarepon oletushaaran nimi, "production", on tästä syystä sama, kuin Puppet agenttien oletuksena käyttämä environment. Hallintarepon haaroissa on pitkälti sama sisältö kuin tavanomaisessa /etc/puppetlabs/code/environments/production -kansiossakin olisi:

$ ls control-repo
 data
 environment.conf
 hiera.yaml
 Puppetfile
 README.md
 site
 site.pp

Puppetfileä käsiteltiin jo aiemmassa artikkelista, jossa luotiin Puppet-koodiin pohjautuvia Kafo-installereja. Tiivistetysti Puppetfile sisältää viittaukset niihin Puppet-moduuleihin, jotka environmentin moduulikansiossa halutaan olevan:

# Forgen osoite
 forge "https://forgeapi.puppetlabs.com"
 
 # Moduuli Puppet Forgesta
 mod 'puppetlabs/stdlib'
 
 # Moduuli Gitistä
 mod 'puppet-mymodule',
 :git => '[email protected]:myorg/puppet-mymodule.git'

Tiedosto site.pp on näinä aikoina usein äärimmäisen pelkistetty, koska sitä tulee usein käytettyä lähinnä luokkien lataamiseen Hieran "classes"-listasta:

# Oletusarvo [] estää Puppet-ajojen epäonnistumisen siinä
 # tapauksessa, että jollakin koneella ei ole classes-listassa yhtään
 # luokkaa.
 lookup('classes', {merge => unique, default_value => []}).include

Tiedosto environment.conf on sekin varsin pelkistetty:

# Environmentin manifesti (ks. yllä)
 manifest = site.pp
 
 # Puppet-moduulien latauspolku. Alla käytetään globaaleja,
 # environmentien ulkopuolisia moduuleja kansiosta
 # /etc/puppetlabs/code/modules, sitten etsitään environmentin
 # moduulikansiosta, sitten environmentin site-kansiosta.
 # Site-kansion moduulien tiedostojen oletetaan olevan suoraan
 # hallintarepossa, ts. niihin ei viitata Puppetfilessä.
 modulepath = $basemodulepath:modules:site
 
 # Varmistetaan, että noodit käyttävät aina tuoreinta koodia. Suurella
 # noodimäärällä tämän parametrin arvoa voi joutua miettimään
 # uudelleen. 
 environment_timeout = 0

Tiedosto hiera.yaml on environment-kohtainen Hieran-asetustiedosto. Aiemmista versioista poiketen versio 5 hiera.yaml:ista sallii kolmitasoisen hierarkian, johon kuuluu globaali taso, environment-kohtainen taso ja moduulikohtainen taso. Viimeksi mainittu vaikuttaa suunnitellun vaihtoehdoksi hieman ikääntyneelle params.pp -patternille. Näillä seikoilla ei ole hallintarepon kannalta muuta merkitystä kuin se, että hallintarepon jokaisessa haarassa on hiera.yaml-tiedosto - esimerkiksi tällainen:

---
 version: 5
 defaults:
 datadir: data
 data_hash: yaml_data
 
 hierarchy:
 - name: "Per-node data"
 path: "nodes/%{trusted.certname}.yaml"
 - name: "Common data"
 path: "common.yaml"

Kansio site sisältää hallintarepossa suoraan ylläpidettävät Puppet-moduulit, kuten yllä site.pp:n kommenteissa mainittiinkin. Näin säästytään Puppetfilen ja erillisten moduulirepojen ylläpidolta.

Kansio data sisältää Hieran hierarkian, eli yllä olevaa hiera.yml-tiedostoa käytettäessä tiedoston common.yaml sekä kansion nodes, jossa on noodeille niiden omat yaml-tiedostot.

Artikkelisarjan muut osat:

Puppet on erittäin kätevä erityisesti hyvin monimutkaisten järjestelmien rakentamisessa ja ylläpidossa. Sen avulla on helppoa myös häivyttää suuriakin käyttöjärjestelmäeroja yhden luokkarajapinnan taakse. Hyvänä esimerkkinä käyvät Puppet-Finland-projektin thunderbird- ja openvpn-moduulit, jotka toimivat useilla eri Linux-jakeluilla ja Windowsilla.

Yleensä Puppettia varten rakennetaan palvelinympäristö, joka koostuu puppetserveristä, yleensä puppetdb:stä sekä mahdollisesti myös puppetboardista tai foremanista. Kullekin hallittavalle koneelle asennettu puppet-agent ottaa yhteyden puppetserveriin esim. kerran puolessa tunnissa, päivittää konfiguraationsa vastaamaan puppetserverillä määriteltyä tilaa ja lähettää raportin puppetserverin kautta puppetdb:lle.

Puppettia voidaan ajaa myös paikallisesti ilman puppetserveriä käyttämällä puppet apply-komentoa esimerkiksi seuraavasti:

$ puppet apply init.pp

Yksittäisellä manifest-tiedostolla (yllä init.pp) ei kuitenkaan pystytä tekemään ihmeitä. Puppet apply osaakin käyttää paikallisessa hakemistossa olevia puppet-moduuleita:

$ puppet apply --modulepath=/opt/puppet-modules init.pp

Yllä hakemisto /opt/puppet-modules sisältää kaikki ne moduulit, joita init.pp tarvitsee. Lisäksi siellä on oltava asennettuna moduulien vaatimat riippuvuudet. Moduulikansion ylläpito käsin on melko työlästä, mutta apuna voi käyttää esimerkiksi librarian-puppet-työkalua.

Puppet apply-pohjainen konfigurointi voidaan viedä astetta pidemmälle Kafolla. Kafolla puppet applyn päälle rakennetaan oikea asennusohjelma, jonka toimintaa voidaan ohjata komentoriviparametreilla. Kullekin Kafo-asennusohjelmalle on hyvä luoda rajapinnaksi räätälöity, yksinkertainen Puppet-moduuli muutamastakin eri syystä:

Kafo-asentimien luontiin vaadittava ympäristö on helppoa luoda Vagrant + Virtualbox -yhdistelmällä:

$ git clone https://github.com/Puppet-Finland/puppet-kafo
 $ cd puppet-kafo
 $ vagrant up kafo

Kun virtuaalikone on pystyssä, yhdistetään siihen seuraavasti:

$ vagrant ssh kafo

Sen jälkeen luodaan virtuaalikoneella hakemisto Kafo-asentimelle:

$ mkdir puppetmaster-installer
 $ cd puppetmaster-installer
 $ kafofy -n puppetmaster-installer

Asentimen hakemistoon on nyt luotu Kafon vaatima hakemistorakenne konfiguraatiotiedostoineen. Seuraavassa vaiheessa hakemistoon asennettaan asentimen vaatimat Puppet-moduulit. Tämän voisi tehdä käsinkin, mutta librarian-puppet -työkalulla homma hoituu kätevämmin:

$ rm -rf modules
 $ librarian-puppet init

Tämän jälkeen määritetään asentimen tarvitseman moduulit ja niiden version Puppetfile-tiedostossa, jonka "librarian-puppet init" loi. Alla esimerkki hyvin yksinkertaisesta Puppetfilestä, jossa kaikki moduulit on määritetty noudettaviksi Git-repositoryistä:

#!/usr/bin/env ruby 
 #^syntax detection
# Puppet Forgen osoite 
forge "https://forgeapi.puppetlabs.com"
# Kafo-installerin rajapintaluokka ("entrypoint") 
mod 'puppetfinland-puppetmaster', 
:git => 'https://github.com/Puppet-Finland/puppet-puppetmaster.git'
# Luokka, jolla asennetaan puppetserver 
mod 'puppet-puppetserver', 
:git => 'https://github.com/Puppet-Finland/puppet-puppetserver.git'
# Stdlib, jota hyvin monet muut luokat käyttävät. m
od 'puppetlabs-stdlib', 
:git => 'https://github.com/puppetlabs/puppetlabs-stdlib.git', 
:ref => '4.19.0

Puppetfileen voidaan määrittää myös moduuleja, jotka noudetaan Gitin sijaan Puppet Forgesta. Puppet Forgen käytön etuna on se, että librarian-puppet osaa moduulien vaatimat moduulit automaattisesti. Sen sijaan Gitiä käytettäessä moduulien vaatimukset on määritettävä itse Puppetfileen.

Rajapintamoduulin (yllä puppet-puppetmaster) pääluokka manifests/init.pp voi olla hyvinkin yksinkertainen:

# A simple wrapper class for setting up puppetmasters. Primarily 
# aimed at use in Kafo installers. 
# 
# == Parameters: 
# 
# $puppetserver:: Setup puppetserver 
# class puppetmaster 
( Boolean $puppetserver = true 
) 
{ if $puppetserver { 
class { 'puppetserver::repository': } 
class { 'puppetserver': } 
} 
}

Huom! Kafo on erittäin tarkka parametrien dokumentaation muodosta. Esim. parametrien dokumentaatiossa ei sallita sarkaimia. Dokumentaatio pitää siis kirjoittaa juuri yllä esitetyssä muodossa.

Kun Puppetfile on luotu, voidaan siellä määritetyt moduulit asentaa moduulikansioon librarian-puppetilla:

$ librarian-puppet install 
 $ ls modules 
 apt 
 augeas 
 augeasproviders_core 
 puppetmaster 
 puppetserver 
 puppetserver_gem 
 stdlib
 
Kuten yltä nähdään, librarian-puppet nouti Puppet Forgesta automaattisesti myös sellaisia moduuleja, joita ei oltu määritetty Puppetfileen käsin (apt, augeas, augeasproviders_core).
 
Lopuksi määritetään mitä rajapintaluokkaa asentimen halutaan käyttävän:
$ echo "puppetmaster: true" > config/installer-scenarios.d/default-answers.yaml
Kuten yltä voi arvata, Kafo tukee useita asennusskenaarioita. Asentimen tukemat skenaariot voi listata seuraavasti:
$ bin/puppetmaster-installer --list-scenarios
 Available scenarios
 default (INSTALLED)
Oletusskenaario eli default riittää kuitenkin aivan hyvin useimpiin käyttötapauksiin.
 
Asentimen komentoriviparametrit näkee --help -vivulla:
$ bin/puppetmaster-installer --help
 Usage:
 puppetmaster-installer [OPTIONS]
 
 Options:
 
 = Generic:
 --[no-]colors Use color output on STDOUT (default: true)
 --color-of-background COLOR Your terminal background is :bright or
 :dark (default: :dark)
 --dont-save-answers Skip saving answers to './config/installer-
 scenarios.d/default-answers.yaml'? (default: false)
 --ignore-undocumented Ignore inconsistent parameter documentation
 (default: false)
 -i, --interactive Run in interactive mode
 --log-level LEVEL Log level for log file output (default: "info")
 -n, --noop Run puppet in noop mode? (default: false)
 -p, --profile Run puppet in profile mode? (default: false)
 -s, --skip-checks-i-know-better Skip all system checks (default:
 false)
 -v, --verbose Display log on STDOUT instead of progressbar
 -l, --verbose-log-level LEVEL Log level for verbose mode output
 (default: "info")
 -S, --scenario SCENARIO Use installation scenario
 --disable-scenario SCENARIO Disable installation scenario
 --enable-scenario SCENARIO Enable installation scenario
 --list-scenarios List available installation scenarios
 --force Force change of installation scenario
 --compare-scenarios Show changes between last used scenario and the
 scenario specified with -S or --scenario argument
 --migrations-only Apply migrations to a selected scenario and exit
 --[no-]parser-cache Force use or bypass of Puppet module parser
 cache
 -h, --help print help
 --full-help print complete help
 --[no-]enable-puppetmaster Enable 'puppetmaster' puppet module (default: true)
 
 
 = Module puppetmaster:
 --puppetmaster-puppetserver Setup puppetserver (current: true)
 
 Only commonly used options have been displayed.
 Use --full-help to view the complete list.
Suurin osa parametreista on Kafon luomia geneerisiä parametreja. Rajapintaluokan parametri "puppetserver" on muuntunut asentimen komentoriviparametriksi --puppetmaster-puppetserver, joka voi saada arvokseen true tai false.

Kafo-asennin ei toimi sellaisenaan millä tahansa koneella, vaan se vaatii toimivan Puppet-asennuksen. Tämä ongelma voidaan kiertää käärimällä Kafo-asennin esimerkiksi .deb tai .rpm -pakettiin. Esimerkiksi foreman-installer RPM-paketti paitsi Kafo-installerin, myös sen ajonaikaiset vaatimukset (rubygem-kafo, puppet, rubygem-highline, ruby). Vaihtoehtoisesti asentimen kaveriksi voidaan luoda yksinkertainen skripti, jolla voidaan asentaa tarvittavat paketit.
menucross-circle