Código Java + BitBucket + Jenkins + Maven en OpenShift

Escenario

Estamos desarrollando una aplicación Java, usando BitBucket como repositorio Git privado, y queríamos tener un Jenkins en línea para tener nuestro código contínuamente testeado y empaquetado cada vez que metíamos código nuevo al repo. Así que decidimos darle una oportunidad a OpenShift.

Sobre OpenShift

OpenShift ofrece una cuenta gratuita con tres “small gears” (“pequeños engranajes”?), donde podés instalar lo que sea que quieras. También te permite instalar algunas aplicaciones con solo un par de clicks, todo preconfigurado. A éstas se las llama “cartuchos” (si, como esos juegos de family game!).

Estos gears tienen algunas limitaciones: 1Gb de espacio de disco y 512 Mb de RAM. Pero funcionan de una, sin más configuración, podés conectarte por SSH, te ofrece tu propio repo Git para actualizar la aplicación (el gear se reinicia y carga los cambios cuando pusheas algo), te da tu propio dominio e incluso pueden ser creados y destruidos para optimizar su uso. Muy groso!

Así que el cartucho de Jenkins ahí usa un gear y siempre está online. Cuando le pedís ejecutar un job, otro gear se crea o reusa para el job executor que se va a encargar del proceso. Este gear se termina destruyendo después de 15min de inactividad.

Si el gear es nuevo, el job executor clona el repo y baja todo de cero (código, artefactos, plugins etc), compila y arma todo y los resultados son colectados por el gear principal (donde está el Jenkins, no sé exactamente el proceso, es automágico). Por supuesto, si el gear ya existe y se reusado, el job executor actualiza el repo y corre con todo lo que ya tenía, obviamente más rápido.

No encontré donde se puede configurar para que el gear del job executor permanezca activo siempre, principalmente para evitar que haga todo de nuevo cada vez. De cualquier forma, no investigué mucho sobre el tema y parece que el único problema es que el job toma más tiempo, porque el resto funciona bárbaro (igual, ojo ahí si pensás correr varios jobs al mismo tiempo).

Hacer que Jenkins consiga el código

Una vez que tenés tu Jenkins andando, podrías necesitar acceder a tu repo para clonarlo.

Credenciales SSH para clonar el repo de BitBucket

  • Conectarse al servidor de Jenkins con SSH.
  • Generar las credenciales SSH de dicho usuario con:
    ssh-keygen -t rsa
  • Guardar las credenciales en alguna parte dentro de $OPENSHIFT_DATA_DIR.
  • Agregarlas a Jenkins, en la página de configuración de “Administrar Credenciales”. Yo guardé las mías acá:
    $OPENSHIFT_DATA_DIR/sshkeys/id_rsa
  • Finalmente, hay que ir a BitBucket para permitirle a Jenkins clonar el repo con esas credenciales, usando Configuration/Deployment keys/Add key”, y agregando la clave pública.

Una vez agregada la clave, ya está listo. Podés seguir el proceso de clonación desde la consola del job. No hay nada más para hacer.

Después, decirle a Maven que arme el proyecto

El problema

Hay un gran problema con este esquema de Integración Continua (digo, código Java + repo en BitBucket + Jenkins en OpenShift): Incluso cuando Jenkins fue instalado mega fácil y funciona sin mayores configuraciones, la integración con Maven simplemente APESTA. Porqué? Maven usa el directorio ~/.m2 por defecto para buscar su settings.xml y guardar su repositorio de artefactos. Pero el gear no provee acceso de escritura a $HOME al proceso, solamente a $OPENSHIFT_DATA_DIR. Así que intentar usar un job de tipo Maven2/Maven3 no va a funcionar.

Por otro lado, el gear que correrá Maven es creado cuando se necesita el job executor, por lo tanto cualquier configuración para cambiar los valores por defecto debe traerse de otro lugar. Una alternativa es guardarla en el mismo repositorio, pero estaremos mezclando configuración específica del server con archivos del proyecto. Otra alternativa es que el mismo job configure Maven de alguna forma.

¿Cómo lo “atamo con alambre”?

  • crear un job vacío
  • agregar un paso para ejecutar un script de consola después de clonar el repo
  • usar ese script para crear un settings.xml en el directorio $OPENSHIFT_DATA_DIR que le diga a Maven que guarde su repo en alguna parte dentro de éste directorio.
  • correr los goals de Maven para armar el proyecto pasándole por parámetro el path de nuestro settings.xml

Ejemplo de script

 cd $OPENSHIFT_DATA_DIR
 echo -e "74settings>\n 74localRepository>$OPENSHIFT_DATA_DIR74/localRepository>\n74/settings>\n" > settings.xml
 cd ../../$WORKSPACE/ok-prototype-backend
 mvn clean package -s $OPENSHIFT_DATA_DIR/settings.xml

¿Cómo disparar la ejecución del job cuando cambia el repo?

Ahora necesitamos decirle al Jenkins que inicie el job cada vez que el repo se actualiza, automáticamente, así no necesitamos andar chequeando nosotros mismos cuando subimos código nuevo.

Para lograr ésto, usamos el “POST hook” en el repo de BitBucket, donde solo hace falta construir la url del Jenkins para que dispare dicho job de la siguiente forma:
https://USUARIO:APITOKEN@URL_DE_JENKINS/job/NOMBRE_DE_JOB/build?token=TOKEN

donde:

  • USUARIO: es el usuario de Jenkins que dispara el job
  • APITOKEN: es el token asociado a ese usuario, que le permite usar la API de Jenkins, se obtiene de la página de configuración de dicho usuario en Jenkins
  • URL_DE_JENKINS: la url de tu Jenkins
  • NOMBRE_DE_JOB: el nombre del job
  • TOKEN: este es el token asociado al job, que se debe agregar en la configuración del mismo (habilitar ejecuciones remotas o algo así)

Lo bueno de este “hook”, es que podés revisar si funciona simplemente desde la consola usando curl.

Cabe notar que no hay passwords en la url, solo tenés el TOKEN del API en su lugar, esto es para evitar andar publicando usuario y clave por ahí.
Una cosa más que hacemos para mejorar un poquito la seguridad es que éste usuario que dispara los jobs remotamente sea un usuario distinto a los miembros del equipo, que solo tenga permiso de lectura de los jobs y para ejecutarlos. Así no tenemos que publicar el usuario y token de alguno de los usuarios propios, que tienen más privilegios.

El contenido de este post está basado en estos documentos (en Inglés):

Si conocés otra forma de hacer ésto, o formas mejores para conseguir estás integraciones, por favor compartila, si?

Anuncios

2 comentarios en “Código Java + BitBucket + Jenkins + Maven en OpenShift

  1. Excelente post, gracias por compartir tu experiencia en esta configuración, faltaría solo agregar algún sistema de tickets tipo redmine corriendo también en openshift y combinar con hooks para tener un entorno bien completo.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s