Configurar JMX para Tomcat con Docker

Cada cierto tiempo me toca configurar JMX para Tomcat y siempre no tengo mis apuntes a mano, por lo que sirva esta entrada para ello y para quien le pueda interesar.

Logo oficial de Tomcat

Antes de nada, como viene siendo habitual, os comento que estoy haciendo todas las pruebas y cacharreos, en el entorno de pruebas que tengo en los VPS ofrecidos por  la compañía Clouding.io

Configurar JMX para Tomcat con Docker

¿Qué es JMX?

Seguramente a gran parte de las personas que visitan esta web esto le puede resultar un poco extraño si no son administradores de sistemas y han batallado con Tomcat

JMX (Java Management Extension) es una tecnología que permite administrar, monitorear y configurar Tomcat.

Se trata de una herramienta clave si administramos Tomcat para monitorear su memoria, sus subprocesos, su uso de CPU, entre otros.

Configurar JMX para Tomcat en Docker

A diferencia de otros tutoriales que hay por la red de redes, en nuestro caso vamos a ver como configurar un contenedor con Tomcat, para que admita los parámetros de JMX. Tengo que decir que esto me ha dado un poco de guerra, a la vez que me ha resultado entretenido 🙂

En mi caso, como verás más adelante, he utilizado un contenedor con Tomcat hecho a media por mi. Su fichero de Dockerfile lo puedes encontrar aquí: Github – Dockerfile sobre RockyLinux 9 con Tomcat 10

En el fichero Docker Compose definimos varias cosas, entre ellas que vamos utilizar el usuario de Tomcat, los puertos ha utilizar y una serie que ficheros imprescindibles en este caso:

version: '2.2'
 
x-logging: &loki-logging
  driver: json-file
  options:
    tag: "{{.ImageName}}|{{.Name}}|{{.ImageFullID}}|{{.FullID}}"
 
networks:
  loki:
 
services:
  tomcat:
    image: davidpenya77/rockylinux9-tomcat
    user: "0:1000"
    ports:
      - '8080:8080'
      - '9090:9090'
    volumes:
    - "./setenv.sh:/opt/tomcat/bin/setenv.sh"
    - "./jmxremote.access:/opt/tomcat/conf/jmxremote.access"
    - "./jmxremote.password:/opt/tomcat/conf/jmxremote.password"
    networks:
      - loki
    logging: *loki-logging

Esta configuración está pensada para funcionar con Loki, para ver los logs vía Grafana, sino os interesa esta parte la podéis obviar.

Tal y como se observa utilizamos varios ficheros, en el primero llamado «setenv.sh«, definimos las variables de entorno que vamos a utilizar. Aquí es importante, de hecho es una de las partes que me ha dado mucha guerra, que utilicemos un fichero standard de setenv.sh y luego lo modifiquemos. Yo he utilizado este: Github.com – setenv.sh, pero vamos, que hay muchos por internet. Una vez lo tenemos le añadimos, justo al final de los «export»:

export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.port=9090 \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.rmi.port=9090 \
-Djava.rmi.server.hostname="IP-DEL-SERVIDOR" \
-Dcom.sun.management.jmxremote.ssl=false"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.password.file=/opt/tomcat/conf/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=/opt/tomcat/conf/jmxremote.access

Os explico los parámetros:

  • -Dcom.sun.management.jmxremote , habilitamos JMX
  • -Dcom.sun.management.jmxremote.local.only=false, indicamos que se puede conectar a la JMX de forma remota.
  • -Dcom.sun.management.jmxremote.port=9000, indicamos al puerto utilizar por JMX, en este caso el 9000
  • -Dcom.sun.management.jmxremote.authenticate=true, habilitamos la conexión de forma autentificada.
  • Dcom.sun.management.jmxremote.rmi.port=9090, indica el puerto remoto a utilizar
  • -Djava.rmi.server.hostname=«IP-DEL-SERVIDOR«
  • -Dcom.sun.management.jmxremote.ssl=false, deshabilitamos la conexión por SSL
  • -Dcom.sun.management.jmxremote.password.file=/opt/tomcat/conf/jmxremote.password, indicamos el fichero donde esta ubicada la contraseña para cada usuario.
  • -Dcom.sun.management.jmxremote.access.file=/opt/tomcat/conf/jmxremote.access, indicamos los usuarios que se pueden conectar y sus roles.

Ahora nos queda definir los fichero con usuario que utilizará JMX, ya que el acceso es autentificado, además del fichero con la contraseña.

Primero creamos el fichero «jmxremote.access» y añadimos con nuestro editor favorito:

jmxrouser readonly
jmxrwuser readwrite

Es decir, definimos uno de solo lectura y otro que también tiene escritura.

En el siguiente creamos el fichero «jmxremote.password«, donde vamos a definir la contraseña para cada usuario:

jmxrouser contrasea
jmxrwuser contrasea

Es muy importante, sino queremos tener problemas, que ahora le asignemos los siguientes permisos:

chmod 600 jmxremote.password

Nos deberían quedar los siguiente ficheros, una vez hechos todos estos pasos:

├── docker-compose.yml
├── jmxremote.access
├── jmxremote.password
└── setenv.sh

Ahora solo nos falta levantar el fichero de Docker Compose:

docker-compose up -d

Comprobaciones

Vale, todo esto es muy bonito, ¿pero funciona?

Veamos primero los logs del contenedor:

docker logs "contenedor"

Y en mi caso tiene una pinta como sigue:

Revisamos el registro del contenedor con Tomcat

Además, si os habéis fijado en los parámetro definidos para JMX, hemos habilitado el acceso remoto desde cualquier sitio. Sí, no es lo más seguro, pero esto solo es una prueba. Lo recomendado es restringir el acceso desde el lugar que decidamos.

En esta ocasión voy a utilizar «jconsole«, incluida en el kit SDK de Java, lo podéis descargar aquí: Oracle.com – JDK

Existen más opciones que podemos utilizar, de ello os hablé en esta entrada: Herramientas para analizar un Java Thread Dump en Linux

Una vez conectada la herramienta, podemos obtener una información muy amplia:

Información de la actividad de Tomcat con JMX en jconsole

Fuentes consultadas

Tomcat Apache – Monitoring and Managing Tomcat