En este post vamos a explicar cómo configurar nuestro servidor Bitbucket Server para que pueda ser monitorizado con AppDynamics con el fin de medir y optimizar su rendimiento.
Atlassian Bitbucket Server es un sistema de control de versiones auto-alojado basado en Git, para la administración de repositorios de equipos empresariales y que además permite a todo el mundo colaborar fácilmente en sus repositorios.
AppDynamics es una potente herramienta para la gestión del rendimiento de aplicaciones, lo que se conoce como un APM por sus siglas en inglés (Application Performance Management) que proporciona una gestión end-to-end centrada en las transacciones de negocio de las aplicaciones.
AppDynamics proporciona, además, una serie de extensiones para algunos de los productos Atlassian, que permiten monitorizar e integrarse de forma rápida y sencilla.
Así que vamos al lío, es hora de comprobar qué tal rinde nuestro servidor de control de versiones.
Las siguientes instrucciones son válidas para una instancia de Bitbucket Server y AppDynamics instaladas en un SO Linux sin SSL.
Antes de nada, habilita JMX
Lo primero que deberemos hacer es habilitar JMX MBeans en nuestro servidor Bitbucket ya que las métricas son extraídas a través de este protocolo. JMX (Java Management eXtensions) es una tecnología para monitorizar y administrar aplicaciones Java que utiliza objetos denominados MBeans para exponer datos y recursos de la aplicación.
Por defecto Bitbucket Server se inicia con JMX deshabilitado. Para habilitarlo seguiremos estos pasos:
1 - Editar (o crear si no existe) el archivo bitbucket.properties ubicado en la carpeta <bitbucket_home>/shared
, incluyendo la siguiente propiedad:
jmx.enabled=true
2 - Creamos en la misma ubicación un archivo llamado jmx.access donde definiremos la contraseña para JMX añadiendo la siguiente propiedad:
monitorRole=<mypassword>
3 - Por último editamos el archivo de configuración de entorno setenv.sh modificando las siguientes propiedades tal y como se indica:
JMX_REMOTE_AUTH=password
JMX_REMOTE_PORT=3333
RMI_SERVER_HOSTNAME=-Djava.rmi.server.hostname=hostname>
JMX_PASSWORD_FILE=<path-to>/jmx.access
4 - Será necesario reiniciar Bitbucket para que tomen efecto los cambios.
Para comprobar que JMX está correctamente configurado ejecutaremos desde una consola de comandos el comando jconsole y crearemos una conexión nueva:
Si la configuración es correcta aparecerán diferentes estadísticas de rendimiento del servidor:
Configurando la extensión de AppDynamics
Una vez habilitado JMX estamos listos para configurar la extensión de AppDynamics para Bitbucket Server
Desde este enlace descargamos la extensión y descomprimimos su contenido en la siguiente ruta <MACHINE_AGENT_HOME>/monitors
Modificamos el archivo config.yml ubicado dentro de <MACHINE_AGENT_HOME>/monitors/BitbucketMonitor
en el bloque donde pone #List of Bitbucket Instances
# List of Bitbucket Instances
instances:
- host: "pirineos"
port: 7990
username: "monitorRole"
password: "<your-jmx-password>"
#encryptedPassword:
#encryptionKey:
displayName: "LocalBitbucket" #displayName is a REQUIRED field for level metrics.
Y por último indicamos la ruta completa al archivo config.yml editando el archivo monitor.xml ubicado en la ruta <MACHINE_AGENT_HOME>/monitors/BitbucketMonitor
en el apartado <task-arguments>
<monitor>
<name>BitbucketMonitor</name>
<type>managed</type>
<description>AppDynamics Monitoring Extension for use with Atlassian Bitbucket</description>
<monitor-configuration></monitor-configuration>
<monitor-run-task>
<execution-style>periodic</execution-style>
<execution-frequency-in-seconds>60</execution-frequency-in-seconds>
<name>Bitbucket Monitor Run Task</name>
<display-name>Bitbucket Monitor Task</display-name>
<description>Bitbucket Monitor Task</description>
<type>java</type>
<execution-timeout-in-secs>60</execution-timeout-in-secs>
<task-arguments>
<!-- config file-->
<argument name="config-file" is-required="true" default-value="/var/appdynamics/machineagent/monitors/BitbucketMonitor/config.yml" />
</task-arguments>
<java-task>
<classpath>bitbucket-monitoring-extension.jar</classpath>
<impl-class>com.appdynamics.extensions.bitbucket.BitbucketMonitor</impl-class>
</java-task>
</monitor-run-task>
</monitor>
¡Listo! Bitbucket Server está preparado para ser monitorizado por AppDynamics. Para que esto suceda de forma automática vamos a indicar en el setenv.sh de Bitbucket que ejecute el agente de aplicación siempre que Bitbucket se inicie, añadiendo la siguiente configuración justo donde se declara la variable CATALINA_OPTS:
export JAVA_OPTS="-Xms${JVM_MINIMUM_MEMORY} -Xmx${JVM_MAXIMUM_MEMORY} ${JAVA_OPTS} ${JVM_REQUIRED_ARGS} ${JVM_SUPPORT_RECOMMENDED_ARGS} ${BITBUCKET_HOME_MINUSD}"
CATALINA_OPTS="${JMX_OPTS} ${CATALINA_OPTS}"
#export CATALINA_OPTS
export CATALINA_OPTS="${CATALINA_OPTS} -javaagent:/var/appdynamics/appserveragent/javaagent.jar"
OSGi y los contenedores perdidos
Y aquí viene el pequeño quebradero de cabeza que puedes encontrarte cuando vayas a arrancar tu servidor de Bitbucket con la nueva extensión por primera vez.
Después de esperar unos segundos viendo cómo carga la barra de progreso, cuando parece que va a llegar al final y todo es maravilloso, un mensaje de error asaltará tu navegador advirtiéndote de que numerosos add-ons no han podido ser iniciados y el archivo de log será un flujo continuo de errores.
¿Pero qué $%@&# está pasando?
Bien, resulta que una parte fundamental del core de Bitbucket, en concreto de los add-ons, se basa en OSGi.
OSGi es un sistema dinámico de módulos para Java. Una de sus características es estar formado por un sistema de dependencias de paquetes (bundles). Un bundle o contenedor es un archivo JAR con entradas OSGi especiales en su manifiesto y que contiene clases, recursos y otros JARs.
AppDynamics y GlassFish también utilizan la arquitectura OSGi. Por defecto, los contenedores OSGi siguen un modelo específico de delegación de clases en el arranque. Las clases no especificadas en el classpath del contenedor no se delegarán, por tanto, es necesario configurar los contenedores OSGi para las clases del Agente Java.
Para asegurarnos que el contenedor OSGi identifica al Agente Java, hay que especificar el prefijo de paquete siguiente:
org.osgi.framework.bootdelegation=com.singularity.*
¡Ojo! Hay que tener en cuenta que si ya existen delegaciones durante el arranque, lo que tenemos que hacer es añadir la que nos toca, com.singularity.*, a las ya existentes separado por comas. Por ejemplo:
org.osgi.framework.bootdelegation=com.sun.btrace.*,com.singularity.*
Volviendo a nuestro servidor de Bitbucket, lo que tendremos que hacer es agregar la siguiente propiedad de sistema Java junto con el resto de propiedades ya existentes.
-Datlassian.org.osgi.framework.bootdelegation=META-INF.services,com.yourkit,com.singularity.*,com.jprofiler,com.jprofiler.*,org.apache.xerces,org.apache.xerces.*,org.apache.xalan,org.apache.xalan.*,sun.*,com.sun.jndi,com.icl.saxon,com.icl.saxon.*,javax.servlet,javax.servlet.*,com.sun.xml.bind.*
Hay varios sitios donde se puede incluir esta propiedad. En mi caso, la he incluido en el archivo de arranque setenv.sh justo debajo de donde se define la variable JAVA_OPTS quedando de la siguiente forma:
export JAVA_OPTS="-Xms${JVM_MINIMUM_MEMORY} -Xmx${JVM_MAXIMUM_MEMORY} ${JAVA_OPTS} ${JVM_REQUIRED_ARGS} ${JVM_SUPPORT_RECOMMENDED_ARGS} ${BITBUCKET_HOME_MINUSD}"
export JAVA_OPTS="${JAVA_OPTS} -Datlassian.org.osgi.framework.bootdelegation=META-INF.services,com.yourkit,com.singularity.*,com.jprofiler,com.jprofiler.*,org.apache.xerces,org.apache.xerces.*,org.apache.xalan,org.apache.xalan.*,sun.*,com.sun.jndi,com.icl.saxon,com.icl.saxon.*,javax.servlet,javax.servlet.*,com.sun.xml.bind.*"
CATALINA_OPTS="${JMX_OPTS} ${CATALINA_OPTS}"
#export CATALINA_OPTS
export CATALINA_OPTS="${CATALINA_OPTS} -javaagent:/var/appdynamics/appserveragent/javaagent.jar"
Ahora sí que sí, Bitbucket Server se iniciará correctamente con AppDynamics monitorizando todas y cada una de sus transacciones.
Espero que os haya servido de ayuda.
¡Feliz APM a todos!
Si te ha gustado, ¡síguenos en Twitter!