Docker Fundamentals
Images, containers and Dockerfiles — and packaging a Spring Boot app in one.
What you’ll learn
- Images vs containers
- Essential docker commands
- Writing a Dockerfile for a Java app
- Multi-stage builds for smaller images
The problem Docker solves
"It works on my machine" usually means the machine has a different Java version, OS library or environment variable than production. Docker packages your app with its environment so it runs identically everywhere.
Images vs containers
- An image is a read-only template: an OS base, a runtime, your app and its config. Think of it as a class.
- A container is a running instance of an image. Think of it as an object.
Essential commands
docker pull eclipse-temurin:21-jre # download an image
docker images # list local images
docker run -d -p 8080:8080 --name api my-api # run in background, map port
docker ps # running containers
docker logs -f api # follow logs
docker exec -it api sh # shell inside the container
docker stop api && docker rm api # stop and remove-p 8080:8080 maps host port : container port. Without it, your app runs but isn't reachable.
A Dockerfile for Spring Boot
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/employee-api.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]./mvnw package -DskipTests
docker build -t employee-api .
docker run -p 8080:8080 employee-apiMulti-stage builds
The Dockerfile above requires you to build the JAR on your machine first. A multi-stage build compiles inside Docker, then copies only the JAR into a small runtime image:
# Stage 1: build
FROM eclipse-temurin:21-jdk AS build
WORKDIR /src
COPY . .
RUN ./mvnw -q package -DskipTests
# Stage 2: run
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /src/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]The final image contains no JDK, no source code and no Maven cache — it's smaller and has less attack surface.
Tip
Add a .dockerignore with target/, .git/ and IDE folders so the build context stays small and builds stay fast.
Configuration via environment variables
Spring Boot maps environment variables to properties automatically — SPRING_DATASOURCE_URL becomes spring.datasource.url:
docker run -p 8080:8080 \
-e SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/hr \
-e SPRING_PROFILES_ACTIVE=prod \
employee-apiNever bake secrets into an image.
⚡ Try it yourself
Containerise the REST API from the Spring Boot lessons with a multi-stage Dockerfile. Run it, call an endpoint, then change SERVER_PORT with -e and adjust the port mapping to match.
Interview questions
QWhat's the difference between a container and a virtual machine?+
A VM virtualises hardware and runs a full guest OS with its own kernel. A container shares the host's kernel and isolates processes with namespaces and cgroups, so it starts in milliseconds and uses far less memory.
QWhat's the difference between CMD and ENTRYPOINT?+
ENTRYPOINT defines the executable that always runs. CMD provides default arguments (or a default command) that can be overridden by arguments to docker run.
Key takeaways
- Image = template, container = running instance.
- Use multi-stage builds to ship small runtime images.
- Configure with environment variables, never baked-in secrets.
Finished this lesson?
Mark it complete to move forward on your roadmap.