Puppet

1. Puppet Basiswissen

  1. Was ist Puppet?
  2. Was ist Puppet NICHT?
  3. Wie funktioniert Puppet?
  4. Klassen
  5. Module
  6. Rollen
  7. Fakten
  8. External Node Classifiers
  9. Hiera

1.1 Was ist Puppet

  • Puppet ist ein Config management System.
  • In Puppet können Konfigurationen als "Code" geschrieben werden der von einem Agent dann interpretiert und umgesetzt wird.

Beispiel:

Der Administrator definiert das auf jedem System eine gewisses Datei vorhanden sein soll und gibt den Inhalt der Datei vor.


file { "/etc/environment.conf":
  source  => 'puppet:///modules/name_of_module/filename',
  ensure  => present,
}


Puppet wird ausgeführt: Die Datei wird angelegt oder auf den im Code definierten Stand gebracht.

Nun kommt ein böser Administrator und logged sich auf dem System ein um die Datei zu ändern weil ihm XYZ nicht gefällt.

Beim nächsten Puppet lauf wird Puppet den Inhalt des Files wieder "richtigstellen" (-;

KONSISTENZ

1.2 Was ist Puppet NICHT

  • Puppet ist KEIN Orchestration System
  • KEIN Relase Management System
  • KEIN Deployment Tool

1.3 Wie funktioniert Puppet

Puppet benötigt einen Installierten Puppet Agent
Der Agent übersetzt die nicht OS-spezifische konfiguration (Beispiel: Ein Paket installieren)


package { "vim":
    ensure => "installed"
}

in den richtigen Befehl für das jeweilige Betriebssystem.
Alles was man puppet mitteilen muss ist wie das Paket jeweils heißt (funktionert auch mit case statements)

Puppet Agent vs. Puppetmaster

Puppet Agent Standalone Puppetmaster
Konfiguration auf jedem Node Konfiguration nur am Puppetmaster
Reports werden am Node gespeichert Reports zentral in PuppetDB
Fakten nur am Agent bekannt Fakten werden zum Puppetmaster übertragen

1.5 Klassen

Eine Klasse Gruppiert mehrere Konfigurations-Items, zum Beispiel:

  • Ein zu installierendes Paket
  • Eine Konfigurations-Datei für das Paket
  • Der Service der gerade Installiert wurde soll beim boot gestartet werden
  • Änderungen an der Konfiguraton soll einen reload des Services auslösen

Klassen können parameterisiert werden. Details folgen später

1.6 Module

Module haben immer einen einzigen Zweck, zum Beispiel:

  • Ein Modul zum managen von apt
  • Ein Modul zum managen von sshd

Module setzen sich aus mehreren Klassen zusammen und sollten immer generisch gehalten sein.

1.7 Rollen

Rollen sind eigentlich keine Puppet Funktionalität, eher Best Practice.
Rollen werden über ein eigenes Modul realisiert, deren Sinn und Zweck es ist:

  • Klassen nach Node-Verwendungszweck zusammenzufassen
  • Die Definition der Nodes zu vereinfachen und übersichlicher zu machen

1.8 Fakten

Der Puppet-Agent kommt mit einem Tool das Facter genannt wird.
Facter sammelt wissenswerte Information über das Node System
Diese FACTS werden in Variablen gespeichert und können im Puppet code benutzt werden

~BEISPIEELEEE~

Klasse (ohne Parameter)


class base::linux {
  file { '/etc/passwd':
    owner => 'root',
    group => 'root',
    mode  => '0644',
  }
  file { '/etc/shadow':
    owner => 'root',
    group => 'root',
    mode  => '0440',
  }
}

Klasse (mit Parameter)


class apache (String $version = 'latest') {
  package {'httpd':
    ensure => $version, # Using the class parameter from above
    before => File['/etc/httpd.conf'],
  }
  file {'/etc/httpd.conf':
    ensure  => file,
    owner   => 'httpd',
    content => template('apache/httpd.conf.erb'), # Template from a module
  }
  service {'httpd':
    ensure    => running,
    enable    => true,
    subscribe => File['/etc/httpd.conf'],
  }
}

Module (Ordnerstruktur)


/sshd_module                                 -> Order mit dem Namen des Moduls
 |---------/manifests/                       -> Manifest-Dateien
 |              \----/init.pp                -> Primäre Manifest-Datei (Startpunkt wenn sshd_module eingebunden wird)    
 |---------/files/                           -> Dateien die von Puppet zur Node übertragen werden
 |---------/templates/                       -> Dynamische .erb Templates die Mittels Ruby Code erstellt werden.

Module (mein_sshd beispiel)


/mein_sshd/
|---------/manifests/
|              |----/init.pp             -> inkludiert mein_sshd::install und mein_sshd::config
|              |----/install.pp          -> stellt sicher das openssh-server installiert ist
|              \----/config.pp           -> kümmert sich um die konfigurations-dateien und das ldap-script
|---------/files/ 
|            \--/sshbanner               -> das Banner wird von hier ausgeliefert
|---------/templates/
|              |----/ldapsearch.erb      -> Dynamisch erstelltes ldapsearch.sh, LDAP Server usw. kommen aus hiera
|              \----/sshdconfig.erb      -> Dynamisch erstellte sshd_config, vieles aus Hiera, 
-                                         anderes kann im Include überschrieben werden.

Rollen (Beispiel)


class mein_roles::base {
  include mein_sysctl
  include mein_apt
  include mein_apt::mein
  include mein_sshd
  include mein_sssd
  include mein_allblinkystuff
}
class mein_roles::appservers {
  include mein_roles::base
  include mein_tomcat::appserver
  include mein_mounts::appserver
}
...

Fakten (gekürzte Beispiel-Facts)


architecture => amd64
blockdevice_sda_model => SAMSUNG SSD PM83
blockdevice_sda_size => 256060514304
domain => hades
facterversion => 2.2.0
fqdn => Prometheus.hades
hardwaremodel => x86_64
hostname => Prometheus
interfaces => lo,wlan0
ipaddress => 10.42.10.9
ipaddress_lo => 127.0.0.1
ipaddress_wlan0 => 10.42.10.9
is_virtual => false
kernel => Linux
kernelmajversion => 4.2
kernelrelease => 4.2.0-rc7amd1212
kernelversion => 4.2.0
lsbdistcodename => stretch
lsbdistdescription => Debian GNU/Linux testing (stretch)
operatingsystemrelease => stretch/sid
osfamily => Debian
path => /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/sschoerg/.gem/ruby/2.1.0/bin:/usr/sbin:/sbin
physicalprocessorcount => 1
processorcount => 4
puppetversion => 3.8.2
rubyversion => 2.1.5
selinux => false
timezone => CEST
uniqueid => 007f0101
virtual => physical
...

Fakten -> USE THE FORCE LUKE!


...class-blablub...
if str2bool("$is_virtual") {
  include meine_hardware::virt_optimizations
}
case $operatingsystem {
  'Solaris':          { include role::solaris } # apply the solaris class
  'RedHat', 'CentOS': { include role::redhat  } # apply the redhat class
  /^(Debian|Ubuntu)$/:{ include role::debian  } # apply the debian class
  default:            { include role::generic } # apply the generic class
}
.../class-blablub...

External Node Classifiers (ENC):

ENC's werden benutzt um Nodes nicht im Code definieren zu müssen
Ein ENC kann alles sein, beispielsweise:

  • Ein Textfile
  • Hiera
  • Eine Ausführbare Datei
  • Eine Datenbank-Query

Über ENC's werden Nodes angelegt und ihnen Rollen zugewiesen

Hiera

Hiera löst basierend auf einer Hierarchie Variablen auf.
Hiera wird immer in Parameterisierten Klassen verwendet
Die Hierarchie kann natürlich angepasst werden:


:backends:
  - yaml
:yaml:
  :datadir: /etc/puppet/hieradata
:hierarchy:
  - "node/%{::fqdn}"
  - "virtual/%{::virtual}"
  - "%{::role}"
  - "%{::environment}"
  - common

Hiera Beispiel

Hiera call nach der Variable LDAPSERVER von bo-vm-inst im environment BO:

  1. hiera sucht im Ordner "node" nach einem Prometheus.hades.yaml (kein Treffer der Variable)
  2. hiera sucht im Ordner "virtual" nach einem true.yaml (der Node ist virtuell -> das hat Facter rausgefunden -> kein Treffer der Variable)
  3. hiera sucht im File mein-env.yaml -> (Match)

Gibt "mein-ldap.hades" zurück.

Puppet is AWESOME!!!

Zusätzliche Tools

Themen:

  • PuppetDB
  • Puppet-Explorer

PuppetDB

Die PuppetDB ist ein Postgres Backend in dem die Reports die Puppet generiert gespeichert werden.
Diese Reports enthalten:

  • Fakten
  • Fehler-reports
  • Laufzeiten und statistiken

Da alle Daten in einer Postgres DB gepeichert werden lassen diese sich auch mit vielfältigen Methoden verarbeiten (nötig für Nagios-checks, usw.)

Puppet-Explorer

Der Puppet-Explorer ist eine Webseite die eine Übersicht über die wichtigsten Daten in der PuppetDB bietet.

  • Wieviele Nodes
  • Wie ist die Node-verteilung in den verschiedenen Environments
  • Haben alle Nodes in den letzten X Stunden einmal eingecheckt
  • Gibt es Fehler auf Nodes?
  • Auflistung und Sammlung von Fakten: z.B 200 meiner Nodes laufen unter Wheezy, 300 sind virtualisiert.

Workflow?

Themen:

  • Grundsätze
  • Code styling
  • myRepos
  • r10k
  • Git (-;

Grundlegendes

  • Puppet selbst hat keine eingebaute Versionskontrolle -> man benutzt es also IMMER mit einem Versions-Kontrollsystem. In unserem Fall Git/Gerrit.
  • Für jedes Modul das von "extern" kommt wird ein Git Repository angelegt und der Upstream-Pfad hinzufefügt.
  • Für jedes selbstgeschriebene Modul wird ebenfall jeweils ein Repository angelegt.
  • Verschiedene Versionen der Module werden über "git tags" realisiert (mehr dazu später)

Code styling

In Puppet gelten einige Code Styling Regeln welchee sich auch mit einem Tool "Puppet lint" auf überprüfen lassen

  • Tabstop 2 .> softtabs (also 2 spaces)
  • alle "=>" müssen pro Klasse untereinander angeordnet werden (verbessert die Lesbarkeit

Zusätzlich sollte man das vim-puppet Modul benutzen. Es bringt Syntax-Highlighting usw. mit

myRepos

myRepos ist ein Tool das mehrere Git Repositories über ein konfigurationsfile kontrolliert das ebenfalls in einem Repository liegt.
Der Vorteil daran:
- Neue Module usw. werden in myRepos Konfigurationsfile eingetragen und jeder der am Projekt arbeitet muss nir das myRepos Repository auschecken und:


mr checkout
mr update

Installation mit:


apt-get install myrepos

r10k

r10k ist ein Tool (das unter anderen von Spotify eingesetzt wird) welches die benötigten Konfigurations-Teile am Puppetmaster ausrollt.

  • r10k hat ein Konfigurations-File, das sogenannte Puppetfile
  • in diesem Puppetfile werden alle Module spezifiziert und mit explizit genannten Versionen (auf git tags basierend) auchgecheckt
  • Jeder Branch in dem r10k Repositorie spiegelt ein Environment wieder und wird dann auch dementsprechend aufgelöst.

Git (-;

Tools die alles besser machen:

  • Git Bash Prompt: https://github.com/magicmonty/bash-git-prompt
  • gitg: Ein git Versions-Browser

Vorgehensweise:
- Alle Repos außer dem r10k Repo


git add %changes%
git commit -m "Commitnachricht die unglaublich Informativ ist"
git tag 0.0.42 # Legt einen neuen Tag an, dieser muss dann im Puppetfile von r10k referenziert werden wenn er benutzt werden soll
git push origin master
git push origin --tags

Im r10k Repository


git add %changes%
git commit -m "Commitnachricht die unglaublich Informativ ist"
git checkout %environment%
git push origin %environment% # Wobei das benötigte environment immer erst ausgecheckt werden sollte

Fragen?

Pro Frage 1€ in die Mate-Kasse!