---
title: Notes on Troubleshooting Java Container Images Created with Paketo Buildpack
tags: ["Cloud Native Buildpacks", "Paketo", "Java", "jattach", "Spring Boot"]
categories: ["Dev", "Infrastructure", "CloudNativeBuildpacks", "Paketo"]
date: 2025-12-18T10:06:43Z
updated: 2025-12-18T12:21:55Z
---

Java container images created with `mvn spring-boot:build-image`/`gradle bootBuildImage` or Paketo Buildpack use JRE by default and do not include JDK. Therefore, diagnostic tools such as `jstack` and `jcmd` are not included in the container.
Additionally, recent Spring Boot uses [Paketo Noble Java Tiny Builder](https://github.com/paketo-buildpacks/builder-noble-java-tiny) as the Builder.
The Stack of this Builder is [ubuntu-noble-run-tiny](https://github.com/paketo-buildpacks/ubuntu-noble-base-images/tree/main/stacks/noble-tiny-stack/run), which is an image with minimal necessary files added to scratch.
In other words, this image does not include shells such as `bash` or `sh`.
This is necessary for image lightweighting and multi-architecture support, but it can be inconvenient during troubleshooting.

You'd want to be able to troubleshoot while using this Builder, right? We want to be able to take stack traces and heap dumps with `jcmd`.
This is where [Paketo Buildpack for Jattach](https://github.com/paketo-buildpacks/jattach) comes in handy.

[jattach](https://github.com/jattach/jattach) is a lightweight command-line tool for dynamically connecting to and performing operations on running Java processes.
The functionality of [jmap](https://dev.java/learn/jvm/tool/troubleshooting/jmap/), [jstack](https://dev.java/learn/jvm/tool/troubleshooting/jstack/), [jcmd](https://dev.java/learn/jvm/tool/troubleshooting/jcmd/), and [jinfo](https://dev.java/learn/jvm/tool/troubleshooting/jinfo/) is combined into a single binary.
Paketo Buildpack for Jattach is a Buildpack that adds this jattach to container images.

Paketo Buildpack for Jattach is not enabled by default, but can be enabled by setting the build-time environment variable `BP_JATTACH_ENABLED` to `true`.
For Maven, the following configuration will include `jattach` in the image.

```xml
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <image>
            <env>
              <BP_JATTACH_ENABLED>true</BP_JATTACH_ENABLED>
            </env>
          </image>
        </configuration>
        <!-- ... -->
      </plugin>
```

Now you can use `jattach` within the container to take stack traces and heap dumps. The path to `jattach` is `/layers/paketo-buildpacks_jattach/jattach/bin/jattach`.

The usage of `jattach` is as follows.

```bash
NAMESPACE=...
POD_NAME=...
kubectl exec -n $NAMESPACE $POD_NAME -ti -- /layers/paketo-buildpacks_jattach/jattach/bin/jattach help  
```

You will get output like the following.

```
jattach 2.2 built on Jan 10 2024

Usage: jattach <pid> <cmd> [args ...]

Commands:
    load  threaddump   dumpheap  setflag    properties
    jcmd  inspectheap  datadump  printflag  agentProperties
command terminated with exit code 1
```

Below is an example of taking a heap dump within a Kubernetes Pod. The PID of the Java process is `1`.

```bash
NAMESPACE=...
POD_NAME=...
kubectl exec -n $NAMESPACE $POD_NAME -ti -- /layers/paketo-buildpacks_jattach/jattach/bin/jattach 1 dumpheap /tmp/heapdump.hprof
```

You should see log output like the following.

```
Connected to remote JVM
JVM response code = 0
Dumping heap to /tmp/heapdump.hprof ...
Heap dump file created [69843865 bytes in 0.294 secs]
```

This saves the heap dump to `/tmp/heapdump.hprof`.

Now let's copy this heap dump file locally with the following command.

```bash
kubectl cp -n $NAMESPACE $POD_NAME:/tmp/heapdump.hprof ./
```

However, you get an error like the following and cannot copy it. This is because the `tar` command does not exist within the image.

```
time="2025-12-18T09:58:08Z" level=error msg="exec failed: unable to start container process: exec: \"tar\": executable file not found in $PATH"
command terminated with exit code 255
```

Let's try using the `cat` command to output the heap dump to standard output and receive it locally instead.

```bash
kubectl exec -n $NAMESPACE $POD_NAME -- cat /tmp/heapdump.hprof > ./heapdump.hprof
```

However, again you get an error like the following and cannot copy it. This is because the `cat` command also does not exist within the image.

```
time="2025-12-18T10:00:09Z" level=error msg="exec failed: unable to start container process: exec: \"cat\": executable file not found in $PATH"
command terminated with exit code 255
```

As you can see, container images created using Paketo Noble Java Tiny Builder do not include shells, so you cannot copy files with `kubectl cp` or `kubectl exec`.

So what should you do? Actually, JRE has a lesser-known command called [`jwebserver`](https://dev.java/learn/jvm/tool/jwebserver/). `jwebserver` is a small HTTP server that can serve specific directories.

Use the following command to start `jwebserver` within the Pod and serve the `/tmp` directory on port 8000.

```bash
kubectl exec -n $NAMESPACE $POD_NAME -ti -- /layers/paketo-buildpacks_bellsoft-liberica/jre/bin/jwebserver -b 0.0.0.0 -p 8000 -d /tmp 
```

In another terminal, forward local port 8000 to the Pod's port 8000.

```bash
NAMESPACE=...
POD_NAME=....
kubectl port-forward -n $NAMESPACE $POD_NAME 8000:8000
```

In yet another terminal, download the heap dump file with the `wget` command.

```bash
wget http://localhost:8000/heapdump.hprof
```

Now you have successfully saved the heap dump file locally.

---

Java container images created with Paketo Buildpack do not include diagnostic tools by default, but you can add the `jattach` command by setting the `BP_JATTACH_ENABLED=true` environment variable.
Also, images using Paketo Noble Java Tiny Builder do not include shells, so the usual `kubectl cp` command cannot be used, but by utilizing `jwebserver` included in JRE, file downloads become possible.

This method allows you to enjoy the benefits of lightweight container images while being able to obtain diagnostic information such as heap dumps and stack traces when needed.
