Fabric: despliegues en cadena

El objetivo de cada programador es llevar a producción el código que escribe. En los tiempos que corren, este código se suele preparar para estar disponible para ejecutarse como servidor, dentro de un servidor o como paquete para descarga desde la nube. ¿Pero cómo podemos hacer que ese código llegue a estar preparado sin convertir esta tarea en épica?

En estos últimos días me he topado con el problema de que estaba montando una maqueta en una máquina virtual para trabajar de forma más limpia sin ensuciar mi equipo cuando me pasaron el acceso de una máquina virtual en AWS para que los clientes tuviesen también acceso al servidor que estaba montando, y al poco tiempo, en otra máquina hubo que hacer lo mismo. Al final invertí tiempo en hacer tres veces lo mismo… y eso sin contar que hay que poner después esto también en producción.

Este problema me llevó a revisar varias herramientas como Vagrant, Docker, … y revisando unas diapositivas en la que hablaban de Puppet me topé con Fabric. Fabric está basado en la producción en cadena de las fábricas, pero llevado al contexto de los despliegues. Un sistema para despliegues en cadena.

¿Qué es Fabric exactamente?

Es un sistema que establece una conexión SSH hacia uno o varios hosts, en cadena, realizando un conjunto de tareas definidas en un proceso escrito dentro de un fichero en código Python. Esto no implica que tengamos que ser unos perfectos programadores de Pyhton, aunque nunca viene mal saber bien la sintaxis del lenguaje para poder hacer cosas más elaboradas.

¿Cómo empezamos con Fabric?

Lo primero, como con cada herramienta de software que puedas tener, es instalarlo. La forma más fácil es a través del instalador de Python easy_install de la siguiente forma:

easy_install Fabric

Si necesitas más información sobre los huevos de Python, puedes ver este artículo.

¿Cómo hacemos la primera producción en cadena?

Como muestra, en la página web oficial de Fabric podemos ver este ejemplo:

from fabric.api import run

def host_type():
    run('uname -s')

Que puede ser ejecutado así:

fab -H localhost,linuxbox host_type

Es algo simple y no realiza nada más que una ejecución en cada una de las máquinas a las que se conecta, pero da una idea de cómo poder ejecutar algo empleando el comando run. También dispone de otros comandos como sudo que nos permite realizar ejecuciones en la máquina remota tomando privilegios de superusuario, o incluso simulando otro usuario.

IMPORTANTE: para esto el usuario con el que accedamos vía SSH debe de poder escalar a superusuario, obviamente.

¿Y solo eso?, ¿qué más se puede hacer?

Después de unas horas con él la verdad es que me he dado cuenta de que es una herramienta impresionante y que lo que se puede realizar con ella es increíble. Para poder llegar a los entresijos habría que plantearse el automatizar la puesta en producción o en entorno de desarrollo de un proyecto en concreto y navegar por su API para descubrir todo lo que se puede hacer. No todo es run y sudo en esta vida.

Dejo un ejemplo algo más elaborado para que se vea lo que quiero decir:

%% extraido de https://github.com/gingerlime/graphite-fabric
from fabric.api import cd, sudo, run, put, settings, task

def _check_sudo():
    with settings(warn_only=True):
        result = sudo('pwd')
        if result.failed:
            print "Trying to install sudo. Must be root"
            run('apt-get update && apt-get install -y sudo')


def conf_file(filepath):
    import pkg_resources
    return pkg_resources.resource_filename(__name__,
                                           "/config/{0}".format(filepath))

@task
def statsd_install():
    """
    Installs etsy's node.js statsd and dependencies
    """
    _check_sudo()
    sudo('apt-get update && apt-get upgrade -y')
    sudo('apt-get install -y build-essential supervisor make git-core')
    with cd('/usr/local/src'):
        sudo('wget -N http://nodejs.org/dist/node-latest.tar.gz')
        sudo('tar -zxvf node-latest.tar.gz')
        sudo('cd `ls -rd node-v*` && make install')

    with cd('/opt'):
        sudo('git clone https://github.com/etsy/statsd.git')

    with cd('/opt/statsd'):
        sudo('git checkout v0.7.1') # or comment this out and stay on trunk
        put(conf_file('localConfig.js'), 'localConfig.js', use_sudo=True)
        sudo('npm install')

    put(conf_file('statsd.conf'), '/etc/supervisor/conf.d/', use_sudo=True)
    sudo('supervisorctl update && supervisorctl start statsd')

    # UDP buffer tuning for statsd
    put(conf_file('10-statsd.conf'), '/etc/sysctl.d/', use_sudo=True)
    sudo('sysctl -p /etc/sysctl.d/10-statsd.conf')

Esto puede dar una idea de cómo realizar nuestros propios scripts para producción en cadena.

Conclusiones

Las tareas de puesta en producción se suelen dejar a manos de administradores de sistemas, mientras que el desarrollo se realiza por los programadores. En este caso, esta puesta en producción es un mundo intermedio, es terreno de DevOps. Fabric, junto con herramientas como Puppet o Chef, constituye una parte de este gran mundo de los DevOps.

Estos scripts podrían entrar en el terreno de los programadores, pero también requieren del conocimiento del administrador de sistemas para saber qué elementos se deben configurar, que sistemas hay que instalar y los mejores parámetros según la plataforma o la infraestructura en conjunto donde se vaya a desplegar.

Si has tenido estos problemas y en tu empresa y aún no conseguís que haya armonía entre los dos mundos quizás venga bien tener algo de guía al mundo DevOps. ¿Cuáles son los principales problemas en este sentido a los que te enfrentas diariamente?