Puppet, klar. Und dann?

23.05.2013 | LinuxTag 2013

Thomas Gelf
www.netways.de

VORSTELLUNG

Kurzvorstellung: Thomas Gelf

Puppet und Ich

Puppet und Netways

Puppet und Netways

Puppet und Netways

Es gibt Zertifizierungen!

Puppet und Netways

We are hiring!

www.netways.de/jobs

WICHTIG: Dieser Vortrag will...

Übersicht

WARMUP: WO ANFANGEN?

Wofür ist Puppet zuständig?

Langsam anfangen, Step by Step:

Nicht übertreiben: Paketmanagement

package { 'apache2':
  ensure => installed
}
package { 'xz-utils':
  ensure => '5.1.1alpha+20110809-3'
}
        

Nicht übertreiben. Beispiel: Updates

# Möglich:
package { 'whatever':
  ensure => 'latest'
}

# Aber besser:
case $osfamily {
  'debian': {
    cron { 'autoupgrade':
      path    => '/bin:/sbin:/usr/bin:/usr/sbin',
      command => 'apt-get update && apt-get upgrade',
      user    => root,
      hour    => 2,
      minute  => ip_to_cron(),
    }
  }
  'redhat': {
    package { 'yum-autoupdate': ensure => installed }
  }
}

Alles muss in Module!

$pkg = $osfamily ? {
  'redhat' => 'openssh',
  'debian' => [ 'openssh-server', 'openssh-client' ],
  default => 'ssh'
}

package { $pkg: ensure => installed }

DANN: REIHENFOLGE

Wir erinnern uns

Explizite Abhängigkeiten

class ssh {
  package { 'openssh-server':
    ensure => installed,
  }

  file { '/etc/ssh/sshd_config':
    ensure  => file,
    source  => 'puppet:///modules/ssh/sshd_config',
    mode    => 0644,
    owner   => 'root',
    group   => 'root',
    require => Package['openssh-server'],
    notify  => Service['ssh'],
  }

  service { 'ssh':
    ensure  => running,
    enable  => true,
  }
}

Kurzschreibweise

Package['openssh-server']
-> File['sshd_config']
~> service { 'ssh':
  ensure => running,
  enable => true,
}

Implizite Abhängigkeiten

File {
  owner   => 'user1',
  group   => 'group1',
  require => [ User['user1'], Group['group1'] ],
}

file { '/tmp/test': ensure => directory }
file { '/tmp/test/file':
  ensure  => file,
  require => File['/tmp/test'],
}

User['user1'] {
  gid    => 'group1',
  require +> Group['group1'],
}
group { 'group1': ensure => present }
        

Noch eleganter: Run Stages

Run Stages: Beispiel

class yumrepos {
  $url = "http://host/repo/$operatingsys../$architecture"

  yumrepo { 'meinrepo':
    baseurl  => $url,
    descr    => 'Mein repository',
    enabled  => 1,
    gpgcheck => 0,
  }
}

stage { 'yum': before => Stage['main'] }

node /^www\d+/ {
  class { 'yumrepos': stage => yum }
  include webserver
  include dbserver
}

Wichtige Regeln zu Abhängigkeiten

SYSTEMÜBERGREIFENDE CONFIG

Beispiele

Lösung: exportierte Ressourcen

Exportierte Ressourcen - Beispiel I

class webserver {
  package { 'apache2': ensure => installed }

  @@nagios_service { "check_http_$fqdn":
    use       => "check_http",
    host_name => $fqdn,
    target    => "/etc/icinga/objects/check_http_$fqdn.cfg",
  }
}

class icinga {
  Nagios_service <<||>>
}
        

Exportierte Ressourcen - Beispiel II

@@mysql::db { 'guug2013':
  user     => 'guug',
  password => '2013',
  host     => $ipaddress,
  grant    => ['all'],
  tag      => 'web_db'
}
        
Mysql::Db <<| tag == 'web_db' |>>
        

Exportierte Ressourcen - Beispiel III

class hosts {
  @@host { $fqdn:
    ip           => $ipaddress,
    host_aliases => $hostname,
  }
  Host <<||>>
}
        

Voraussetzungen

[master]
storeconfigs = true
thin_storeconfigs = true
dbadapter    = mysql
dbuser       = puppet
dbpassword   = ***
...
        

Wichtig: aufräumen!

puppet node clean host1.example.com
        

Neu: PuppetDB

Zu umständlich? Zu wenig?

# Array aller aktiven Knoten mit Uptime > 30 Tagen
# und zugewiesener Klasse Apache:
$ret = pdbnodequery(
  ['>',['fact','uptime_days'],30],
  ['and',
    ['=','type','Class'],
    ['=','title','Apache']])

https://github.com/dalen/puppet-puppetdbquery
        

ORCHESTRATION: MCOLLECTIVE

Was ist Marionette Collective?

Einfach mal HALLO sagen...

% mco ping
dev8                                     time=126.19 ms
dev6                                     time=132.79 ms
dev10                                    time=133.57 ms
.
.

---- ping statistics ----
25 replies max: 305.58 min: 57.50 avg: 113.16
        

Wir stoppen...

Fazit zu MCollectie

WORKFLOWS

Organisatorisches

Wer darf was?

Seid großzügig ;-)

Ziel

SCHNITTSTELLEN - ENC

Unsere Node-Definitionen

node 'some-server.domain.tld' {
  include baseconfig
  include webserver
}

node 'www1.domain.tld' inherits 'some-server.domain.tld' {
  include my-webapp
}

node /^www\d+\.domain\.tld$/ {
  include baseconfig
  class {'webserver': type => 'apache', version => '2.4' }
}

node default {
  include unconfigured
}

Vor- und Nachteile textbasierter Nodes

ENC Konfiguration

[master]
node_terminus = exec
external_nodes = /usr/local/bin/my_node_classifier

ENC Ausgabe

---
classes:
  baseconfig
  webserver
    type: Apache
    version: 2.4
parameters:
  global_var: foo
  global_array:
    - foo
    - bar
environment: production

Beispiel in Perl

#!/usr/bin/perl
use YAML;

my $hostname = $ARGV[0];

# Unsere "CMDB":
my $result = {
  'classes' => {
    'baseconfig' => {
      'datacenter' => 'Nuremberg'
    },
    'webserver' => {
      'type'       => 'apache',
      'version'    => '2.4'
    }
  }
};

print YAML::Dump($result);

SCHNITTSTELLEN - LOOKUPS

extlookup()

$relay_host = extlookup('relay_host', 'default-relay.tld')
some-host.tld.csv:
relay_host,datacenter2.domain.tld

common.csv:
relay_host,datacenter1.domain.tld
# Sind im Grunde globale Variablen!!
$extlookup_datadir = "/etc/puppet/manifests/extdata"
$extlookup_precedence = ["%{fqdn}", "common"]
$relay_host = extlookup('relay_host')

Hiera!

Hiera - backends

Hiera!

class apache($version = hiera('apache::version', '2.4'))
class apache($version = hiera('version', '2.4'))
class apache($version = '2.4')

Eigene functions und facts

SCHNITTSTELLEN: REST API

Rest?

Rest API

Puppet REST API URI Beispiele

Kleines SSL-basiertes Beispiel

curl \
 --cert /var/lib/puppet/ssl/certs/host.pem \
 --key /var/lib/puppet/ssl/private_keys/host.pem \
 --cacert /var/lib/puppet/ssl/ca/ca_crt.pem \
 -k -H "Accept: yaml" \
 https://master:8140/production/facts/somehostname

Vorteile der REST API

BITTE NICHT...

#!/usr/bin/php
<?php

$api = new Puppet_Api($master);
$facts = $api->hostFacts($hostname);
echo "$hostname is running $facts->osfamily";

Schnittstellen - wie geht's weiter?

SONSTIGE FEATURES

Reporting

Enterprise?

Enterprise: Live Management

Open Source Software

Puppet Module Forge


Danke für eure Aufmerksamkeit!

Fragen?




class linuxtag2013::puppet {

    service { 'questions':
        ensure => answered
    }

}

        
Thomas Gelf <thomas.gelf@netways.de>