Puppet r10k – GIT control

r10k is een deployment pipeline tool voor Puppet in combinatie met een git repository. Het doel is om de Puppet-code te wijzigen volgens version control met GIT en nadat een update comitted is, zal de Puppet-agent altijd de laatste updates ophalen via de GIT repositorie(s). Hierdoor is er een centrale locatie waar de geschiedenis van wijzigingen is opgeslagen en een DevOps-team kan clonen, updaten en pushen van wijzigingen waarbij er verschillende branches gemaakt kunnen worden voor b.v. test, productie of bepaalde features.

r10k is een ‘open source project’ en is geïntegreerd in Puppet PE vanaf v3.8. Het werkt alsvolgt:

  • Er is een controle-repository met branch-namen die gelijk zijn aan de environment-namen en die elk een bestand bevatten met de naam ‘Puppetfile‘. Hierin staan welke modules in de environment gebruikt worden. Hierin staat ook het manifest en eventueel de hiera.yaml met de hieradata.
  • Voor elke zelfgeschreven module is er een repository met dezelfde branch-namen als de environment-namen. Hierin staan de bestanden voor de module met de manifest-file(s).

Zo maak ik op mijn GIT-repository een ‘control-repo‘ en ga deze vervolgens clonen naar mijn dev-computer:

git clone git@git.digitalinfo.local:puppet/control-repo.git

Het standaard bestand die hier minimaal moet zijn is genaamd ‘Puppetfile‘. Daarnaast moeten we een manifest-bestand hebben:

touch Puppetfile
mkdir manifests
touch manifests/install-server.pp

Hierna is het zaak dat GIT ook weet dat ‘production’ de default branch is, dus we committen, wijzigen de branch en pushen met:

git add --all
git commit -m "Initial commit"
git branch -m master production
git push origin production

De branches ‘kodi’ en ‘musicplayer’ maak ik ook aan en push deze ook naar de GIT:

git checkout -b kodi
git push origin kodi
git checkout -b musicplayer
git push origin musicplayer

Hiermee is de basis gelegd en gaan we verder met de configuratie.

In de Puppetfile van bijvoorbeeld de branch ‘musicplayer’ wordt aangegeven welke modules gebruikt moeten worden. Dit kunnen modules van de puppet-forge zijn maar ook zelfgeschreven modules. De inhoud kan er bijvoorbeeld zo uit zien:

forge "http://forge.puppetlabs.com"

# Additional modules from the Puppet Forge
mod 'puppetlabs-stdlib', '4.17.1'

# Modules from the GitLab
mod 'musicplayer',
 :git => 'git@git.digitalinfo.local:puppet/musicplayer.git',
 :branch => 'musicplayer'

mod 'saz-sudo',
 :git => 'git@git.digitalinfo.local:puppet/saz-sudo.git',
 :branch => 'musicplayer'

Opmerking: r10k ‘kijkt’ niet naar dependencies van modules dus controleer op de forge welke dat zijn en zet deze modules ook in de Puppetfile!

Een voorwaarde voor r10k is dat de toegang naar de GIT-repository via een key-pair verloopt van het type rsa en deze mag geen wachtwoord hebben. Genereer eventueel een nieuw key-pair met:

ssh-keygen -t rsa

en plaats de publieke sleutel op de GIT-repository. De private key komt in /etc/puppetlabs/puppetserver/ssh/ op de puppetmaster.

We voegen de gewijzigde ‘Puppetfile’ toe aan de GIT-repo:

git add Puppetfile
git commit -m "Puppetfile added"
git push origin musicplayer

Zoals je al kunt zien in de Puppetfile, zijn de modules die we gebruiken eerder al toegevoegd aan de GIT-repository, namelijk ‘musicplayer‘ en ‘saz-sudo‘. De branches die hier gebruikt worden heben de naam ‘musicplayer’ en ;kodi’, dus die moeten wel aangemaakt worden in alle (module)repo’s die gebruikt worden. Voor mijn GIT-repository gebruik ik GitLab en daar heb ik een Puppet-repository aangemaakt met de benodigde projecten::

In de control-repo dient voor elke branch ook een manifest aanwezig te zijn, dus

mkdir manifest
cd manifest
touch setup-server.pp

In het setup-server.pp manifest bestand plaatsen we de nodes met hun classes, zoals beschreven in het artikel over Puppet Manifests.

In het r10k.yaml bestand op de puppetmaster, geven we aan wat de instellingen zijn. Dit bestand is: /etc/puppetlabs/r10k/r10k.yaml en ziet er bv. zo uit: (yaml files beginnen altijd met drie streepjes)

---
cachedir: /opt/puppetlabs/server/data/puppetserver/r10k
sources:
 puppet:
 basedir: /etc/puppetlabs/code/environments
 remote: git@git.digitalinfo.local:puppet/control-repo.git

git:
 private_key: /etc/puppetlabs/puppetserver/ssh/id_control_repo.rsa
 provider: rugged
  • cachedir: kan elke directory zijn, zolang er maar toegang toe is, vaak ook /var/cache/r10k
  • basedir: is de directory waar r10k de omgevingen zal maken aan de hand van de branches in de GIT repository. Zelf hoeven we dus niets aan te maken hier, r10k doet dat voor ons!
  • remote: is de remote GIT repository waar de control-repo in staat.
  • private_key: is de locatie (en de naam) van het gebruikte private-key-bestand
  • provider: Ruby-rugged is de default in Puppet PE v4, kan in andere versies ook shellgit zijn.

Tenslotte dient r10k aangeroepen te worden om de modules te bouwen in de juiste directories. Dit moet dan uiteraard op de puppetmaster gebeuren en clone daarom de control-repo ook naar een locatie op de puppetmaster. Geef van daaruit het volgende commando:

r10k deploy environment -pv

Dit maakt de environments naar aanleiding van de branch-namen en plaatst deze volgens de r10k-configuratie in /etc/puppetlabs/code/environments/. Hier halen de nodes via de puppet-agents hun gegevens op.

Alle modules en manifests kunnen nu bijgehouden worden in de GIT-repositories en worden aangestuurd vanuit de control-repo. Voor de nodes zal er geen verschil zijn in het ophalen van de catalog en testen kan op een node met:

puppet agent --test --noop

Dit houdt dus in dat telkens na een wijziging in de GIT-repositories, je handmatig met r10k de environments moet deployen. Je kunt hiervoor een ‘hook‘ maken in je GIT-host of je laat een crontab op de puppetmaster dit elke 15 minuten voor je doen. Voor dit laatste kun je natuurlijk een resource-class maken in de manifest voor je puppetmaster. Die kan er alsvolgt uit zien:

node 'puppetmaster.digitalinfo.local' {
  cron { 'run r10k deployments':
    command => '/usr/local/bin/r10k deploy environment -p',
    minute => '*/15',
  }
}