Production-Grade Docker Images for Java
Introduction
A Java Dockerfile can be three lines and technically work — or it can be a 700 MB image that runs as root, rebuilds from scratch on every code change, and gets OOM-killed under load. The difference is a handful of well-understood practices.
This post walks through building Java images that are small, secure, cache-friendly, and container-aware.
Start From a Slim, Current JRE — Not a JDK
You need a JDK to build, but only a JRE to run. Shipping a full JDK bloats the image and widens the attack surface.
Production-Grade Docker Images for Python
Introduction
The typical first-draft Python Dockerfile — FROM python, COPY . ., pip install -r requirements.txt — produces an image that is close to a gigabyte, reinstalls every dependency whenever a single source file changes, and runs as root with a Python process that ignores SIGTERM.
This post covers how to fix all of that: small images, cached dependency installs, a non-root runtime, and clean shutdowns.
Pick the Right Base Image
python:3.12-slim is the pragmatic default: a Debian-based image with Python but without the large build toolchain. Avoid the full python:3.12 (hundreds of MB of tools you don’t run) and be cautious with alpine — its musl libc frequently breaks or slows down packages with C extensions (NumPy, pandas, database drivers), forcing slow source builds.