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.
- 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. - 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. - 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)
- What is an image? A container?
- Where should persistent uploads live?
- Are containers full VMs?
- Scenario: A container works, but your data vanished after an update. Why?
- Should a production API key be in the image?
Reference
Common mistakes
| Symptom | Likely cause | Fix |
|---|---|---|
| Lost data after redeploy | Stored in container layer | Use volumes/external storage |
| Surprise changes in prod | latest tag | Pin versions/digests |
| Host exposure risk | Mounted Docker socket / privileged mode | Avoid; 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.