So, you have a legacy Java-based application running on aging virtual machines, and you want to move it into containers and deploy it on Kubernetes. You're not alone.
We’re helping a customer do exactly that: transitioning a sprawling, service-oriented Java application into a modern, containerized environment orchestrated by Kubernetes. This is more than a technical refresh; it's a full operational and architectural shift.
If you're planning a similar journey, here are the high-level steps we're following, including insights from our DevOps transformation work and containerization readiness checklist.
Before you write a single line of Dockerfile, you need a full understanding of how each service works.
Document:
How each service starts, runs, and shuts down
All runtime dependencies (files, databases, queues, other services)
Communication methods (HTTP, gRPC, shared libraries, IPs, FQDNs)
Environment assumptions (ports, paths, memory settings)
State management (what state exists, where it's stored)
Build a clean inventory of your service-oriented architecture so you can scope and sequence the transformation.
Encapsulate each service's runtime environment using a Dockerfile. Consistency matters.
For Spring Boot apps:
FROM eclipse-temurin:17-jdk
WORKDIR /app
COPY ./target/my-service.jar app.jar
CMD ["java", "-jar", "app.jar"]
For WAR/EAR apps, you'll need appropriate base images (such as Tomcat or WebLogic) and custom entrypoints.
Use official base images or vendor-supported options. Avoid unmaintained or custom community images.
Hardcoded values are a container anti-pattern. Externalize settings like DB credentials, API endpoints, and feature flags using environment variables or mounted config files.
Design your containers to read from their environment. This ensures portability and prepares them for ConfigMaps and Secrets in Kubernetes.
Test each container in isolation and with others using docker-compose
. Validate:
Clean startup and shutdown
Dependency connectivity
Statelessness and restart behavior
Logging to stdout/stderr
Runtime configuration injection
This gives you confidence before layering on orchestration.
Containers are ephemeral. If your services write to disk, re-architect them to use mounted volumes or external storage.
Watch for legacy behaviors like sticky sessions or shared directories. Kubernetes will not tolerate them well.
For each service, create:
Deployment to define replicas and rolling updates
Service to enable internal discovery
Ingress to expose endpoints externally
ConfigMap or Secret to provide externalized settings
Probes for health and readiness
This is where you codify your deployment model. If you're using GitOps, this is your source of truth.
Push images to a container registry. Deploy manifests into a Kubernetes cluster. Start small:
Deploy one or two services
Verify behavior, connectivity, and logs
Scale incrementally
Use kubectl
to monitor pods, logs, and deployments. Tools like Portainer can simplify visibility and governance.
Enable Kubernetes to self-heal and manage availability.
Liveness probes restart crashed containers
Readiness probes gate traffic until services are ready
Use endpoints like /actuator/health
or custom health checks.
With your services running in Kubernetes:
Use Horizontal Pod Autoscaler for demand-based scaling
Use rolling updates for zero-downtime deployments
Integrate CI/CD pipelines for continuous rollout
Use observability tools such as OpenTelemetry, Grafana, and Portainer for full visibility
You are no longer maintaining pets. You are managing cattle: scalable, reproducible, and observable units of compute.
Migrating to containers and Kubernetes is also a cultural and workflow shift. Your CI/CD and DevOps processes need to evolve to support the new reality.
Legacy version control patterns often don't translate well to modern, CI-driven workflows.
A clean, scalable Git strategy is foundational to everything from automation to auditability.
As part of our containerization readiness checklist, ensure:
Dockerfiles use supported base images and multi-stage builds
Configuration is externalized
Logging is standardized
CI/CD pipelines are integrated
Secrets are handled securely
Containers are stateless
Probes are defined and tuned
This is a bird’s eye view of the journey. We’ve helped organizations modernize ERP systems, Java SOA estates, and everything in between.
If you're looking to skip the trial and error and accelerate with confidence, the Portainer Managed Services team is here to help. We bring the tools, templates, and experience needed to modernize your apps and get them production-ready on Kubernetes.
Let’s talk.