Automatizzare Barman con Puppet: it2ndq/barman (parte due)

Nella prima parte di questo articolo abbiamo configurato Vagrant per avviare due VM Ubuntu 14.04 Trusty Tahr, chiamate rispettivamente pg e backup.  In questa seconda parte vedremo come utilizzare Puppet per installare e configurare un server PostgreSQL su pg e effettuarne il backup via Barman dalla seconda macchina.

Puppet: configurazioneINSIDE-manualchemical

Dopo aver definito le macchine come nell’articolo precedente, occorre definire i moduli Puppet necessari, che lasceremo gestire a librarian-puppet.

I moduli sono due:

  1. puppetlabs/postgresql (https://github.com/puppetlabs/puppetlabs-postgresql/) per installare PostgreSQL sulla VM pg
  2. it2ndq/barman (https://github.com/2ndquadrant-it/puppet-barman) per installare Barman su backup.

Per il primo useremo la versione presente su Puppet Forge, per il secondo effettueremo il clone da GitHub del progetto, per poterne sfruttare le modifiche più recenti.

Creiamo nella directory corrente un file chiamato Puppetfile con questo contenuto:

forge "https://forgeapi.puppetlabs.com"
mod "puppetlabs/postgresql"
mod "it2ndq/barman", :git => "git://github.com/2ndquadrant-it/puppet-barman.git"

Possiamo ora installare il modulo Puppet e le sue dipendenze eseguendo:

$ librarian-puppet install --verbose

Per quanto non indispensabile, il consiglio è quello di utilizzare sempre l’opzione --verbose ogni volta che si usa librarian-puppet.  Il comando è molto silenzioso ed è bene avere dettagli su quello che sta facendo, prima di scoprire (ad esempio) di avere buttato tempo prezioso aspettando che risolvesse senza successo un complicato conflitto di dipendenze.

Al completamento del comando, all’interno della directory corrente sarà presente la nuova directory modules che conterrà i moduli richiesti (barman, postgresql) e le loro dipendenze (apt, concat, stdlib). Inoltre, sarà stato creato il file Puppetfile.lock, che identifica dipendenze e versioni dei moduli installati, fissandole a protezione di aggiornamenti futuri. In questo modo, i successivi librarian-puppet install installeranno le stesse identiche versioni definite nel Puppetfile.lock, invece di possibili aggiornamenti.

A questo punto, aggiungiamo alla configurazione di Vagrant il fatto di utilizzare un manifesto Puppet per effettuare il provisioning dei server al termine dell’installazione di Puppet.
Modifichiamo quindi il Vagrantfile in questo modo:

Vagrant.configure("2") do |config|
  {
    :pg => {
      :ip      => '192.168.56.221',
      :box     => 'ubuntu/trusty64'
    },
    :backup => {
      :ip      => '192.168.56.222',
      :box     => 'ubuntu/trusty64'
    }
  }.each do |name,cfg|
    config.vm.define name do |local|
      local.vm.box = cfg[:box]
      local.vm.hostname = name.to_s + '.local.lan'
      local.vm.network :private_network, ip: cfg[:ip]
      family = 'ubuntu'
      bootstrap_url = 'https://raw.github.com/hashicorp/puppet-bootstrap/master/' + family + '.sh'

      # Run puppet-bootstrap only once
      local.vm.provision :shell, :inline => <<-eos
        if [ ! -e /tmp/.bash.provision.done ]; then
          curl -L #{bootstrap_url} | bash
          touch /tmp/.bash.provision.done
        fi
      eos

      # Provision with Puppet
      local.vm.provision :puppet do |puppet|
        puppet.manifests_path = "manifests"
        puppet.module_path = [".", "modules"]
        puppet.manifest_file = "site.pp"
        puppet.options = [
         '--verbose',
        ]
      end
    end
  end
end

Con le linee che abbiamo appena aggiunto, abbiamo dato a Vagrant l’istruzione di effettuare il provision delle macchine a partire dal file manifests/site.pp e che i moduli necessari al manifesto sono da cercare all’interno della directory modules. Il Vagrantfile è adesso nella sua forma definitiva.
Creiamo perciò la directory manifests all’interno della nostra directory di lavoro:

$ mkdir manifests

Andiamo quindi a scrivere in manifests una prima versione di site.pp, iniziando con una configurazione di default.

node backup {
  class { 'barman': 
    manage_package_repo => true,
  }
}
node pg {}

A questo punto, avviamo le due macchine virtuali. Se le avete distrutte al termine dell’articolo precedente, tutto quello che serve è eseguire:

$ vagrant up

Altrimenti, se le macchine sono ancora attive, occorreranno i comandi:

$ vagrant reload
$ vagrant provision

Possiamo osservare che sulla VM è stato creato un server Barman con una configurazione di base, senza alcun server configurato, connettendoci

$ vagrant ssh backup

e controllando il contenuto del file /etc/barman.conf:

# Main configuration file for Barman (Backup and Recovery Manager for PostgreSQL)
# Further information on the Barman project at www.pgbarman.org
# IMPORTANT: Please do not edit this file as it is managed by Puppet!
# Global options

[barman]
barman_home = /var/lib/barman
barman_user = barman
log_file = /var/log/barman/barman.log
compression = gzip
backup_options = exclusive_backup
minimum_redundancy = 0
retention_policy =
retention_policy_mode = auto
wal_retention_policy = main
configuration_files_directory = /etc/barman.conf.d

Procediamo adesso ad avviare un server PostgreSQL sulla macchina virtuale pg, modificando il site.pp. Dobbiamo tenere presente di quali siano i parametri richiesti da Barman al server, per cui dovremo impostare:

  • wal_level almeno a livello archive
  • archive_mode a on
  • archive_command in modo che i WAL possano essere copiati su Barman
  • una regola nel pg_hba.conf per consentire l’accesso al database dal server backup

Tutti questi parametri sono facilmente configurabili attraverso il modulo puppetlabs/postgresql.

Inoltre, aggiungiamo i parametri minimi di configurazione per il backup del server PostgreSQL pg sul nodo backup. Avremo bisogno di:

  • una stringa di connessione PostgreSQL
  • un file .pgpass per l’autenticazione
  • un comando per connettersi via SSH
  • effettuare lo scambio delle chiavi SSH.

it2ndq-barman genera automaticamente una coppia di chiavi pubblica/privata in ~barman/.ssh/. Scambiare in automatico le chiavi richiede la presenza di un puppet master per l’esportazione delle risorse. Configurare un puppet master è fuori dagli obiettivi di questo tutorial (ma sarà parte del prossimo, incentrato proprio sull’utilizzo di un puppet master e della classe barman::autoconfigure), quindi questo ultimo passo sarà eseguito manualmente.
Modifichiamo quindi il file site.pp come segue:

node backup {
  class { 'barman': 
    manage_package_repo => true,
  }
  barman::server {'test-server':
    conninfo     => 'user=postgres host=192.168.56.221',
    ssh_command  => 'ssh postgres@192.168.56.221',
  }
  file { '/var/lib/barman/.pgpass':
    ensure  => 'present',
    owner   => 'barman',
    group   => 'barman',
    mode    => 0600,
    content => '192.168.56.221:5432:*:postgres:insecure_password',
  }
}

node pg {
  class { 'postgresql::server':
    listen_addresses  => '*',
    postgres_password => 'insecure_password',
    pg_hba_conf_defaults => false,
  }
  postgresql::server::pg_hba_rule {'Local access':
    type        => 'local',
    database    => 'all',
    user        => 'all',
    auth_method => 'peer',
  }
  postgresql::server::pg_hba_rule {'Barman access':
    type        => 'host',
    database    => 'all',
    user        => 'postgres',
    address     => '192.168.56.222/32',
    auth_method => 'md5',
  }
  postgresql::server::config_entry {
    'wal_level'       : value => 'archive';
    'archive_mode'    : value => 'on';
    'archive_command' : value => 'rsync -a %p barman@192.168.56.222:/var/lib/barman/test-server/incoming/%f';
  }
  class { 'postgresql::server::contrib':
    package_ensure => 'present',
  }
}

Avendo modificato la configurazione delle macchine, è necessario rieseguire il provision:

$ vagrant provision

Quando le macchine sono su, possiamo procedere allo scambio di chiavi. Connettiamoci a pg:

$ vagrant ssh pg

e creiamo le chiavi per l’utente postgres, lasciando vuoto ogni campo durante l’esecuzione di ssh-keygen (ovvero, premendo sempre invio):

vagrant@pg:~$ sudo -iu postgres
postgres@pg:~$ ssh-keygen
postgres@pg:~$ cat .ssh/id_rsa.pub

L’ultimo comando emette una lunga stringa alfanumerica che deve essere inserita nel file ~barman/.ssh/authorized_keys su backup.

$ vagrant ssh backup
vagrant@backup:~$ sudo -iu barman
barman@backup:~$ echo "ssh-rsa ..." >> .ssh/authorized_keys

Allo stesso modo, copiamo la chiave dell’utente barman nel file authorized_keys dell’utente postgres su pg:

barman@backup:~$ cat .ssh/id_rsa.pub
ssh-rsa ...
barman@backup:~$ logout
vagrant@backup:~$ logout
$ vagrant ssh pg
vagrant@pg:~$ sudo -iu postgres
postgres@pg:~$ echo "ssh-rsa ..." >> .ssh/authorized_keys

A questo punto, facciamo una prima connessione in entrambe le direzioni fra i due server:

postgres@pg:$ ssh barman@192.168.56.222
barman@backup:$ ssh postgres@192.168.56.221

Eseguiamo un barman check per verificare il corretto funzionamento di Barman:

barman@backup:~$ barman check all
Server test-server:
        ssh: OK
        PostgreSQL: OK
        archive_mode: OK
        archive_command: OK
        directories: OK
        retention policy settings: OK
        backup maximum age: OK (no last_backup_maximum_age provided)
        compression settings: OK
        minimum redundancy requirements: OK (have 0 backups, expected at least 0)

Ogni riga dovrebbe risultare OK. Adesso, per effettuare un backup, basterà lanciare:

barman@backup:$ barman backup test-server

Una configurazione realistica

La configurazione di Barman effettuata finora è molto semplice, ma è facilmente possibile aggiungere pochi parametri al site.pp per sfruttare al meglio tutte le feature di Barman, come le retention policy e il nuovo backup incrementale disponibile con Barman 1.4.0.

Concludiamo questo tutorial con un caso d’uso realistico, in cui i requisiti sono:

  • un backup ogni notte alle 1:00;
  • avere la possibilità  di effettuare una Point In Time Recovery in un qualunque istante di tempo nell’ultima settimana;
  • avere sempre almeno un backup disponibile;
  • segnalare un errore durante barman check nel caso il backup più recente sia più vecchio di una settimana;
  • attivare il backup incrementale per risparmiare spazio su disco.

Usiamo quindi la risorsa file di Puppet per creare un .pgpass con i parametri di connessione al db e la risorsa cron per generare il job da ripetere ogni notte. Infine, modifichiamo il barman::server per aggiungere i parametri Barman necessari.
Il risultato finale è quello che segue:

node backup {
  class { 'barman':
    manage_package_repo => true,
  }
  barman::server {'test-server':
    conninfo                => 'user=postgres host=192.168.56.221',
    ssh_command             => 'ssh postgres@192.168.56.221',
    retention_policy        => 'RECOVERY WINDOW OF 1 WEEKS',
    minimum_redundancy      => 1,
    last_backup_maximum_age => '1 WEEK',
    reuse_backup            => 'link',
  }
  file { '/var/lib/barman/.pgpass':
    ensure  => 'present',
    owner   => 'barman',
    group   => 'barman',
    mode    => 0600,
    content => '192.168.56.221:5432:*:postgres:insecure_password',
  }
  cron { 'barman backup test-server':
    command => '/usr/bin/barman backup test-server',
    user    => 'barman',
    hour    => 1,
    minute  => 0,
  }
}

node pg {
  class { 'postgresql::server':
    listen_addresses  => '*',
    postgres_password => 'insecure_password',
    pg_hba_conf_defaults => false,
  }
  postgresql::server::pg_hba_rule {'Local access':
    type        => 'local',
    database    => 'all',
    user        => 'all',
    auth_method => 'peer',
  }
  postgresql::server::pg_hba_rule {'Barman access':
    type        => 'host',
    database    => 'all',
    user        => 'postgres',
    address     => '192.168.56.222/32',
    auth_method => 'md5',
  }
  postgresql::server::config_entry {
    'wal_level'       : value => 'archive';
    'archive_mode'    : value => 'on';
    'archive_command' : value => 'rsync -a %p barman@192.168.56.222:/var/lib/barman/test-server/incoming/%f';
  }
}

Conclusioni

Con 51 righe esatte di Puppet siamo riusciti a configurare una coppia di server PostgreSQL/Barman con delle impostazioni molto simili a quelle che potremmo volere in produzione. Abbiamo così combinato i vantaggi dell’avere un server Barman che gestisce i backup a quelli di avere un’infrastruttura gestita da Puppet, riutilizzabile e versionabile.

Nella prossima e ultima parte di questa serie di articoli vedremo come utilizzare un Puppet master per approfittare della possibilità di esportare risorse fra macchine diverse e così permettere alle due macchine di scambiarsi i parametri necessari al loro corretto funzionamento tramite la classe barman::autoconfigure.

This Post Has 2 Comments

  1. giulio.garau says:

    ciao, ottimo walkthrough vagrant/puppet/barman/postgres :D

    un suggerimento: per lo scambio chiavi è sempre meglio usare ssh-copy-id (http://linux.die.net/man/1/ssh-copy-id) il quale è facilmente integrabile nel provisioning puppet

    gg

  2. […] seconda parte di questa serie di articoli abbiamo configurato via Puppet due virtual machine con un server PostgreSQL e un server Barman in […]

Leave A Reply