Installing JFR on a live container

There may be times when you encounter a JVM running in a container that is not monitored or exposed via JMX, and is not attachable from the host. If you need to collect metrics from the JVM without stopping it and the java install does include the JDK, this can be a problem. We recently encountered identified a method of obtaining metrics using jfr.

The steps below were run on an AWS EKS node where the container was running as root and the JVM was running with pid 1. Changes to file ownership maybe required for difference scenarios, as well as java environment variables if the jcmd command is reported as not found.

# find the container id you want to monitor
for i in `ctr --namnespace k8s.io containers ls | grep <name> | cut -d' ' -f1; do ctr --namespace k8s.io task list | grep $i | tr -s ' '; done
# example output:
# 6bddbc9a642661016bcedb9eb1cf35e65b554a209a5e519f8e3634e957e364c4 3274115 RUNNING

# install jdk on the host
yum install java-1.8.0-amazon-corretto-devel
cd /usr/lib/jvm/java-1.8.0-amazon-corretto.aarch64

# copy the files for running jfr onto the container root. note: the exact location may require changing
cp -r lib /run/containerd/io.containerd.runtime.v2.task/k8s.io/$CID/rootfs/tmp
cp -r bin /run/containerd/io.containerd.runtime.v2.task/k8s.io/$CID/rootfs/tmp
cp -r jre /run/containerd/io.containerd.runtime.v2.task/k8s.io/$CID/rootfs/tmp

# connect to the container
ctr --namespace k8s.io task exec -t --exec-id 1 $CID sh

# change directory to the location of jcmd
cd /tmp/bin

# run jfr command, in the example below the process is running with pid 1
./tmp/bin/jcmd 1 JFR.start duration=300s

# assemble chunks into single file
cd /tmp
jfr assemble <jfrdir> assembled-filename.jfr

# from the host copy the assembled file from the rootfs directory
cp /run/containerd/io.containerd.runtime.v2.task/k8s.io/$CID/rootfs/tmp/assembled-filename.jfr <desired location>