Filters
How to search
  • Plain words find names, texts and examples.
  • "two words" finds the exact phrase.
  • --name or -x finds an option.
  • #word looks only inside commands.
  • @grep finds lessons and labs that use grep.
  • Filters: cat:network · in:labs · in:notes · level:rhcsa · ch:8 · root:yes. Put ! before a word to leave it out. OR between words means one of them.
  • ↑ ↓ to move · Enter to open · Esc to close · / to search

Chapter 4Name in the course: Building images

Write a Dockerfile

A Dockerfile (Podman also reads Containerfile) is the recipe of an image: start from a base, copy files, install packages, set the user and the start command. Every instruction makes a layer, and the order decides how well the build cache works.

  • 5 Lessons
  • 2 Commands

$ run as a normal user# run as root (or with sudo)

4.1

Know the instructions

A short list of instructions covers almost every image.

InstructionDoes
FROM image:tagThe base image
WORKDIR /appThe working folder (created if missing)
COPY src dstCopy files from the build context
RUN commandRun a command at build time (new layer)
ENV KEY=valueEnvironment variable in the image
ARG NAME=defaultBuild-time variable (not kept at run time)
EXPOSE 8080Document the port
USER 1001Run as this user
HEALTHCHECKA command that tells if the app is healthy
ENTRYPOINT / CMDThe start command / its default arguments
LABELMetadata (maintainer, version, source)

4.2

Build a Python app image

Dependencies first, code second — so code changes do not reinstall everything.

Dockerfile
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -r -u 1001 app && chown -R app /app
USER 1001
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"
CMD ["gunicorn", "-b", "0.0.0.0:8080", "app:app"]
docker build -t shop:dev .
docker build -t shop:1.4.0 --build-arg VERSION=1.4.0 -f Dockerfile .
docker run -d -p 8080:8080 shop:dev
podman build -t shop:dev .

4.3

Use the build cache well

Docker reuses a layer when the instruction and its input did not change. The first changed layer and everything after it rebuild.

  • Put rarely changing steps (OS packages, dependencies) before often changing ones (your code).
  • Copy only the dependency file first (requirements.txt, package.json, go.mod), install, then copy the rest.
  • Join apt-get update and install in one RUN, and clean up in the same line.
Dockerfile (packages)
RUN apt-get update \
 && apt-get install -y --no-install-recommends curl ca-certificates \
 && rm -rf /var/lib/apt/lists/*

4.4

Keep the build context small

Everything in the build folder is sent to the builder. .dockerignore keeps out junk and secrets.

.dockerignore
.git
.env
*.log
node_modules
__pycache__
tests/
Dockerfile

Watch out

Without .dockerignore, COPY . . can copy .env or .git (with old secrets) into the image — anyone who pulls the image can read them.

4.5

Know CMD and ENTRYPOINT

ENTRYPOINT is the program; CMD gives default arguments that docker run IMAGE ARGS can replace.

Dockerfile (tool image)
ENTRYPOINT ["terraform"]
CMD ["--help"]
docker run --rm mytf
docker run --rm mytf version

Remember

Use the exec form (["prog", "arg"]). The shell form (CMD prog arg) starts a shell as PID 1, and your program does not get SIGTERM — slow, unclean stops.

All commands in this chapter