Skip to content
← Email, Security & Cloud Foundations

Draft — in editorial review, not yet published. Content has not been approved by a human reviewer.

Lesson 49 / 50 · Version 2.2.0

Docker and Container Fundamentals

Level
Beginner–Intermediate
Duration
15 min learn + 15 min apply
Prerequisites:
Command-line familiarity helpful, not required

Why it matters: Containers make "works on my machine" portable, and they're how most modern apps, automation tools (like self-hosted n8n), and AI services ship. Knowing images, containers, and persistence prevents lost data and insecure defaults.

By the end you can:

  • Distinguish images from containers
  • Build and run a simple container
  • Persist data with volumes
  • Apply baseline image and runtime security

Learn (15 min)

1. Image vs. container (5 min)

An image is a layered, packaged template (app + dependencies). A container is a running (or stopped) instance of an image with its own writable layer. Many containers can come from one image. Containers isolate processes but share the host kernel; they're not full virtual machines and are not a complete security boundary on their own.

2. Build, run, persist (5 min)

## Dockerfile
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node            # don't run as root
EXPOSE 3000
CMD ["node", "server.js"]
docker build -t example-app:1.0 .
docker run -d --name app -p 3000:3000 -v appdata:/data example-app:1.0
docker ps
docker logs app
docker stop app && docker rm app

The writable layer is deleted with the container. For data that must survive, use a volume (-v appdata:/data) or external storage, and a bind mount only when deliberately sharing a host path.

3. Reduce risk (5 min)

Use trusted, minimal base images; pin versions or digests for reproducibility (avoid relying on latest in production); rebuild regularly to pick up fixes; scan images; run as non-root; drop unneeded privileges; limit mounts, network, and resources. Never bake secrets into images; inject them at runtime. Treat access to the Docker daemon or socket as root-level access to the host.

Apply (15 min)

Worked example (3 min). Classify a small app's files: source + dependencies → image; the environment-specific API endpoint → runtime config (environment/config file); the database password → secret (runtime secret mechanism); uploaded user files → volume/external storage.

Lab (7 min): Run and break a container.

  1. Install Docker Desktop (or use a sandbox environment) and run docker run --rm -it alpine sh; create a file, exit, rerun, and confirm the file is gone.
  2. Run a container with a named volume (-v testdata:/data), write a file in /data, remove the container, run a new one with the same volume, and confirm the file persists.
  3. Write down which of your own apps would need a volume.

Deliverable: A short log of the two experiments and a "what needs persistence" list. You're done when: You can explain exactly why the first file vanished and the second survived.

Check yourself (5 min)

  1. What is an image? A container?
  2. Where should persistent uploads live?
  3. Are containers full VMs?
  4. Scenario: A container works, but your data vanished after an update. Why?
  5. Should a production API key be in the image?

Reference

Common mistakes

SymptomLikely causeFix
Lost data after redeployStored in container layerUse volumes/external storage
Surprise changes in prodlatest tagPin versions/digests
Host exposure riskMounted Docker socket / privileged modeAvoid; least privilege

Cheat sheet: Dockerfile → build and scan → tag → run non-root with limits → persist data separately → patch and rebuild.

Key terms: image, container, Dockerfile, volume, bind mount, base image.

Interview prompts: Explain image vs. container to a non-technical stakeholder. How do you handle secrets in containers?

Go deeper: What is a container? · Docker volumes · Docker Engine security · Sharing local files

Next: Lesson 50 — when something goes wrong.