multiple app nodes how to expose jmx in kubernetes?
Asked Answered
W

4

52
  1. In kubernetes I can expose services with service. This is fine.
  2. Lets say I have 1 web instance and 10 java server instances.
  3. I have a windows gateway I'm used to access those 10 java servers instances via the jconsole installed on it.
  4. Obviously I do not expose all apps jmx port via kubernetes service.

What are my options here? how should I allow this external to kubernetes cluster windows gateway access to those 10 servers jmx ports? Any practices here?

Week answered 3/2, 2016 at 18:13 Comment(0)
T
146

Another option is to forward JMX port from K8 pod to your local PC with kubectl port-forward.

I do it like this:

1). Add following JVM options to your app:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.rmi.port=1099
-Djava.rmi.server.hostname=127.0.0.1

The critical part here is that:

  • The same port should be used as 'jmxremote.port' and 'jmxremote.rmi.port'. This is needed to forward one port only.

  • 127.0.0.1 should be passed as rmi server hostname. This is needed for JMX connection to work via port-forwarding.

2). Forward the JMX port (1099) to your local PC via kubectl:

kubectl port-forward <your-app-pod> 1099

3). Open jconsole connection to your local port 1099:

jconsole 127.0.0.1:1099

This way makes it possible to debug any Java pod via JMX without having to publicly expose JMX via K8 service (which is better from security perspective).

Another option that also may be useful is to attach the Jolokia (https://jolokia.org/) agent to the Java process inside the container so it proxies the JMX over HTTP port and expose or port-forward this HTTP port to query JMX over HTTP.

Tellurion answered 7/10, 2016 at 23:44 Comment(10)
This is the most straightforward explanation I've encountered and works perfectly. Thanks!Quartis
Thank you! Big helpSausauce
setting -Djava.rmi.server.hostname=127.0.0.1 did the trick for us.Neolithic
How to add the JVM options to the app? Is there any file where those options have to be added? We're deploying a WAR file to Tomcat server in the container.Kyungkyushu
Perfect explanation. Thanks you!Impend
I owe you a coffee!Whilst
How can I connect to this jmx server from a remote host ?Shayn
@Tellurion hostname can be tricked in hosts file, but how about two diff ports (for port and rmi.port)? Any chance on correct forwarding in such case?Teetotum
Wow. Have been searching all over for this. Now it makes sense. Thanks a lot!Dimitri
This amazing answer lacks just one detail which I found in another answer https://mcmap.net/q/293417/-unable-to-remotely-connect-to-jmx: "Then when I tried to use VisualVM to connect to localhost:9001, the connection was refused. JMX seems to require port numbers on both sides to be identical." That completed the trick for me.Czarra
T
4

Adding to https://mcmap.net/q/342229/-multiple-app-nodes-how-to-expose-jmx-in-kubernetes, I wanted to monitor all instances of the same pod at once, since we are hardcoding the port as 1099, it was difficult as I can do only one portforward to one pod with that port.

I used Shell Script to dynamically assign pod when running the docker

Dockerfile CMD /run.sh

run.sh

JMX_PORT=$(((RANDOM % 20)+1099))

echo "Running JMX on Port $JMX_PORT"

java ``eval echo $JAVA_OPTS`` ...

deployment.yml env: - name: JAVA_OPTS value: "-Xms256m -Xmx6144m -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=$JMX_PORT -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT -Djava.rmi.server.hostname=127.0.0.1"

the eval will evaluate the JMX_PORT to bash value, each pod when starts will likely to get different pod. I

Tabathatabb answered 9/9, 2018 at 9:20 Comment(0)
D
3

We did it in following way

  1. Add a unique label for each pod. ex: podid=asdw23443
  2. Create a new service with selector of podid=asdw23443. Make sure in the service you expose jmx ports on pod through nodeport or loadbalancer.

If you are selecting nodeport in service, because you a doing a NAT operation you may have to give following JVM argument for each jvm you need to connect through jconsole

-Djava.rmi.server.hostname=<your-ip-address>
Dovetail answered 20/2, 2016 at 3:1 Comment(4)
I'm not sure I get it is it that you have a podid for each instance of the pod? so if you scale it up from 10 to 20 then you have access to each and every of the pod instances without a load balancer? I want access to a specific pod instance.Week
I'm not sure I get it is it that you have a podid for each instance of the pod? so if you scale it up from 10 to 1000 then you have 1000 services?Week
Yes in this approach you have to create a service per pod. If you have 1000 pods then there should be 1000 services.Dovetail
One thing I'm struggling with: how can I set a JVM arg to the IP address running the process, when I don't know ahead of time which worker the pod will be scheduled to?Plinth
M
1

I think one way is to add a label to your pod with a unique string \ id for example pod_name and use the expose command to create a new service with the selector of this unique id\string.

kubectl label pods <podname> podname=<podname>
kubectl expose pod <podname> --port=9010 --name=<podname>_jmx
Museology answered 19/2, 2016 at 10:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.