Debug java in kubernetes

Debug java in kubernetes

Recently, when implementing a feature in our application, I had a NullPointerException issue that would occur only on Kubernetes. This issue was not reproducible on local, and was not reproducible running the docker container either. To debug this issue, I had to set up a remote debugging session. These are the steps to setup this session:-

First, change the Java startup command by adding the jdb parameters. In my applications case, it meant changing it from

java -cp ". /conf/:./lib/\*" -noverify com.app.name
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=_:5005 -cp ". /conf/:./lib/_" -noverify com.app.name

Note that the exact parameters differ based on JDK version. The above example is valid for JDK 9 or higher.

At this point you have an application that has exposed a debug port on port 5005. If you run this application, the first printed line would be: Listening for transport dt_socket at address: 5005 . If this gets printed you know that the java application has been correctly configured.

This application can now be deployed on K8S. We need to expose the 5005 port in the container section of our deployment so that it is accessible from outside Kubernetes. In your deployment.yaml make the following change to expose the port:

spec:
template:
spec:
containers:
- name: java-app
ports:
- containerPort: 5005
name: "debug"

Kubectl provides us a port forward command to be able to access a pods port as if it were a local port. To set this up do the following:

Get the name of the pod using the get pods command.

$ kubectl get pods -n app-namespace
NAME READY STATUS RESTARTS AGE
java-app-6c54c9b858-7bpbp 3/3 Running 1 6d2h

Then use the kubectl port-forward command to forward the 5005 port of the pod to your local machine.

$ kubectl port-forward java-app-6c54c9b858-7bpbp 5005:5005 -n app-namespace
# With this, the debug session should be available at localhost:5005.

Next, you need to setup the debug configuration in your favourite IDE. My preference is to use IntelliJ IDEA. In IDEA, the steps are as follows:

  • From the main menu, select Run | Edit Configurations or press ⌃⌥R then 0.
  • In the Run/Debug Configurations dialog, click the Add New Configuration button and select Remote.
  • Fill out the details for host as localhost and port and 5005. Make sure you select the correct JDK version.
  • Save the configuration

With this configuration is saved you can click on the debug icon to debug at any time!

I'm Hiranmaya Gundu, a dev exploring web and systems programming. This is my personal blog!

Источник

How to Remote Debug A Java Application In a Kubernetes Pod

Let’s consider we have a Java application that provides some REST endpoints and you want to debug it using your IDE.

Let’s create a simple application in Spring Boot, that provides a simple REST endpoint.

@RestController public class WebController   @GetMapping("/")  public ResponseEntity get()  return ResponseEntity.ok("All Works fine");  > > 

Now, we will create a docker image of this application with maven using Google’s JIB plugin.

plugin>  groupId>com.google.cloud.toolsgroupId>  artifactId>jib-maven-pluginartifactId>  version>3.2.1version>  configuration>  from>  image>openjdk:17image>  from>  to>  image>ghcr.io/amrutprabhu/$:$image>  to>  configuration>  executions>  execution>  phase>verifyphase>  goals>  goal>buildgoal>  goals>  execution>  executions> plugin> 

There are other plugins to dockerize your application and you can explore some of the popular ones in my article here.

Now, when we run mvn clean verify , the docker image will be built and pushed to the GitHub repository.

Deploying Docker Images on Kubernetes

Let’s consider you already have a Kubernetes cluster to deploy your application. If not, you can run a local Kubernetes cluster using https://k3s.io.

We will be using this K3s cluster to deploy our application.

To deploy our application, we are going to create a simple helm chart with a deployment definition as follows.

apiVersion: apps/v1 kind: Deployment metadata:  name: application-deployment spec:  selector:  matchLabels:  app: application template:  metadata:  labels:  app: application spec:  containers:  - image: ghcr.io/amrutprabhu/remote-application:1.0.0-SNAPSHOT imagePullPolicy: Always ports:  - name: http containerPort: 8080  protocol: TCP - name: debug-port containerPort: 5005  protocol: TCP env:  - name: JAVA_TOOL_OPTIONS value: '-Xdebug -agentlib:jdwp=transport=dt_socket,address=0.0.0.0:5005,server=y,suspend=n' 

The most important thing for us is the environment variable JAVA_TOOL_OPTIONS set in the deployment.

Since we are using OpenJDK images, the JVM will pick up this environment variable to allow you to attach a debugger to the port 5005 .

Now, you can deploy the application using helm install

Once you deploy the application, you need to port forward the port 5005 to attach our debugger.

kubectl port-forward your pod name> 5005:5005 

Similarly, we will port forward port 8080 to call our REST endpoint.

Attaching Remote Debugger with Intellij

To attach a debugger, go to the run section in the right-hand corner and add a “Remote JVM debug” run configuration.

As you can see, the command line argument shown above is the same value we specified as the environment variable in the deployment file.

That is it. You can now run the configuration and the debugger will be attached.

Attaching Remote Debugger with VSCode

To attach a remote debugger using VScode, we need to add a launch configuration as below

  "version": "0.2.0",  "configurations": [    "type": "java",  "name": "Remote debugging RemoteApplication", // name for you your configuration  "request": "attach",  "hostName": "localhost",  "projectName": "remote-application", // your java project  "port": "5005" // port to attach to  >  ] > 

To add this launch configuration, go to “Run and Debug” on the left bar, then click on the gear icon on the top to open “launch.json”.

Once this is done, start the configuration and the debugger will be attached. Add your breakpoint and send a request on the endpoint for the debugger to pause the execution as shown below.

I keep exploring and learning new things. If you want to know the latest trends and improve your software development skills, then subscribe to my newsletter below and also follow me on Twitter.

Источник

Remote debugging of Java apps in Kubernetes

"It works on my machine ¯_(ツ)_/¯" - the older generation of developers often used this phrase in daily life. With Docker and Kubernetes there are platforms that solve such problems today. But don’t be too happy about it: sometimes your application does not do what was implemented and tested locally. An experienced developer would turn on the debugger in such a case, but is that so easy on a Kubernetes cluster? Yes, and we'll show you exactly how in this blog post! For the sake of simplicity, we will use the IntelliJ development environment throughout this post, but that should not be a big limitation - other development environments offer similar features.

Concept

Concept

The underlying idea is to enable debugging on a port in the Kubernetes pod (in which the Java app is running). This port must be exposed by the Pod. Afterwards, a local port must be forwarded to the open debugging port of the pod using Port Forwarding. Last but not least, JVM Remote Debugging must be started in the development environment with the forwarded local port. The following diagram shows the structure of remote debugging in a Kubernetes cluster:

Step 0: Setting up JVM remote debugging in IntelliJ

Editing Run Configurations

The first step is to set up remote debugging in IntelliJ. To do this, open please the configuration window for Run Configurations :

  1. Create a new Run Configuration by clicking on the plus symbol in the upper left corner and selecting Remote JVM Debug from the list.
  2. Then you can give the configuration any name you like.
  3. The standard configuration usually does not need to be adjusted. If the default port 5005 is used elsewhere in your application, you can change it in the configuration.
  4. Now copy the command line arguments, they will be needed in the next step.
  5. Finally, save the configuration, because you will need it later.

Step 1: Enable debugging in the remote JVM

We usually package our applications in Docker Images, which we build with such a Dockerfile:

FROM eclipse-temurin:17-alpine ARG ARTIFACT COPY $ARTIFACT app.jar ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app.jar"] 

Important is the variable $JAVA_OPTS in the ENTRYPOINT . We use this to insert the previously copied command line arguments. We do this by adapting the deployment resource in Kubernetes. With kubectl get deployments you can display a list of your deployments and with kubectl edit deployment you can adjust the deployment as follows:

spec: containers: - . env: - name: JAVA_OPTS value: ports: - name: remotedebugging containerPort: protocol: TCP . 
  • Replace with the copied command line arguments from IntelliJ.
  • Replace with the port you use for debugging, in our case 5005 .

Once you have done this, you can close the editor and Kubernetes starts a new deployment for you. You can check this with the command kubectl get pods . A new pod should have been created. Important for the next step: Copy the name of the pod!

Step 2: Port Forwarding

After the Pod has been restarted, the debugging port of the Pod must be forwarded to your local machine. This can be done with the following command: kubectl port-forward :

  • is the name of the pod you should have copied in the previous step.
  • must be replaced with the port used locally for forwarding and to which the development environment connects for debugging.
  • is the port you opened in the deployment configuration in the previous step.

Step 3: Happy Debugging!

Finally, the debugging configuration created in Step 0 must be started and the following message should appear: Listening for transport dt_socket at address: 5005 . 🎉

Now you can set breakpoints and find some bugs!

Resources

Источник

Читайте также:  Php and sql website
Оцените статью