CNFS をバックエンドとする NAS ボリュームをマウントすることで、OOM による Pod の再起動後も永続化される .hprof ヒープダンプをキャプチャします。
前提条件
以下を確認してください。
-
CNFS で管理される NAS ファイルシステムがプロビジョニングされていること。
-
Container Registry の Enterprise Edition インスタンスが作成されていること。
注意事項
JVM の最大ヒープを Pod のメモリ制限よりも低く設定してください。 -Xmx は Pod のメモリ制限よりも低く設定してください。JVM ヒープが先に Pod の制限に達した場合、JVM がダンプを書き込む前に Linux の OOM Killer が Pod を終了させてしまいます。
ヒープダンプには専用の CNFS を使用してください。 1 回の OOM イベントで数ギガバイトの .hprof ファイルが生成される可能性があり、共有クォータを使い果たして運用に支障をきたす恐れがあります。
開始する前に File Browser イメージを同期してください。 docker.io/filebrowser/filebrowser:v2.18.0 は、ネットワークの制限によりプルに失敗する可能性があります。「中国以外からのイメージのサブスクライブ」を参照して、ご利用の ACR Enterprise Edition インスタンスに同期してください。
| フィールド | 値 |
|---|---|
| アーティファクトソース | Docker Hub |
| ソースリポジトリ座標 | filebrowser/filebrowser |
| サブスクリプションポリシー | v2.18.0 |
同期後、ACR Enterprise Edition インスタンスと ACK クラスター間でパスワードなしのイメージプルを設定します。
Java アプリケーションのデプロイ
ヒープダンプの保存先として CNFS をバックエンドとするストレージを持つ Java Deployment をデプロイします。サンプルイメージ registry.cn-hangzhou.aliyuncs.com/acs1/java-oom-test:v1.0 は、80 MiB のヒープ制限で Mycode を実行します。
この Deployment は subPathExpr: $(POD_NAMESPACE).$(POD_NAME) を使用して、共有 NAS ボリューム内に Pod ごとのサブディレクトリを作成します。これにより、Pod が再起動しても互いのダンプが上書きされるのを防ぎます。
subPathExprは、波括弧ではなく丸括弧 —$(POD_NAME)— を使用します。値は、Downward API の環境変数POD_NAMEとPOD_NAMESPACEから取得されます。
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-application
spec:
selector:
matchLabels:
app: java-application
template:
metadata:
labels:
app: java-application
spec:
containers:
- name: java-application
image: registry.cn-hangzhou.aliyuncs.com/acs1/java-oom-test:v1.0
imagePullPolicy: Always
env:
- name: POD_NAME # Downward API 経由で Pod 名を挿入
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE # Downward API 経由で Pod の名前空間を挿入
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
args:
- java
- -Xms80m # 最小ヒープサイズ
- -Xmx80m # 最大ヒープサイズ (Pod のメモリ制限より低く設定)
- -XX:HeapDumpPath=/mnt/oom/logs # CNFS をバックエンドとするマウント先にヒープダンプを書き込む
- -XX:+HeapDumpOnOutOfMemoryError # OOM 時にヒープダンプをトリガー
- Mycode
volumeMounts:
- name: java-oom-pv
mountPath: "/mnt/oom/logs"
subPathExpr: $(POD_NAMESPACE).$(POD_NAME) # 波括弧ではなく丸括弧
volumes:
- name: java-oom-pv
persistentVolumeClaim:
claimName: cnfs-nas-pvc
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: cnfs-nas-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: alibabacloud-cnfs-nas
resources:
requests:
storage: 70Gi # ディレクトリクォータが有効な場合、サブディレクトリを 70 GiB に制限
---
EOF
OOM イベントの確認
Deployment が開始されると、Mycode は JVM が 80 MiB のヒープを使い果たして OOM をトリガーするまでメモリを割り当てます。Pod が再起動し、ACK はイベントセンターに back-off restarting アラートを記録します。
OOM が発生したことを確認するには:
-
ACK コンソールにログインします。左側のナビゲーションウィンドウで、[クラスター] をクリックします。
-
対象のクラスターを見つけて、その名前をクリックします。左側のナビゲーションウィンドウで、[運用] > [イベントセンター] を選択します。
-
イベントリストで、
java-applicationPod のback-off restartingアラートを確認します。
ヒープダンプファイルの参照
ヒープダンプを参照してダウンロードするために、同じ CNFS PVC を rootDir にマウントした File Browser をデプロイします。
File Browser のデプロイ
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: filebrowser
namespace: default
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
data:
.filebrowser.json: |
{
"port": 80,
"address": "0.0.0.0"
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: filebrowser
namespace: default
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
template:
metadata:
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
spec:
containers:
- name: filebrowser
# filebrowser/filebrowser:v2.18.0 を同期した後、ご利用の ACR イメージアドレスに置き換えてください
image: XXXX-registry-vpc.cn-hangzhou.cr.aliyuncs.com/test/test:v2.18.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
volumeMounts:
- mountPath: /.filebrowser.json
name: config
subPath: .filebrowser.json
- mountPath: /db
name: rootdir
- mountPath: /rootdir
name: rootdir
volumes:
- name: config
configMap:
name: filebrowser
defaultMode: 420
- name: rootdir
persistentVolumeClaim:
claimName: cnfs-nas-pvc # java-application Deployment と同じ PVC
EOF
期待される出力:
configmap/filebrowser unchanged
deployment.apps/filebrowser configured
サービスの作成
-
ACK コンソールにログインします。左側のナビゲーションウィンドウで、[クラスター] をクリックします。
-
対象のクラスターを見つけて、その名前をクリックします。左側のナビゲーションウィンドウで、[ネットワーク] > [サービス] を選択します。
-
サービスページで、
default名前空間を選択し、[作成] をクリックします。以下のパラメーターを設定します:詳細については、「NLB の課金概要」をご参照ください。
パラメーター 値 名前 filebrowserサービスタイプ SLB > SLB タイプ: CLB。[リソースの作成] を選択し、[アクセスメソッド] を [パブリックアクセス] に設定します。 バックエンド [+ワークロードラベルの参照] をクリックします。[リソースタイプ] を Deploymentsに、[リソース] をfilebrowserに設定します。ポートマッピング サービスポート: 8080、 コンテナポート:80、 プロトコル:TCP -
構成を送信します。
File Browser へのアクセス
-
サービスページからエンドポイントアドレスをコピーします。
-
ブラウザで
<endpoint-address>:8080を開きます。File Browser のログインページが表示されます。 -
デフォルトの認証情報でログインします:ユーザー名
admin、パスワードadmin。
-
[rootdir] をダブルクリックして、NAS のマウントポイントに入ります。

結果
rootdir 内では、各 Pod のダンプディレクトリは subPathExpr: $(POD_NAMESPACE).$(POD_NAME) のルールに従って命名されます。例: default.java-application-76d8cd95b7-prrl2。
ディレクトリを開くと java_pid1.hprof が見つかります。ダウンロードして Eclipse Memory Analyzer (MAT) で分析し、OOM の原因となったコードを特定します。
仕組み
3 つのメカニズムが連携して、Pod の再起動後もヒープダンプを永続化します:
-
`ReadWriteMany` を持つ CNFS PVC: NAS をバックエンドとする PVC は、
java-applicationPod と File Browser Pod の両方にマウントされます。NAS は Pod のライフサイクルとは独立してファイルを永続化するため、ダンプファイルは Pod のクラッシュ後も残ります。 -
Downward API を使用した `subPathExpr`: 各 Pod は NAS のルートではなく、自身のサブディレクトリ (
<namespace>.<pod-name>) にマウントされます。これにより、再起動時にダンプが上書きされるのを防ぎ、ダンプから Pod を簡単にトレースできるようになります。 -
`-XX:+HeapDumpOnOutOfMemoryError`: JVM は OOM で終了する前に、ヒープの状態を
-XX:HeapDumpPathに書き込みます。そのパスは NAS をバックエンドとしているため、ファイルは Pod の終了後も残ります。