Skip to content
← DevOps foundations

Learning bite

Images and Dockerfiles

Build a small runtime image and distinguish build-time from runtime behavior.

Documentation reviewed2026-10-01 · 3 min read
On this page

A Dockerfile is a build recipe

The previous lesson ran an existing image. Now package a file and a runtime command into your own image. Building creates an image; running creates a container from it. A Dockerfile instruction such as RUN executes during the build, whereas CMD supplies the default command for later containers.

Create a new docker-status directory. Save status.json:

json
{"status":"ok"}

Save this Dockerfile beside it:

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY status.json ./status.json
USER 10001:10001
EXPOSE 8000
CMD ["python", "-m", "http.server", "8000", "--bind", "0.0.0.0"]

Read it in order. FROM chooses a base filesystem and metadata. WORKDIR sets the working directory. COPY places our file there from the build context. USER selects a non-root numeric UID and GID for subsequent instructions and runtime. This fixture only reads a public file. EXPOSE documents the intended port; it opens no host port. The JSON-array command starts Python directly without an extra shell wrapper.

The last instruction runs a development file server, not a production API. Binding 0.0.0.0 means listen on the container's interfaces; host exposure is chosen separately when running it.

Control the inputs sent to the builder

The final . in a build command names the current directory as its context. COPY can use files from that context, subject to .dockerignore. Save .dockerignore containing:

text
.git
.env
.venv
__pycache__
*.tfstate*
*.tfplan
.local

Keep secret files out of the context deliberately; do not assume a selective COPY makes a broad context harmless. ARG, ENV, and copied files are not suitable ways to hide build credentials. Use supported build-secret mechanisms when a build truly needs authentication.

Build, run, and read the response

Check the local context from the first lesson. In docker-status, run:

bash
docker build -t learnwithsk-status:dev .
docker run --rm --name sk-status -p 127.0.0.1:8765:8000 learnwithsk-status:dev

Use another terminal for curl --fail --max-time 3 http://127.0.0.1:8765/status.json. Expect {"status":"ok"}. The mapping means host loopback port 8765 forwards to container port 8000. If 8765 is occupied by the earlier Python fixture, stop that fixture before running this one. EXPOSE 8000 alone would not create this mapping.

Stop the container with docker stop sk-status. Because it was started with --rm, Docker also removes the stopped container. Keep the image and source for later lessons.

Images have layers and names

A build produces reusable layers and image metadata. Containers add a writable layer without modifying the shared image. Build caching can reuse unchanged work; changing an early build input can invalidate later steps. Put stable dependency declarations before frequently changing source when that reflects the real dependency relationship.

Change status.json to {"status":"learning"}, rebuild, and run again. Expect the new response. Editing the host file alone does not change an already built image, because COPY captured it during the build. Restore ok and rebuild before the next exercise.

A tag such as python:3.12-slim or learnwithsk-status:dev is a name that can be reassigned. Record resolved identities when comparing runs; later we distinguish local image IDs from registry digests. A cache hit improves speed, not proof of current or trustworthy dependencies.

Checkpoint: why does RUN python -m http.server ... belong in neither this build nor its success criterion? A server is the intended runtime process, not a build step that should wait forever. Next, connect containers and give data an explicit lifetime.

References: Dockerfile reference↗, build context↗, and build best practices↗.

Additional primary references: OrbStack Docker↗.

Your notes and evidence

Record observations, questions, or links to your work. Keep credentials out of your notes.

Loading saved progress…

Back up or restore this path

Progress and notes stay in this browser. A backup contains only this learning path.