Contenido

LAMP con Puppet

En esta ocasión se me ha ido la pelota. En un solo artículo vamos a:

  • crear una máquina virtual con Vagrant
  • configurar Puppet
  • configurar librarian-puppet
  • instalar todo un entorno LAMP (Linux + Apache + MySQL + Php)
  • descargarnos la web de un repositorio remoto Git
  • servir su contenido desde el servidor Apache.

Y sabéis que mis artículos se leen en unos 10 minutos.

Puppet

Jerarquía

Ésta es la jerarquía de archivos que se van a emplear. Así no tendréis que romperos la cabeza más adelante:

.
├── bootstrap.sh
├── manifests/
│   └── site.pp
├── modules/
├── puppet.conf
├── Puppetfile
├── Puppetfile.lock
└── Vagrantfile

Los directorios son los que tienen la barra al final. Creadlos para evitar problemas posteriores.

Vagrant

Lo primero es que no queremos romper nuestra máquina. Así que vamos a usar una máquina virtual. En esta ocasión será una Debian Wheezy de 64 bytes. Pero no os aburriré con tonterías:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# -*- coding:utf-8; tab-width:4; mode:ruby -*-
# vi: set ft=ruby :
# filename: Vagrantfile

Vagrant::Config.run do |config|

  config.vm.define :example do |c|
    # VM creation
    c.vm.box = 'wheeze64'
    c.vm.box_url =  'https://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210.box'
    c.vm.host_name = 'vagrant-example'

    # Manual provisioning
    c.vm.provision :shell, :path => 'bootstrap.sh'

    # Port forwarding
    c.vm.forward_port 80, 9090

	# Puppet configuration
    c.vm.provision :puppet do |puppet|
      puppet.manifests_path = 'manifests'
      puppet.module_path = ['modules']
      puppet.manifest_file = 'site.pp'
    end
  end

end

Hay mucho que explicar aquí, pero voy a ser rápido. A parte de toda la parafernalia Ruby que requiere este archivo de configuración, vemos que estoy creando una máquina virtual llamada “wheeze64” y que me la voy a descargar de esa URL. Espero que siga siendo válida, y si no, podéis usar cualquier otra máquina virtual de la lista. Además la he bautizado como “vagrant-example”.

Lo primero que hago es un provisionamiento inicial mediante un script mío que luego veremos. Después me aseguro de que voy a poder acceder a mi servidor web, que estará escuchando en el puerto 80 de la VM, y que estará mapeado con el puerto 9090 de la máquina host.

Finalmente rollos de configuración típicos de Vagrant para que funcione bien con Puppet.

Bootstrap

Mi pequeño script de provisionamiento inicial:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
# filename: bootstrap.sh

function install {
		package=$1
		min_version=$2
		version=$(apt-cache policy $package | grep '\*\*\*' | cut -f3 -d' ')

		dpkg -l $package > /dev/null
		installed=$?
		dpkg --compare-versions $min_version lt $version
		updated=$?

		echo "$package version: $version"
		if [ $installed != 0 ] || [ $updated != 0 ]; then
				apt-get install -y $package
		fi
}

if [[ ! $(grep "deb https://ftp.es.debian.org/debian unstable main contrib non-free" /etc/apt/sources.list) ]]; then
		(
				echo deb https://ftp.es.debian.org/debian unstable main contrib non-free
				echo deb https://ftp.es.debian.org/debian testing main contrib non-free
		) > /etc/apt/sources.list

		apt-get update
fi

install facter 1.6
install puppet 3.3

Básicamente: le meto una configuración de APT fija (así dará igual qué VM hayais elegido) y me aseguro de tener dos cosas instaladas: facter y puppet (en una versión superior a la 3.3). Todo esto ocurrirá en la VM, por lo que no tenéis que temer por vuestras máquinas reales. Estos paquetes me hacen falta para poder ejecutar Puppet, así que en una máquina real tendría que instalarlos a mano.

Puppet

Vamos con puppet, aunque no estoy seguro de que este archivo haga falta:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# filename: puppet.conf
[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
templatedir=$confdir/templates
prerun_command=/etc/puppet/etckeeper-commit-pre
postrun_command=/etc/puppet/etckeeper-commit-post
modulepath = /etc/puppet/modules:/usr/share/puppet/modules:modules
storeconfigs = true

dbadapter = sqlite3
dblocation = storeconfigs.sqlite

Y ahora lo que sí hace falta, la configuración de los nodos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# filename: site.pp

File {
  owner => root,
  group => root,
  mode => 644,
}

node 'example', 'vagrant-example' {
  include 'ntp'
  include 'logrotate'
  include 'apache'
  class { "mysql":
    root_password => 'secret',
  }
  include 'php'
  include 'git'

  logrotate::rule { 'messages':
    path         => '/var/log/messages',
    copytruncate => true,
    missingok    => true,
    rotate_every => 'day',
    rotate       => 7,
    compress     => true,
    ifempty      => true,
  }
  php::module { "mysql": }

  git::reposync {'web': source_url => 'https://github.com/magmax/small_php_example.git',
                        destination_dir => '/var/www/example'}

  apache::vhost { 'default':
    docroot  => '/var/www/example',
    priority => '000',
  }
}

Aquí sí que hay telita. Primero establezco la configuración por defecto para los archivos. No es necesario, pero lo he puesto porque siempre lo hago. Luego configuro dos nodos: ’example’ y ‘vagrant-example’. Eso es porque hay dos máquinas que tendrán esta configuración: la real y la que vamos a usar nosotros, que sería la de Vagrant. Así la misma configuración de Puppet os vale para ambas y podéis guarrear en la VM sin romper el servidor.

Luego viene todo lo que instalo: [ntp], logrotate, Apache, MySQL (con la contraseña ‘secret’), Php y Git.

Finalmente un poco de configuración básica para logrotate a modo de ejemplo, indico que quiero usar el módulo de Php para MySQL, llamo a una macro para instalar una pequeña página de ejemplo que mostrará todas las tablas de la base de datos “mysql” desde PHP y configuro Apache para que sirva esa configuración. Todo esto en menos de 20 líneas de código.

Librarian

Bueno, pero… ¿de dónde saco los módulos de puppet que necesito?

Para eso está librarian-puppet, y aquí está su configuración:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# filename: Puppetfile

forge "https://forge.puppetlabs.com"

mod 'example42/puppi'
mod 'example42/ntp'
mod 'example42/git'
mod 'example42/mysql'
mod 'example42/apache'
mod 'example42/logrotate'
mod 'example42/php'

En dos palabras: configuro la fuente de módulos y los que quiero seleccionar.

También se habrá creado el archivo Puppetfile.lock, que contiene las versiones de los módulos que se instalaron. Si metéis esta configuración en un repositorio (cosa que deberíais hacer si lo vais a usar de verdad), recomiendo subirlo también junto con Puppetfile a pesar de ser generado, para evitar disgustos si éstas cambian. Si os cargáis el directorio modules, librarian-puppet tratará de reinstalar las versiones que tiene ese archivo.

Al lío

Pues ya lo tenemos todo. Ahora viene lo mejor. Queremos lanzar la máquina virtual y que se configure sola, pero no tenemos los módulos de Puppet. Así que lo primero es traérselos:

1
$ librarian-puppet install

Y con eso ya está todo. Podréis verlos en el directorio modules. Y ahora la magia: Descargamos, instalamos, proveemos y levantamos la máquina virtual:

1
$ vagrant up example

Y podéis conectaros a https://localhost:9090/example, donde os está esperando la lista de tablas de la base de datos mysql, servida con PHP.

También podéis entrar en vuestra VM con:

1
2
3
$ vagrant ssh example
example $ sudo su
example #

Simplemente Acojonante.

Más ventajas

Bueno, pues eso no es todo. Aún hay más.

Si la rama principal del repositorio cambiara, la siguiente ejecución de Puppet la actualizaría. Eso facilita bastante el despliegue y la gestión de un sistema de integración contínua, ¿verdad?