Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~14 min· topic 1 of 5

Topic 2.1

Your First Dockerfile

In one line

A Dockerfile is a plain-text recipe, read top to bottom, where each instruction produces exactly one new layer in the resulting image.

0/5 · 0%

Think of it like this

A recipe card. 'Preheat oven' (base setup), 'add flour, sugar, eggs' (add your files), 'mix' (run a build command), 'bake at 350°F' (the command that runs when you start it). Docker reads your Dockerfile top to bottom exactly like a recipe, one step at a time, in order.

Key ideas

  1. 01

    FROM — every Dockerfile starts here, picking a BASE image to build on top of (e.g. FROM eclipse-temurin:17-jre). You're never starting from nothing; you're always extending an existing image.

  2. 02

    COPY — copies files from your local machine (the 'build context') into the image's filesystem. COPY target/app.jar app.jar copies a built JAR into the image at path app.jar.

  3. 03

    RUN — executes a command DURING the build (not when the container later starts) — e.g. RUN apt-get update && apt-get install -y curl installs a package into the image itself, once, at build time.

  4. 04

    CMD — specifies the DEFAULT command that runs when a container is STARTED from this image (not during build). E.g. CMD ["java", "-jar", "app.jar"]. There can be only one CMD (the last one wins if you accidentally write several); it can be overridden at docker run time by appending a command.

  5. 05

    WORKDIR — sets the working directory for all subsequent instructions (like cd that persists for the rest of the file) — cleaner than repeating full paths in every RUN/COPY/CMD.

  6. 06

    EXPOSE — pure DOCUMENTATION that a container listens on a given port; it does NOT actually publish the port to your host (that's -p at docker run time, Phase 4) — many beginners mistakenly think EXPOSE alone makes a port reachable.

  7. 07

    Build the image with docker build -t myapp:v1 . — the . is the BUILD CONTEXT (the directory Docker can see and copy files from), and -t tags the resulting image with a name.

In your stack

  • →

    The minimum viable Dockerfile for a Spring Boot app, assuming you've already run mvn package locally to produce a JAR: FROM a JRE (not a full JDK — you only need to RUN Java, not compile it) base image, COPY the jar in, CMD to run it. Phase 7 improves on this significantly with multi-stage builds that also handle the mvn package step INSIDE Docker.

Code & diagrams

Dockerfilemarkdown

The simplest real Dockerfile for a Java app — five instructions, each doing exactly one job.

# 1. Start from an official, minimal Java runtime (not a full JDK — we only RUN, not compile)
FROM eclipse-temurin:17-jre

# 2. Set the working directory for everything below
WORKDIR /app

# 3. Copy the already-built JAR from your local machine into the image
COPY target/myapp-0.0.1.jar app.jar

# 4. Document (not publish!) the port this app listens on
EXPOSE 8080

# 5. The default command when a container starts from this image
CMD ["java", "-jar", "app.jar"]
build-and-run.shmarkdown
# Build the image, tagging it "myapp:v1", using the current directory as build context
docker build -t myapp:v1 .

# Run a container from the image you just built, mapping the port to your host
docker run -d --name myapp -p 8080:8080 myapp:v1

# Confirm it's running and check its logs
docker ps
docker logs myapp

Explain it without notes

01

Why does EXPOSE 8080 in a Dockerfile NOT let you actually reach the app at localhost:8080 from your browser?

02

What's the difference between RUN and CMD — specifically, WHEN each one executes?

Practice

01

Write a Dockerfile for a simple static website: FROM nginx, COPY your HTML files into nginx's default serving directory (/usr/share/nginx/html), and build+run it.

02

Deliberately write TWO CMD instructions in one Dockerfile, build it, and confirm which one actually takes effect when you run a container.

Trade-offs

  • ↔

    Starting FROM a full JDK image instead of a JRE-only image works fine functionally but bloats your final image with an entire compiler toolchain you'll never use at runtime — a wasted few hundred MB that Phase 7's multi-stage builds specifically eliminate.

Done when you can

  • I can write a working Dockerfile for a simple app from memory.

  • I know exactly when RUN executes versus when CMD executes.

  • I understand EXPOSE is documentation only, not port publishing.