
Learn how to run Java in containers with Docker or Kubernetes, including JVM ergonomics, graceful shutdown, and building distroless and native images using multi-stage builds.
Discover how Docker packages applications into portable, versioned containers that run on a single host, offering isolation and easy deployment with images, Dockerfile, and registries.
Install Docker on macOS, Windows, or Linux with Docker Desktop and verify the setup. Run your first container using the Ubuntu image and explore basic Docker commands.
Learn to write a dockerfile, build a java image from openjdk, and run it as a container with an end-to-end demo, covering image versus container and key docker commands.
Learn to use Gradle to compile Java, build jar packages with dependencies, and create Docker images with the Palantir Docker plugin, aided by startup scripts and environment variables.
Discover how the JVM automatically tunes itself to your machine’s memory and cores, covering heap sizing, thread stacks, garbage collection, the just-in-time compiler, and container-aware behavior in modern Java.
Explore how containers rely on Linux namespaces and cgroups for isolation and resource limits. Watch live Docker demos of pids, networks, and mounts, and compare host versus container environments.
Explore how CPU shares in Docker containers allocate CPU resources as relative values, how Java interprets 1024 as a core, and the impact of container orchestration on production performance.
Learn how container CPU quota and period constrain Java applications, highlight throttling risks for multithreaded workloads, and compare CPU quota with CPU shares across Java 8 and Java 11.
discover how container memory works in docker, compare memory and memory swap, and see how Java ergonomics shift from host to container, with heap, off-heap, threads, and native memory tracking.
Learn to use Kubernetes as a container orchestrator to deploy and manage containers with deployments, pods, and services, enabling scaling, rolling upgrades, graceful shutdowns, and access via ingress and DNS.
Learn how minikube runs a complete kubernetes cluster locally for testing and learning, and how to install minikube, kubectl, and enable addons like ingress.
Demonstrates deploying two Java apps in Kubernetes using the built-in http server, exposing /ready, /alive, and Hello from server up, with a service and ingress in Minikube.
Explore how kubernetes allocates cpu and memory via abstractions and control groups, with namespaces restricting access and resources per namespace, and understand how requests and limits affect scheduling.
Explore how Kubernetes assigns CPU to containers via requests and limits, using 1.5 cores or 1500 millicores and 1024 shares, and how scheduling and throttling impact Java apps.
Learn how Kubernetes memory works with requests for scheduling and limits for cgroups, and why Java apps should set memory request under limit to avoid eviction.
Mastering liveness and readiness checks in Kubernetes keeps containers alive and ready, enabling rolling deployments that update pods one by one.
Learn to build production-ready Java images for Docker and Kubernetes by selecting base images, evaluating JDK vs JRE, and shrinking with Alpine, Distroless, GraalVM, and multi-stage builds.
Choose a small, official base image to minimize build time, transfer time, and attack surface when shipping Java containers; compare OpenJDK and AdoptOpenJDK, and target Java 11 with slim variants.
Compare JDK and JRE base images in Docker; the 11 slim JRE (~200MB) is smaller than the 11 JDK slim (~400MB), with tools like jcmd, jstat, and jfr.
Master multi-stage docker builds to produce lean production images by building inside docker, copying artifacts between stages, and extracting tar files to keep the final image small.
Learn to use the Java module system and jlink to create a minimal custom JRE, determine required modules with deps, and build smaller Docker images via a two-stage production workflow.
Learn to implement graceful shutdown for a Java application in containers and Kubernetes by handling sigterm and sigint, stopping new requests and finishing in-flight requests.
Learn how signals reach the JVM inside containers, enable graceful shutdown, and explore how Docker and startup scripts affect PID 1 handling, with practical demos in Docker and Kubernetes.
Debug java applications inside containers using lightweight tools like J attach and the Java Swiss Army knife, and leverage ephemeral containers or debug sidecars in Kubernetes for real-time diagnosis.
Speed up startup and save memory by enabling class data sharing for Java apps in containers, using a dumped class list to rebuild the image.
Distroless creates minimal containers by starting from the application and only including what is needed, such as Java, its dependencies, and the JRE, with no shell.
Explore ahead of time compilation in Java and compare it to just in time compilation. Use JROTC and GraalVM to create native libraries for faster startup.
Explore GraalVM native image, an ahead-of-time compiler that creates small, fast Java binaries for Docker in a containerized environment, with caveats around dynamic reflection and startup benefits.
Build GraalVM native images inside Docker with a two-stage workflow to produce small production binaries. Use a base image, copy the jar, and enable static linking for a seven-megabyte image.
Thank you for completing the course; share questions and feedback as we update the material to help you run a Java application in a container in production.
If you need to learn how to run, tune, and maintain JVM applications that run in Docker and/or Kubernetes then this is the course for you.
This course is very different from other Java/Docker/Kubernetes courses. It focuses on all the skills that you need to succeed in production.
All of the examples are in Java but the content is applicable for any JVM language including Scala, Groovy, and Kotlin.
We'll start with introductions for Docker and Kubernetes then we'll get into the fun stuff. We'll learn:
What a container is under the covers
Linux cgroups
Linux namespaces
Then we will go into how the JVM and your Java application behave differently in Kubernetes when running inside cgroups and namespaces. We'll cover:
JVM ergonomics
How CPU Shares and Quota work
How Kubernetes manages CPU and Memory
Then we will teach you all the techniques needed to build production-ready images:
Selecting a base image
JDK vs JRE based images
Multi-stage Docker builds
GraalVM
Class data sharing
Ahead of time compilation
We will experiment with different JVM versions and settings.
By the end of this course you'll know how to:
Build a production-ready image
Select between using CPU limits, quotas, or both in Kubernetes
Select memory limits and tune the JVM for running in Kubernetes
Understand CPU usage in Kubernetes and know why it is different to VMs and physical machines.