P U P P E T http://www.puppetlabs.com/ Vad är Puppet? * Språk för att definiera hur maskiner ska konfigureras * Programmen som applicerar den definitionen Se till att: * paket är/inte är installerade * konfigfiler har rätt innehåll * tjänster kör/inte kör * ... Varför ska man använda Puppet? * Automatisering * Dokumentation * Struktur * Återanvändning * Testinstallationer * Ominstallationer Jämfört med: rdist/rsync + ssh/pdsh - Påverkar bara de maskiner som är uppe just då - Ingen spårbarhet eller klonbarhet. Man vet fortfarande inte hur maskinerna är eller ska vara konfigurerade. Jämfört med: Installera om maskiner från master-image - Kräver nertid för maskinen - Funkar i sin renaste form bara för identiska maskiner. Måste kompletteras med skriptning om maskinerna skiljer sig åt. - Ger klonbarhet, men inte spårbarhet. Man kan göra identiska maskiner, men man är inte mycket till hjälp om man t.ex vill byta OS-versioner eller OS-dist. - Hänsyn måste tas till data, så att det inte försvinner. + Ger ett garanterat identiskt tillstånd. Jämfört med: Installera om med omfattande %post i kickstart - Kräver nertid för maskinen - Oportabelt: varje OS-dist har sin egen kickstart- motsvarighet. - Kan vara knepigt att hålla alla kickstartfiler i synk med varandra. - Hänsyn måste tas till data, så att det inte försvinner. + Ger ett garanterat identiskt tillstånd. + Ger både klonbarhet och spårbarhet Jämfört med: Dokumentera - Tråkigt. - Lätt att man missar att skriva ner någon detalj, beskriver för vagt, inte hinner göra det "just nu", osv. - Fortfarande en massa manuellt jobb att klona. - Lätt att göra fel när man följer dokumentationen. + Ofta lättare och naturligare att beskriva inte bara vad, utan också varför. ± Ger poäng hos PHB:er. Koncept * Idempotens * Konvergens * Deklarativt språk, inte imperativt file { "/etc/hemligt.txt": owner => "root", group => "wheel", mode => 0600; } file { "/etc/nsc": ensure => directory; } file { "/etc/sysconfig/selinux": content => "SELINUX=permissive\nSELINUXTYPE=targeted\n"; } file { "/etc/ntp.conf": source => "/config/files/ntp.conf"; } type { title_a: param1 => value1a, param2 => value2a, ...; title_b: param1 => value1b, param2 => value2b, ...; ... } file { # Samma parametrar till alla "/etc/hemligt-1.txt": owner => "root", group => "wheel", mode => 0600; "/etc/hemligt-2.txt": owner => "root", group => "wheel", mode => 0600; "/etc/hemligt-3.txt": owner => "root", group => "wheel", mode => 0600; "/etc/hemligt-4.txt": owner => "root", group => "wheel", mode => 0600; } file { [ "/etc/hemligt-1.txt", "/etc/hemligt-2.txt", "/etc/hemligt-3.txt", "/etc/hemligt-4.txt" ]: owner => "root", group => "wheel", mode => 0600; } file { "/etc/hemligt.txt": owner => "root", group => "root", mode => 0600; "/etc/nsc": ensure => directory; "/etc/sysconfig/selinux": content => "SELINUX=permissive\nSELINUXTYPE=targeted\n"; "/etc/ntp.conf": source => "/config/files/ntp.conf", mode => 0444; "/etc/rndc.key": ensure => link, target => "/var/named/chroot/etc/rndc.key"; } package { "ntp": ensure => installed; "dhcp": ensure => absent; "torque": ensure => installed, provider => rpm, source => "/pkg/local/torque-2.2.1-1cri.x86_64.rpm"; } yumrepo { "smokerings": descr => "Smokerings local repository", baseurl => "file:///pkg/local/smokerings/x86_64/", gpgcheck => 0, enabled => 1; "nordugrid": descr => "NorduGrid - stable", baseurl => "http://ftp.nordugrid.org/repos/redhat/el5/x86_64/stable", gpgkey => "http://ftp.nordugrid.org/RPM-GPG-KEY-nordugrid", gpgcheck => 1, enabled => 1; } service { "dhcpd": enable => false, ensure => stopped; "ntpd": enable => true, ensure => running; } * augeas * schedule * nagios_command * cron * selboolean * nagios_contact * exec * selmodule * nagios_contactgroup * file * service * nagios_host * filebucket * ssh_authorized_key * nagios_hostescalation * group * sshkey * nagios_hostextinfo * host * tidy * nagios_hostgroup * k5login * user * nagios_hostgroupescalation * mailalias * yumrepo * nagios_service * maillist * zfs * nagios_servicedependency * mount * zone * nagios_serviceescalation * notify * zpool * nagios_serviceextinfo * package * nagios_servicegroup * resources * nagios_timeperiod package { "ntp": ensure => installed; } file { "/etc/ntp.conf": source => "/config/files/ntp.conf", require => Package["ntp"]; } service { "ntpd": enable => true, ensure => running, subscribe => File["/etc/ntp.conf"]; } package { "ntp": ensure => installed, before => File["/etc/ntp.conf"]; } file { "/etc/ntp.conf": source => "/config/files/ntp.conf", notify => Service["ntpd"]; } service { "ntpd": enable => true, ensure => running; } class ntp-generic { file { "/etc/ntp": # Ntpd needs to be able to store /etc/ntp/drift. ensure => directory, owner => "ntp", group => "ntp", mode => 0755; } package { "ntp": ensure => installed; } service { "ntpd": enable => true, ensure => running; } } class timeserver { include ntp-generic file { "/etc/ntp.conf": source => "/config/files/ntp.conf-server"; } } class timeclient { include ntp-generic file { "/etc/ntp.conf": source => "/config/files/ntp.conf-client"; } } node armstrong { include timeserver file { "/etc/nodetype": content => "system-server\n"; } } node goodman, "miller.smokerings.nsc.liu.se" { include timeclient file { "/etc/nodetype": content => "system-server\n"; } } node n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21, n22, n23, n24, n25, n26, n27, n28, n29, n30, n31, n32, n33, n34, n35, n36, n37, n38, n39, n40, n41, n42, n43, n44, n45, n46, n47, n48 { include timeclient file { "/etc/nodetype": content => "computenode\n"; } } file { "/var/named/chroot/etc/named.conf": source => "/config/Files/named.conf"; "/var/named/chroot/etc/rndc.conf": source => "/config/Files/rndc.conf"; "/var/named/chroot/var/named/192-168-116.zone": source => "/config/Files/192-168-116.zone"; "/var/named/chroot/var/named/192-168-117.zone": source => "/config/Files/192-168-117.zone"; } $pupfiles = "/config/Files" $namedroot = "/var/named/chroot/" $namedetc = "${namedroot}etc" $zonedir = "${namedroot}var/named" file { "$namedetc/named.conf": source => "$pupfiles/named.conf"; "$namedetc/rndc.conf": source => "$pupfiles/rndc.conf"; "$zonedir/192-168-116.zone": source => "$pupfiles/192-168-116.zone"; "$zonedir/192-168-117.zone": source => "$pupfiles/192-168-117.zone"; } file { "/etc/smurf.conf": source => ".../smurf.conf-$operatingsystem"; "/etc/gnapp.conf": source => ".../gnapp.conf-$hostname"; "/usr/bin/gargamel": ensure => link, target => ".../gargamel.$architecture"; } $bindpkg = $operatingsystem ? { "Fedora" => ["bind", "bind-chroot"], "Gentoo" => ["net-dns/bind"], } package { "bindpackage": name => $bindpkg, ensure => installed; } service { "named": enable => true, ensure => running, require => Package["bindpackage"]; } case $operatingsystem { "CentOS", "Fedora": { package { "bind": ensure => installed; "bind-chroot": ensure => installed; } service { "named": enable => true, ensure => running, require => [ Package["bind"], Package["bind-chroot"] ]; } } "Gentoo": { package { "net-dns/bind": ensure => installed; } service { "named": enable => true, ensure => running, require => Package["net-dns/bind"]; } } } import "util.pp" import "dns.pp" import "rootuser.pp" import "osfixes.pp" import "puppet.pp" import "filesystems.pp" import "network.pp" import "time.pp" import "installation.pp" import "cluster.pp" import "manifests/*.pp" $cluster_domain = "smokerings.nsc.liu.se" $n_computenodes = 66 file { "/etc/hosts": ensure => file, content => template("$pupfiles/hosts.erb"); } 127.0.0.1 localhost ::1 localhost6 192.168.116.1 armstrong.<%= cluster_domain %> armstrong 192.168.116.2 goodman.<%= cluster_domain %> goodman 192.168.116.3 miller.<%= cluster_domain %> miller 192.168.116.4 ellington.<%= cluster_domain %> ellington 192.168.116.5 basie.<%= cluster_domain %> basie # 192.168.116.129-200 compute nodes <% 1.upto(n_computenodes.to_i) do |i| -%> 192.168.116.<%= i+128 %> n<%= i %>.<%= cluster_domain %> <% end -%> * defined() * inline_template() * split() * extlookup() * md5() * sprintf() * file() * regsubst() * tagged() * fqdn_rand() * sha1() * template() * generate() * shellquote() * versioncmp() * alert * fail * require * crit * include * search * debug * info * tag * emerg * notice * warning * err * realize # Mirror a directory tree using rsync. # # The key in the file $sshkey must not be encrypted. define rsync_mirror($source, $target, $sshkey="", $unless="", $onlyif="") { if $sshkey { $sshcmd = "ssh -i$sshkey" } else { $sshcmd = "ssh" } exec { "rsync -aRqv --no-implied-dirs --delete --delete-excluded '$source' '$target'": env => "RSYNC_RSH=$sshcmd", path => "/bin:/usr/bin", unless => $unless ? { "" => undef, default => $unless }, onlyif => $onlyif ? { "" => undef, default => $onlyif }; } } rsync_mirror { centos: source => "rsync://mirror.nsc.liu.se/CentOS/5/", target => "/pkg/mirror/centos-5"; } augeas { php-upload-size: context => "/files/etc/php.ini", changes => [ "set PHP/post_max_size '96M'", "set PHP/upload_max_filesize '48M'", ]; } Loopar finns inte: define foo($xlist) { for $x in $xlist { # Syntax error file { "/etc/foo/$x": content => $name; } } } Men kan ofta emuleras med hjälpdefinitioner: define foo($xlist) { foo::helper { $xlist: param => $name; } } define foo::helper($param) { file { "/etc/foo/$name": content => "$param"; } } foo { blaha: xlist => [ "ett", "två", "tre", "fyra" ]; } Utökningar * Egendefinierade typer * Egendefinierade funktioner * Egendefinierade fakta * Utökningar skrivs i Ruby Manifestfiler på lokalt filsystem # puppet site.pp "Lokalt" kan även vara t.ex NFS. Eller checka ut senaste version ur t.ex Git eller CVS från en server till lokal kopia innan man kör 'puppet'. Lämpligen från cron. Klient-server * puppetmasterd på en server * puppetd på alla klienter * Krypterad förbindelse (TLS) * Server och klient autentiseras med X.509-certifikat * Manifesten kompileras på servern, och nod-specifik katalog lämnas till klienten * "Environments" - olika uppsättningar manifest, t.ex för test och produktion * Rapport från klienten till servern om vad den gjort file { "/etc/ntp.conf": source => "puppet://some-host/files/ntp.conf"; "/etc/named.conf": source => "puppet:///files/named.conf"; } Andra liknande verktyg: Cfengine 2 + Moget + Välanvänt + Hyfsat väldokumenterat + Har fileditering inbyggt i sig - Jobbigt att få rätt ordning - Svårt att utöka - "Lågnivå" - Oregelbunden syntax - Ersatt med Cfengine 3 Andra liknande verktyg: Cfengine 3 ± Helt annan syntax än Cfengine 2 + Mer regelbunden syntax än Cfengine 2 - Fortfarande ganska lågnivå - Inga makron - Ej utökningsbart (?) Andra liknande verktyg: * Bcfg2 XML-baserat * Quattor Används av CERN * Chef "Recept" direkt i Ruby Ordning implicit från den textuella ordningen Bra och dåligt med Puppet + "Högnivåoperationer" + Utökningsbart (i Ruby) + Kraftfull mallhantering ("templates") för filinnehåll + Aktiv "community" - Inbyggda master-servern skalar dåligt - Den skalbara lösningen med Apache och Passenger är krångligare - Certifikathanteringen kan ibland strula - Manipulering av godtyckliga konfigfiler kan var knepigt (Augeas finns, men är inte helt lättanvänt) - En del "uppenbara" resurstyper saknas, t.ex för att konfigurera nätverk http://docs.puppetlabs.com/ - Puppet Language Guide - Resource Types - Metaparameters - Functions