Docker Fundamentals · Module 04 of 12

Dockerfile fundamentals

Write a clear Dockerfile, understand build context and common instructions, and build your first custom application image.

Learning objectives

By the end of this module, you should be able to:

  • Explain FROM, WORKDIR, COPY, RUN, ENV, EXPOSE, CMD and ENTRYPOINT at a fundamentals level.
  • Build an image from a controlled build context.
  • Distinguish build-time instructions from runtime container configuration.

A Dockerfile describes how to build an image

Docker reads Dockerfile instructions and sends a build context containing files available to COPY/ADD. FROM selects a base stage. RUN executes commands while building. COPY places files from the build context into the image.

CMD and ENTRYPOINT influence the process that starts when a container is run; they are not commands that execute during docker build.

Build context matters

The final argument to docker build is the build context, often a directory such as dot. Files outside that context cannot normally be copied by ordinary Dockerfile COPY instructions. Sending an unnecessarily large context slows builds and can accidentally expose files to the builder.

Prefer explicit, predictable runtime behavior

A good image has a clear purpose and a predictable foreground process. Containers should not rely on interactive login shells to start the application. Use image metadata and runtime flags for configuration that changes between environments.

Worked examples

See the idea in practice.

Minimal static web image

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
  • FROM chooses the base image.
  • COPY adds your page to the image.
  • EXPOSE documents the intended container port but does not publish it to the host.

Build and run

docker build -t gnu-docker-web:1.0 .
docker run --rm -p 8080:80 gnu-docker-web:1.0
  • -t adds a useful local name/tag.
  • The final dot is the build context.
  • -p publishes the container service to the host.
Hands-on lab

Lab — Build your first custom image

Goal: Create a static website image and run it without bind-mounting the source file.

STEP 1

Create the project

mkdir -p ~/docker-fundamentals/web && cd ~/docker-fundamentals/web
printf '<h1>GNU Group Docker Lab</h1>\n' > index.html
STEP 2

Create Dockerfile

cat > Dockerfile <<'EOF'
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
EOF
STEP 3

Build

docker build -t gnu-docker-web:1.0 .
STEP 4

Run and test

docker run -d --name gnu-web -p 8080:80 gnu-docker-web:1.0
curl http://127.0.0.1:8080/
STEP 5

Clean up

docker rm -f gnu-web

Verify

  • docker image ls shows gnu-docker-web:1.0.
  • curl returns the page text without mounting index.html at runtime.

Expected outcome

  • The HTML file is part of the built image.

If it fails

  • If COPY fails, confirm index.html is inside the build context.
  • If a build uses an unexpected Dockerfile, specify -f explicitly and verify your current directory.
Real-world connection

Production release pipelines build versioned images once and promote those artifacts between environments rather than editing files inside running containers.

Avoid these traps

Common mistakes

  • Thinking EXPOSE automatically opens a host firewall port.
  • Putting secrets in Dockerfile ENV or COPY instructions.
  • Using a huge build context that contains source-control metadata, credentials or build outputs.
Knowledge check

Can you explain it without looking back?

Open each answer only after you have tried to answer the question yourself.

1When does RUN execute?

During image build.

2What does the final dot in docker build -t app:1.0 . mean?

It selects the current directory as the build context.

3Does EXPOSE publish a port on the Docker host?

No. Host publishing is normally done with runtime options such as -p or Compose ports.