Posted on :: Tags: , , , , , , , DRAFT

As Java developers, we know the pain of managing OpenTelemetry agents across microservices. Should we bake them into Docker images? Mount them via ConfigMaps? Use init containers? Kubernetes v1.33's beta Image Volume feature offers a surprisingly elegant solution that keeps our application images clean while ensuring consistent observability.

The Java Developer's Observability Dilemma

Every Spring Boot microservice needs observability, but traditional approaches create friction:

# The old way - baking agents into images
FROM openjdk:17-jre
COPY opentelemetry-javaagent.jar /opt/
COPY myapp.jar /app/
ENTRYPOINT ["java", "-javaagent:/opt/opentelemetry-javaagent.jar", "-jar", "/app/myapp.jar"]

This approach has several downsides:

  • Larger Images: Every service carries its own agent copy
  • Version Management: Updating agents requires rebuilding all services
  • Build Complexity: Developers must remember to include agents
  • Testing Overhead: Different environments may use different agent versions

A Cleaner Approach with Image Volumes

The beta Image Volume feature lets us mount container images as volumes, enabling a clean separation between application code and instrumentation:

# Clean application deployment with external agent
volumeMounts:
- name: otel-agent
  mountPath: /opt/opentelemetry
  readOnly: true
volumes:
- name: otel-agent
  image:
    reference: localhost:5001/opentelemetry-javaagent:v2.15.0

Setting Up the Demo Environment

My [demo repository]({{ repository }}) shows exactly how this works with a complete Spring Boot example. Here's the setup process:

1. Prepare the Infrastructure

# Build custom Kubernetes environment with OCI Volume support
./01-build-custom-kind-image.sh
./02-kind-with-registry.sh

Since this is a beta feature that's disabled by default, we need Kubernetes v1.33 with specific containerd versions and feature gate enablement. The demo handles all the complexity for you.

2. Package the OpenTelemetry Agent

The magic happens in the [artifact creation script]({{ repository }}/blob/main/03-artifact-javaagent-upload.sh):

# Download and package the latest OpenTelemetry agent
curl -L "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.15.0/opentelemetry-javaagent.jar" -o opentelemetry-javaagent.jar

# Create OCI artifact and push to registry
./03-artifact-javaagent-upload.sh

This creates a proper OCI image containing just the agent JAR, with all the right metadata for reproducible builds.

3. Deploy Your Spring Boot Application

# Deploy with automatic agent injection
./04-deploy-spring-hello-world.sh

The [Spring Boot deployment]({{ repository }}/tree/main/spring-hello-world) shows how clean this becomes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-hello-world
spec:
  template:
    spec:
      containers:
      - name: spring-hello-world
        image: openjdk:17-jre
        command: ["/bin/sh"]
        args: ["-c", "java -javaagent:/opt/opentelemetry/opentelemetry-javaagent.jar -jar /app/spring-hello-world.jar"]
        volumeMounts:
        - name: app-jar
          mountPath: /app
        - name: otel-agent
          mountPath: /opt/opentelemetry
          readOnly: true
      volumes:
      - name: otel-agent
        image:
          reference: localhost:5001/opentelemetry-javaagent:v2.15.0

Observability in Action

The demo includes the [Aspire Dashboard]({{ repository }}/tree/main/aspire-dashboard) for visualizing telemetry data:

# Deploy observability dashboard
./04a-deploy-aspire-dashboard.sh

Once deployed, you can see your Spring Boot metrics, traces, and logs flowing through OpenTelemetry without any code changes.

Benefits for Java Teams

Simplified Development Workflow

  • Clean Dockerfiles: Focus on your application, not infrastructure concerns
  • Faster Builds: Smaller images build and deploy faster
  • Version Independence: Update agents without touching application code

Better Testing and Debugging

  • Consistent Environments: Same agent version across dev, test, and prod
  • Easy Toggling: Enable/disable instrumentation by changing volume mounts
  • Reduced Variables: Fewer moving parts in your container images

Operational Excellence

  • Zero-Downtime Updates: Update observability without service restarts
  • Centralized Management: One place to manage agent versions across all services
  • Better Security: Smaller attack surface in application images

Production Considerations for Java Teams

Performance Impact

OpenTelemetry agents are designed for production use, but consider:

  • JVM startup time may increase slightly
  • Memory overhead is typically 10-50MB depending on instrumentation
  • CPU overhead is usually under 5% for most applications

Configuration Management

env:
- name: OTEL_SERVICE_NAME
  value: "my-spring-service"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
  value: "http://jaeger:14250"
- name: OTEL_RESOURCE_ATTRIBUTES
  value: "service.version=1.0.0"

Keep your OpenTelemetry configuration in environment variables or ConfigMaps, separate from the agent itself.

Integration with Spring Boot Features

The auto-instrumentation works seamlessly with:

  • Spring Boot Actuator metrics
  • Spring Security traces
  • Spring Data database instrumentation
  • Spring Cloud distributed tracing

Future-Proofing Your Observability

Image Volumes graduated to beta in Kubernetes v1.33, representing the future of clean container architecture. While still disabled by default, this progression shows the feature's maturity. Java teams should:

  1. Experiment Now: Use the demo to understand the workflow
  2. Plan Migration: Identify services that would benefit from external agents
  3. Update Practices: Start designing new services with this pattern in mind

Try It Yourself

The [complete demo]({{ repository }}) includes:

  • Working Spring Boot application with OpenTelemetry
  • Automated setup scripts for local testing
  • Observability dashboard for data visualization
  • Cleanup scripts for easy teardown
git clone https://github.com/dol/k8s-oci-volume-source-demo
cd k8s-oci-volume-source-demo

# Full demo workflow
./01-build-custom-kind-image.sh
./02-kind-with-registry.sh
./03-artifact-javaagent-upload.sh
./04-deploy-spring-hello-world.sh
./04a-deploy-aspire-dashboard.sh

# Check your observability data!

This approach transforms Java observability from a deployment complexity into a simple operational concern. As this feature is now in beta in Kubernetes v1.33, it's the perfect time for Java teams to explore how it can simplify their microservices architecture.


Explore the complete working example at [{{ repository }}]({{ repository }}), including Spring Boot code, Kubernetes manifests, and step-by-step setup instructions.