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.
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:
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: