---
title: Paketo Buildpackで作成したJavaコンテナイメージでトラブルシューティングを行うメモ
summary: この記事では、PaketoTinyBuilderで作ったJavaコンテナに診断ツールを追加し、jattachとjwebserverでヒープダンプを取得する方法を紹介します。
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
---

`mvn spring-boot:build-image`/`gradle bootBuildImage`あるいはPaketo Buildpackで作成したJavaのコンテナイメージはデフォルトではJREが使われ、JDKは含まれていません。そのため、`jstack`や`jcmd`などの診断用のツールがコンテナには含まれません。
また、最近のSpring BootではBuilderとして[Paketo Noble Java Tiny Builder](https://github.com/paketo-buildpacks/builder-noble-java-tiny)を使用します。
このBuilderのStackは[ubuntu-noble-run-tiny](https://github.com/paketo-buildpacks/ubuntu-noble-base-images/tree/main/stacks/noble-tiny-stack/run)であり、scratchに必要最小限のファイルを追加したイメージです。
すなわち、このイメージには`bash`や`sh`などのシェルも含まれていません。
これはイメージの軽量化および、マルチアーキテクチャのサポートのためには必要なことですが、トラブルシューティングの際に不便になることがあります。

このBuilderを使いつつ、トラブルシューティングもできるようにしたいですよね。まずは、`jcmd`でスタックトレースやヒープダンプを取れるようにしたいです。
そこで便利なのが[Paketo Buildpack for Jattach](https://github.com/paketo-buildpacks/jattach)です。

[jattach](https://github.com/jattach/jattach)は実行中のJavaプロセスに動的に接続して操作を実行するための軽量なコマンドラインツールです。
[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/)、[jinfo](https://dev.java/learn/jvm/tool/troubleshooting/jinfo/)の機能が一つのバイナリにまとまっています。
Paketo Buildpack for Jattachはこのjattachをコンテナイメージに追加するBuildpackです。

Paketo Buildpack for Jattachはデフォルトでは有効になっていませんが、ビルド時の環境変数`BP_JATTACH_ENABLED`を`true`に設定することで有効化できます。
Mavenの場合は次のような設定で`jattach`がイメージに含まれるようになります。

```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>
```

これでコンテナ内で`jattach`を使ってスタックトレースやヒープダンプを取れるようになります。`jattach`のパスは`/layers/paketo-buildpacks_jattach/jattach/bin/jattach`です。

`jattach`の使い方は次の通りです。

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

次のような出力が得られます。

```
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
```

以下にKubernetesのPod内でヒープダンプを取る例を示します。JavaプロセスのPIDは`1`です。

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

次のようなログが出力されるでしょう。

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

これで`/tmp/heapdump.hprof`にヒープダンプが保存されます。

ではこのヒープダンプファイルを次のコマンドで、ローカルにコピーしましょう。

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

しかし、次のようなエラーが出てコピーできません。`tar`コマンドがPod内に存在しないためです。

```
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
```

では代わりに`cat`コマンドでヒープダンプを標準出力に出し、ローカルで受け取る方法を試みましょう。

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

しかし、またもや次のようなエラーが出てコピーできません。`cat`コマンドもPod内に存在しないためです。

```
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
```

このように、Paketo Noble Java Tiny Builderを使って作成したコンテナイメージにはシェルも含まれていないため、`kubectl cp`や`kubectl exec`でファイルをコピーすることができません。

では、どうすればよいでしょうか？実はJREにはあまり知られていないコマンドとして[`jwebserver`](https://dev.java/learn/jvm/tool/jwebserver/)があります。`jwebserver`は小さなHTTPサーバーで、特定のディレクトリを公開することができます。

次のコマンドで、Pod内で`jwebserver`を起動し、`/tmp`ディレクトリをポート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 
```

別ターミナルでローカルの8000ポートをPodの8000ポートに転送します。

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

さらに別ターミナルで、`wget`コマンドでヒープダンプファイルをダウンロードします。

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

これで無事ヒープダンプファイルをローカルに保存できました。

---

Paketo Buildpackで作成したJavaコンテナイメージはデフォルトでは診断ツールが含まれていませんが、`BP_JATTACH_ENABLED=true`環境変数を設定することで`jattach`コマンドを追加できます。
また、Paketo Noble Java Tiny Builderを使用したイメージにはシェルが含まれていないため、通常の`kubectl cp`コマンドは使用できませんが、JREに含まれる`jwebserver`を活用することでファイルのダウンロードが可能になります。

この方法により、軽量なコンテナイメージのメリットを享受しつつ、必要な時にはヒープダンプやスタックトレースなどの診断情報を取得できるようになります。
