Skip to content

Docker Support

LeanJ supports profiling Java applications running in Docker containers with automatic discovery and registration.

Docker containers with the agent automatically register with the controller using push-based discovery. No manual configuration needed!

Add the agent to your Dockerfile:

# Copy agent JAR
COPY dist/agent/agent-core-1.0.0-SNAPSHOT.jar /agent/agent.jar
# Configure Java agent
ENV JAVA_TOOL_OPTIONS="-javaagent:/agent/agent.jar=package=com.myapp"
# Optional: Set project name for identification
ENV LEANJ_PROJECT=my-service
# Optional: Set controller host (if not localhost)
ENV LEANJ_CONTROLLER_HOST=host.docker.internal
ENV LEANJ_CONTROLLER_PORT=9876
Terminal window
docker build -t my-java-app .

Make sure the controller is running:

Terminal window
leanj controller start

Important: If controller is on host and container needs to connect:

  • Use host.docker.internal (Docker Desktop) or
  • Use host’s IP address or
  • Run controller in a shared network
Terminal window
docker run -d \
--name my-service \
-p 8080:8080 \
my-java-app

The agent automatically:

  • Detects Docker environment
  • Registers with controller
  • Starts sending metrics
Terminal window
leanj jvms

Output:

Found 2 JVM(s):
1. my-service
ID: def456
Environment: docker
App: my-service
Container: abc123def456

Docker JVMs show:

  • Environment: docker (instead of local)
  • Container ID: Docker container identifier
  • App Name: From LEANJ_PROJECT env var
  • PID: Not available (null for Docker)

Using JVM ID:

Terminal window
leanj attach --jvm-id def456

Note: Docker JVMs use push-based discovery, so they’re already registered. The attach command confirms the connection.

The agent automatically detects Docker environment by checking:

  1. /.dockerenv file existence
  2. /proc/self/cgroup contains “docker”
  3. DOCKER_HOST environment variable
  4. Container ID from hostname or cgroup

When a Docker container starts:

  1. Agent starts with Java application
  2. Detects Docker environment
  3. Registers with controller via HTTP POST:
    POST http://controller:9877/api/v1/jvms/register
  4. Sends heartbeat every 30 seconds
  5. Sends metrics via TCP on port 9876
{
"jvmId": "uuid-generated",
"environment": "docker",
"containerId": "order-service",
"appName": "order-service",
"labels": {
"project": "order-service"
}
}

Docker agents send periodic heartbeats:

  • Interval: Every 30 seconds
  • Endpoint: POST /api/v1/jvms/{jvmId}/heartbeat
  • Purpose: Keep registration alive, update lastSeenAt

Controller removes stale JVMs after 60 seconds of no heartbeat.

Use host.docker.internal:

ENV LEANJ_CONTROLLER_HOST=host.docker.internal
ENV LEANJ_CONTROLLER_PORT=9876

Use host’s IP or shared network:

Option 1: Host IP

ENV LEANJ_CONTROLLER_HOST=172.17.0.1

Option 2: Shared Network

Terminal window
# Create network
docker network create profiler-net
# Run controller in network
docker run -d --network profiler-net --name controller ...
# Run app in same network
docker run -d --network profiler-net ...
version: '3.8'
services:
controller:
# Controller service (if containerized)
app:
build: .
environment:
- JAVA_TOOL_OPTIONS=-javaagent:/agent/agent.jar=package=com.myapp
- LEANJ_PROJECT=my-service
- LEANJ_CONTROLLER_HOST=controller
- LEANJ_CONTROLLER_PORT=9876
networks:
- profiler-net
networks:
profiler-net:
driver: bridge

LeanJ works in Kubernetes too:

  1. Mount agent JAR as ConfigMap or volume
  2. Set JAVA_TOOL_OPTIONS in deployment
  3. Configure controller host to service name or IP
  4. Agents register automatically

Example deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
env:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/agent/agent.jar=package=com.myapp"
- name: LEANJ_CONTROLLER_HOST
value: "profiler-controller.default.svc.cluster.local"
volumeMounts:
- name: agent
mountPath: /agent
volumes:
- name: agent
configMap:
name: profiler-agent

Issue: Docker JVM not in jvms list

Solution:

  1. Check agent is configured: echo $JAVA_TOOL_OPTIONS
  2. Verify controller is accessible from container
  3. Check controller logs: logs/profiler-controller.log
  4. Verify network connectivity

Issue: Agent can’t connect to controller

Solution:

  1. Check controller host/port configuration
  2. Verify network connectivity: ping controller-host
  3. Test HTTP endpoint: curl http://controller:9877/api/v1/status
  4. Check firewall rules

Issue: Old containers still in list

Solution:

  • Controller auto-removes after 60 seconds of no heartbeat
  • Or manually remove: leanj detach --jvm-id <id>
  1. Use project names: Set LEANJ_PROJECT for easy identification
  2. Shared networks: Use Docker networks for better isolation
  3. Resource limits: Set appropriate memory/CPU limits
  4. Health checks: Monitor agent registration in logs
  5. Labels: Use labels for filtering and organization