Integración contínua: BuildBot
Como prometí en el artículo anterior, es hora de presentar otra alternativa para la Integración Contínua (CI, o Continuous Integration).
No es la única alternativa, pero yo sólo he trasteado con Jenkins y con BuildBot.
Maestro/Esclavo
De la misma manera que Jenkins, BuildBot tiene una arquitectura Maestro/Esclavo. Sin embargo, Jenkins nos gestionaba la instalación de los esclavos, mientras que BuildBot no lo hará. En general, es menos amigable que Jenkins.
Cuando comenzamos un proyecto hay que crear el maestro y después crear los esclavos. Este es un proceso sencillo que veremos mediante un ejemplo.
Instalando
El maestro y el esclavo son paquetes debian separados. Eso nos permite instalarlos sólo allí donde hacen falta. En el ejemplo se considerará que ambos están en la misma máquina, aunque no tendría por qué.
Se puede ejecutar en casi cualquier parte, ya que está escrito en python. Basta con tener el intérprete instalado en la máquina.
El ejemplo
Y como ejemplo, trataré de realizar lo mismo que ya hicimos en Jenkins: Vamos a configurar pyDoubles para ejecutarlo con BuildBot.
Creando el esclavo
Comienzo por el esclavo porque no vamos a configurar nada, así que bastará con ejecutar:
$ buildslave create-slave -r ./example-slave localhost example-slave pass
mkdir ./example-slave
chdir ./example-slave
mkdir ./example-slave/info
Creating info/admin, you need to edit it appropriately
Creating info/host, you need to edit it appropriately
Not creating info/access_uri - add it if you wish
Please edit the files in ./example-slave/info appropriately.
buildslave configured in ./example-slave
$
Como véis, un proceso bastante sencillo. Y ahora sólo hay que seguir las instrucciones y editar los archivos que se indican: info/admin
, info/host
y uno que no indica claramente, que es el buildbot.tac
. Si abrís los archivos, veréis que buildbot.tac
es un programa python. Realmente no es necesario saber python para editarlo, ya que la plantilla es autoexplicativa. En nuestro caso, ni siquiera es necesario editarlo porque va a estar todo en local.
La opción ‘-r
’ que utilicé en la línea de órdenes sirve para que utilice rutas relativas. Así, podríamos mover de directorio la configuración del esclavo.
En el caso del esclavo está claro qué archivos podemos mantener en un sistema de control de versiones: los tres indicados (info/admin
, info/host
y buildbot.tac
).
Creando el maestro
De manera similar al esclavo, podemos crear el maestro:
$ buildbot create-master -r example-master
mkdir ./example-master
creating master.cfg.sample
populating public_html/
creating database (sqlite:///state.sqlite)
buildmaster configured in ./example-master
$
Como podeis observar ahora tardará un poco más, ya que tiene que crear e inicializar la base de datos. Por defecto utilizará sqlite, pero podemos configurarlo contra un mysql. Para el ejemplo, sqlite será suficiente.
Veamos lo que nos ha creado aquí:
.
├── buildbot.tac
├── master.cfg.sample
├── public_html
│ ├── bg_gradient.jpg
│ ├── default.css
│ ├── favicon.ico
│ └── robots.txt
└── state.sqlite
Lo primero es mover el archivo “master.cfg.sample
” a “master.cfg
”. Éste será nuestra plantilla a modificar.
¿Qué tendríamos que guardar en un sistema de control de versiones? Pues basta con guardar buildbot.tac
y master.cfg
. Nada más. El resto de los archivos podemos volver a obtenerlos con la orden (fijáos que lo ejecuto desde dentro del directorio creado):
example-master$ buildbot upgrade-master
checking for running master
checking master.cfg
upgrading basedir
populating public_html/
populating ./public_html/favicon.ico
populating ./public_html/robots.txt
populating ./public_html/bg_gradient.jpg
populating ./public_html/default.css
populating ./master.cfg.sample
upgrading database (sqlite:///state.sqlite)
upgrade complete
example-master$
Evidentemente, perderemos el histórico de datos, pero… ¿es realmente importante? Si es así, recomiendo hacer copias de seguridad como se harían de cualquier otra base de datos. Y, evidentemente, no utilizar sqlite.
Configurando el maestro
Ahora es necesario configurar el maestro. Podéis observar el parecido que hay en el archivo buildbot.tac
con el del esclavo. Dejaremos las opciones tal y como están.
Vamos con el complicado: master.cfg
.
Sí, es python. Pero para hacer lo básico no es necesario saber python, sino seguir los consejos de los comentarios. La ventaja de utilizar python es que ofrece mucha versatilidad.
Por defecto trae configurado el proyecto pyFlakes, que vamos a cambiar por pyDoubles. Veremos que no es tan complejo. Voy a pegar todo el archivo, pero si lo comparáis, veréis que sólo han cambiado las secciones “ChangeSources”, “Builders” y “Project Identity "
|
|
Ejecutando el maestro
Ningún misterio: desde el directorio del maestro, basta ejecutar:
example-master$ buildbot start
Ejecutando el esclavo
Tampoco tiene misterio: desde el directorio del esclavo, basta ejecutar:
example-slave$ buildslave start
Y todo debería ir correctamente.
Lanzando una build (cómo usar la GUI)
Si os habéis fijado en los logs o en el archivo de configuración, el maestro está sirviendo una web en https://localhost:8010/. Lo primero que haremos será LogIn. Como no lo hemos modificado en el archivo de configuración, bastará con usar pyflakes/pyflakes (si dudáis, mirad la sección de autenticación del archivo master.cfg
).
Una vez autenticados, podemos irnos a la sección “Waterfall” y pulsar sobre “runtests”. Eso nos mostrará la página de ejecución de tests, donde está todo configurado. Basta pulsar el botón “Force Build”. Y, si todo es correcto, debería haberse ejecutado la batería de pruebas.
La ventana más útil para ver resultados es la de Waterfall. A partir de ahí no os costará mucho navegar el resto.
Comparativa entre BuildBot y Jenkins
A menudo las comparativas son odiosas. Éste es uno de esos casos. No se puede decir que uno sea mejor que el otro, pero sí que cada cual tiene sus puntos fuertes.
Voy a exponer algunas de estas ventajas de cada uno.
Guardando las configuraciones
Ambos utilizan una base de datos para almacenar los resultados. Sin embargo, la forma de guardar las configuraciones de los trabajos es completamente diferente: Jenkins utiliza archivos XML, mientras que BuildBot utiliza un único archivo Python.
Dado que los archivos de Jenkins no se modificarán a mano, sino utilizando la GUI, resultará dificil mantenerlos en un sistema de control de versiones. Sin embargo, resulta muy sencillo hacerlo con BuildBot.
Configuraciones cambiantes
Si tenemos configuraciones que cambian mucho, entonces es mejor no utilizar BuildBot. En BuildBot las configuraciones son estáticas y se requiere un reinicio del maestro para aplicar los cambios. Por esa razón, en estos casos es mejor utilizar Jenkins.
Si lo único que va a cambiar son algunos parámetros, entonces sí podemos plantearnos usar BuildBot.
Try
BuildBot tiene una característica que Jenkins no tiene: el try. Sirve para “intentar” una build, de manera que coja los cambios locales, aunque no estén en el repositorio, e intente realizar una build con ellos. Esta característica puede resultar de mucha utilidad cuando se quieren probar situaciones que pueden no funcionar correctamente o para probar el propio sistema de CI.
Bonito
Indiscutiblemente, Jenkins es mucho más bonito que BuildBot. Han cuidado mucho más la interfaz.
Además, BuildBot ofrece los resultados sin más, mientras que Jenkins permite procesarlos y presentarlos con una interfaz más bonita.
Ampliable
Jenkins permite la fácil ampliación mediante la creación de plug-ins. Estas extensiones requieren conocimientos de Java, Jelly y, probablemente, un poco de Groovy, además de conocer la API.
Con BuildBot es probable que no necesitemos de ampliaciones, ya que se puede programar sobre la propia build. En caso de necesitarlas, basta con escribir el programa Python adecuado. Para ello, podemos basarnos en el propio código de la clase de la que heredaremos.
Para algunas cosas, será más sencillo el sistema de Jenkins. Para otras, el de BuildBot.
Rápido
Jenkins tarda más de un minuto en reiniciarse. BuildBot breves segundos.
Tras un reinicio, Jenkins pierde el control de los esclavos: no sabe si están ejecutando algo, así que es probable que los trate como desocupados. Esto puede producir que fallen tanto el trabajo en curso como el nuevo. En el caso de que no lance un nuevo trabajo, Jenkins ignorará los resultados del trabajo en curso, por lo que se habrá perdido irremediablemente.
Con BuildBot también se pierde la ejecución en curso. Además, cuando recupera el contacto con el esclavo, relanzará la build que estaba a medias. Sin embargo, el maestro reinicia al esclavo, evitando que haya dos instancias del esclavo corriendo simultáneamente.
La documentación de Jenkins es extensa, pero entrar en el código suele ser complejo. La documentación de BuildBot es bastante buena, aunque la página web está desactualizada: recomiendo descargarse el código y leer la documentación directamente de allí (formato sphinx, que podéis compilar en vuestras máquinas). De todas maneras, es código Python, que suele ser bastante legible.
API
Jenkins tiene API en formatos JSON y XML. Además, ofrece un cliente java bastante potente.
BuildBot tiene API en formato JSON. Es algo más sencilla, pero es normal: la mayor parte de las cosas que queremos hacer estarán escritas en python, en el archivo de configuración.
Jenkins, además, ofrece una interfaz Groovy, sólo disponible para administradores. Sobre esta interfaz debo prevenir que es peligrosa: un descuido en una condición y puedes renombrar todos los trabajos en curso; un System.exit
, y se apagará el servidor.
Otras opciones
No son las dos únicas opciones disponibles. Existen muchas otras, de libre disposición, como CruiseControl, Jenkins, BuildBot, Apache Gump o Apache Continuum. También hay aplicaciones propietarias, como Bamboo o Team Foundation Server.
Otro ejemplo es Travis-CI. En este caso, nos venden el servicio, ya que no resulta sencillo encontrar información sobre cómo instalárnoslo. Aún así, es software libre y el código está disponible.
Como véis, todas estas sólo las mencionaré, ya que nunca las he utilizado. Hay muchas otras. Tan sólo tenéis que elegir una y comenzar a usarla.
En producción
Y como no hay nada mejor que un ejemplo, podéis visitar los waterfall de gente que ya lo está usando:
Y fin
Realmente las condiciones para utilizar cualquier sistema de integración contínua son las mismas: deben existir pruebas y debe ser fácil de desplegar.
La elección de un buen servidor de integración contínua es importante. Al principio será más un estorbo que otra cosa, pero poco a poco termina transformándose en un servicio crítico que, cuando está parado, la empresa no avanza.
Puede parecer exagerado, pero la dependencia con el mismo es importante: termina siendo el juez supremo de nuestros cambios. Si el servidor de CI no lo aprueba, nuestros cambios no se aplican. Da igual cómo nos defendamos o cómo queramos interpretarlo: si no hay verde, nuestro trabajo no está terminado.
Además, un buen servidor de CI nos permitirá recoger estadísticas de uso, de manera que podamos optimizar el proceso. Será interesante evaluar la posibilidad de lanzar varios hilos, comprar más hardware (más esclavos), evaluar el impacto de un cambio, comprobar el estilo de nuestro código, etc.
Elegid uno, y usadlo.