LAMP con Salt
De la misma manera que hace unos meses conté cómo crear un entorno LAMP con Puppet, en esta ocasión haremos lo mismo con Salt, también conocido como SaltStack:
- crear una máquina virtual con Vagrant
- configurar Salt
- 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, nuevamente, todo en unos 10 minutos.
Este artículo va por David P., que me habló de Salt, José Antonio, que me preguntó por twitter qué sistema es el mejor, y por @ricbartm, con quien estube hablando este viernes sobre Salt ;)
Jerarquía
Para facilitaros la vida, ésta es la jerarquía de archivos que vamos a usar:
.
├── salt
│ ├── minion
│ └── roots
│ └── salt
│ ├── apache
│ │ └── init.sls
│ ├── logrotate
│ │ └── init.sls
│ ├── mysql
│ │ ├── client.sls
│ │ └── server.sls
│ ├── ntp
│ │ └── init.sls
│ ├── php
│ │ └── init.sls
│ ├── php-example
│ │ └── init.sls
│ └── top.sls
└── Vagrantfile
Como vereis, voy a instalar también ntp y logrotate, con el fin de hacer un ejemplo exactamente igual que en el artículo de LAMP con Puppet.
Lectura rápida
Resulta que el artículo me ha salido más largo de lo esperado, así que he creado un repositorio Git con los archivos de este artículo.
Sé que muchos de mis lectores agradecen artículos pequeños, así que podéis usar el repositorio y saltar directamente a la sección “Al lío”. Si queréis ver en detalle alguno de los archivos, podéis ir a su sección más adelante, si lo creéis necesario.
Vagrant
Éste es el contenido del archivo Vagrantfile:
|
|
Es similar a lo contado en la receta de LAMP con Puppet, y lo explicaré igual de rápido.
Estoy creando una máquina virtual llamada “wheeze64” y que me la voy a descargar de esa URL. Si ya no es válida, podéis usar cualquier otra máquina virtual de la lista. Además la he bautizado como “salt-example”.
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 10080 de la máquina host.
En las dos últimas líneas configuro el provisionamiento mediante Salt.
Salt
El resto de archivos pertenecen a Salt. Pero antes me gustaría aclarar algunos conceptos.
- minion es cada una de las máquinas que están bajo el control de Salt.
- Los pillars son configuraciones básicas, los hechos (facts en terminología Puppet).
- Los states son los estados en los que debe quedar la máquina.
- Un archivo sls es un Salt State, y equivale vagamente a un módulo de Puppet.
- Yaml es un lenguaje de serialización legible por humanos. Os invito a profundizar un poco más en él si os decidís por Salt.
- jinja2 es un lenguaje de plantillas sencillo y potente, muy típico de entornos Python. También deberíais investigarlo.
Se pueden contar muchas más cosas, pero dejémoslo aquí. Es suficiente para una primera toma de contacto.
Ahora describiré cada uno de los archivos. Son pequeños y sencillos. Estos archivos son plantillas jinja2 que generarán un archivo Yaml, que es la propia configuración. Parece complicado, pero veremos que no lo es tanto.
El primer archivo a tener en cuenta es salt/minion, donde está la configuración genérica:
file_client: local
Este archivo contiene configuración básica. En este caso se indica que la configuración es local (no hay estructura cliente-servidor).
El siguiente archivo importante es salt/roots/salt/top.sls, que describe cada uno de los minion:
|
|
Aquí se han indicado cada uno de los módulos que se van a instalar en la máquina salt-example.
logrotate
comencemos por uno de los módulos más sencillos, que se encuentra en salt/roots/salt/logrotate/init.sls. Lo primero, aclarar que el archivo init.sls es el que se buscará por defecto dentro del módulo. Luego veremos cómo utilizar otros. Éste es el contenido:
|
|
Realmente estamos seteando propiedades, tales como logrotate.pkg.installed = True
. Estas simples instrucciones crean un estado: el paquete logrotate
(cogido del nombre del módulo) debe estar instalado.
ntp
Vamos con algo un poco más difícil, ya que contiene un servicio y el paquete debian no se llama igual que el módulo. El archivo es salt/roots/salt/ntp/init.sls:
|
|
En este caso, el estado creado es: el paquete ntp
cuyo paquete debian se llama ntpdate
debe estar instalado. Además, hay un servicio que debe estar running
y se debe reiniciar cada vez que cambie el paquete ntpdate
.
Veremos que este mismo esquema se repite para cada uno de nuestros módulos.
php
Archivo: salt/roots/salt/php/init.sls
|
|
La primera parte ya la hemos visto: se asegura de que tanto los paquetes php5
como php5-mysql
estén instalados. El último apartado lo que hace es asegurarse de que esté habilitada la extensión de mysql en apache. Para ello reemplaza la extensión comentada por la no comentada. Es un poco tricky, pero funcional.
apache
Vamos con el archivo salt/roots/salt/apache/init.sls:
|
|
Que no contiene nada que no hayamos visto ya.
mysql
He dividido mysql en dos partes: una que instalará el cliente y otra el servidor. Por eso el módulo no tiene el archivo init.sls, sino dos:
mysql.client
El archivo salt/roots/salt/mysql/client.sls:
|
|
Se asegura de que el cliente mysql esté instalado.
mysql.server
El archivo salt/roots/salt/mysql/server.sls:
|
|
Es, quizá, el módulo más complejo de todos. La primera parte ya la hemos visto. La sección set-mysql-root-password
lo que hace es establecer la password de root del servidor de mysql. Es muy tricky, pero no he encontrado nada más sencillo.
php-example
Finalmente, descargamos nuestra página web. Es la misma que usé en el artículo LAMP con Puppet (archivo salt/roots/salt/mysql/client.sls):
|
|
Debo decir que esto es lo que me parece más impresionante de todo el artículo: la sencillez para trabajar con Git. Estas tres líneas se descargan el repositorio y comprueban que esté actualizado. Así, sin más.
Al lío
Bien, ahora es cuando lanzamos todo:
|
|
Y de nuevo podéis conectaros a https://localhost:10080/example, donde os está esperando la lista de tablas de la base de datos mysql, servida con PHP.
¡Bug! ¡Bug!
Supongo que lo corregirán, pero debo advertiros de un bug actual: El provisionamiento Salt en Vagrant está un poco verde, y no os mostrará el resultado, ni cuando sea un error. Esto me trajo de cabeza bastante tiempo. La solución es provisionar desde la propia máquina:
|
|
Conclusiones
No puedo evitar comparar Salt con Puppet. Al fin y al cabo he estado usando Puppet desde hace más de dos años. La evolución que he visto en Puppet ha sido desde módulos totalmente específicos de nuestra empresa a módulos genéricos que se pueden cargar con librarian-puppet, posibilitando configurar hiera y, así, configurarlo todo mediante Yaml (¿os suena?).
Hay un montón de módulos para Puppet. De hecho, hay proyectos para crear módulos para Puppet, como example42. En Salt hay muchísimos menos, pero la verdad es que no le hacen falta. Se han centrado en lo importante, aunque sí hecho de menos algunas cosas, como configurar vhosts de Apache directamente por configuración, en lugar de tener que proporcionar archivos. Pero supongo que estos detalles ya se irán completando.
También hay que ver otra diferencia: Ruby vs Python. Como bien saben todos los lectores del blog, yo soy más de Python. De todas maneras, en Puppet se utiliza un DSL bastante interesante, y se ofrece la posibilidad de crear los módulos en Ruby. En Salt, que yo sepa, se crean en Python. Pero me gustaría que juzgáseis vosotros mismos, comparando dos módulos similares: el módulo de Git para Puppet y el módulo de Git para Salt. He elegido éste porque es bastante similar.
Hay otra diferencia más. Quizá la más importante.
En Salt construyeron un sistema para comunicar máquinas y ejecutar comandos simultáneamente en todas ellas. Una especie de shell múltiple remota. Sobre esta arquitectura construyeron el equivalente a Puppet que permite hacer lo que se cuenta en este artículo. Esto permite algo que en Puppet han tenido que implementar aparte, que sería MCollective.
Siento no poder comparar cosas como la velocidad, eficiencia, memoria, seguridad, … En mi opinión no hay una gran diferencia en nada de todo esto, pero no tengo datos. Sinceramente creo que no es lo más importante, ya que ambos necesitarán realizar muchas operaciones de disco para comprobar el estado actual de la máquina, y probablemente esta operación sea similar y se lleve la mayor parte del tiempo y eficiencia.
Personalmente he decidido usarlo para mis máquinas en casa. La decisión viene por dos razones: porque en la empresa ya estoy usando Puppet y así aprendo algo nuevo, y porque es Python. Espero no equivocarme.