Level 6 · Cloud Computing, DevOps and Cybersecurity · Course 6.2 Cloud and Hosting

Module 69: Docker

Goal: package your application into containers that run the same way everywhere, write good Dockerfiles, keep data safe with volumes, connect containers on networks, and run the whole CRM with Docker Compose.

You'll need: Docker Desktop (Windows, Mac) or Docker Engine (Linux, including your lab), and your Level 5 CRM.

Lessons

  1. 1Containers and virtual machines15–25 minutes✓
  2. 2Images and Dockerfiles15–25 minutes✓
  3. 3Volumes and data15–25 minutes✓
  4. 4Networking15–25 minutes✓
  5. 5Docker Compose15–25 minutes✓

🛠️Module practice: Project B, part 3, a containerised CRM

  1. A multi-stage Dockerfile for the API (slim, non-root, no secrets, with .dockerignore), and one for the frontend.
  2. compose.yaml with database (volume, health check), API and an Nginx front, only the front published.
  3. Secrets passed at run time from ignored files; .example files committed.
  4. A tested database backup from the running container.
  5. Notes in your README: build, run, back up. Commit.

✅Module check

Explain in a few sentences, in your own words:

What are containers, and how do you containerise an application well?

Show a good answer

A good answer mentions: a container packages an app and its dependencies to run identically anywhere, sharing the host's kernel (lighter than a VM); images are built from Dockerfiles and run as containers. Good practice: official slim base images with pinned versions, multi-stage builds, dependency layers cached, a non-root user, .dockerignore, and no secrets in images. Data that must survive lives in volumes (or better, managed services) and is backed up with proper tools; containers talk by name on internal networks with only the front door published (bound carefully so the firewall isn't bypassed); Compose describes the whole set with health checks, restarts and run-time secrets.

📝Module quiz

10 questions · 10 marks each · 100 marks in all · pass mark 70% · retry as often as you like ·

1. Why do containers start much faster than VMs?

Why each option is right or wrong

  • “Containers use a faster processor than virtual machines” (Incorrect): They run on the same hardware; the difference is not booting an OS.
  • “Containers skip loading the app's code until it's needed” (Incorrect): The app's code is in the image and loaded normally.
  • “Containers keep a VM running permanently in the background” (Incorrect): On Linux, containers don't need a VM at all.
  • “They share the host's kernel and don't boot a whole OS” is correct.

    A virtual machine boots a complete operating system, which takes time and memory. A container is an isolated process using the host's kernel, so starting it is close to starting a normal program: often under a second.

    • Result: many containers fit on one machine.
    • Trade-off: weaker isolation than a full VM.

📖 Revise: Lesson 1: Containers and virtual machines

Question ID module-69-q1 · Report a mistake in this question
2. What's the difference between an image and a container?

Why each option is right or wrong

  • “They're the same thing under two different names” (Incorrect): One is the template; the other runs from it.
  • “A container is the template; an image is a running instance” (Incorrect): That's the wrong way round.
  • “An image is a backup copy of a stopped container” (Incorrect): Images are built from Dockerfiles as templates; they aren't backups of containers.
  • “An image is the template; a container is a running instance of it” is correct.

    An image is a read-only package of your app, its dependencies and settings. Running it creates a container, with its own process and writable layer. One image can start many identical containers.

    • Like: a recipe (image) and a dish made from it (container).
    • Commands: docker build makes images; docker run starts containers.

📖 Revise: Lesson 2: Images and Dockerfiles

Question ID module-69-q2 · Report a mistake in this question
3. Why copy package*.json and install before copying the rest of the code?

Why each option is right or wrong

  • “npm can't read package.json once the code has been copied in” (Incorrect): npm can read it either way; the order is about caching.
  • “It makes the final image use half as much disk space” (Incorrect): Size is about the same; build speed is the gain.
  • “Docker requires the package files to be copied first” (Incorrect): Docker doesn't require it; it's an optimisation.
  • “Docker caches that layer, so dependencies reinstall only when they change” is correct.

    Each Dockerfile step creates a cached layer. If the package files haven't changed, Docker reuses the installed dependencies and only redoes the steps after them, turning a minutes-long build into seconds when only code changed.

    • Order: rarely changing steps first, often changing steps last.
    • Use: npm ci for exact installs from the lock file.

📖 Revise: Lesson 2: Images and Dockerfiles

Question ID module-69-q3 · Report a mistake in this question
4. Why shouldn't secrets go into an image?

Why each option is right or wrong

  • “Secrets make the image too large to push to a registry” (Incorrect): A few bytes don't affect size; exposure is the problem.
  • “Containers can't read environment variables at all” (Incorrect): They can, which is how secrets should be passed.
  • “Docker deletes secrets automatically during the build” (Incorrect): It doesn't; they stay in the layers.
  • “Anyone who has the image can extract them” is correct.

    Images are shared through registries and saved on many machines. Every layer can be inspected, so a secret copied in, even if deleted in a later step, can be recovered. Pass secrets at run time instead.

    • At run time: environment variables or mounted secret files.
    • Check: .dockerignore excludes .env.

📖 Revise: Lesson 2: Images and Dockerfiles

Question ID module-69-q4 · Report a mistake in this question
5. What happens to files written inside a container when it's removed?

Why each option is right or wrong

  • “They're copied back into the image automatically” (Incorrect): Images don't change when containers write files.
  • “They stay on the host in the same folder forever” (Incorrect): Without a volume, they're removed with the container.
  • “They're uploaded to the registry for safekeeping” (Incorrect): Registries store images, not container files.
  • “They're deleted, unless stored in a volume” is correct.

    A container's writable layer exists only as long as the container. Remove it, and anything written there is gone. Volumes store data outside the container, so it survives restarts and replacements.

    • Databases: need a volume for their data folder.
    • Treat containers as disposable: keep state elsewhere.

📖 Revise: Lesson 3: Volumes and data

Question ID module-69-q5 · Report a mistake in this question
6. How should a containerised database be backed up?

Why each option is right or wrong

  • “By copying the volume folder while the database is running” (Incorrect): A live copy may be inconsistent.
  • “By saving the container as a new image” (Incorrect): Images aren't meant for data, and the copy may be inconsistent.
  • “Containers don't need backups because they restart cleanly” (Incorrect): Restarting doesn't protect the data from loss.
  • “With the database's own tools like pg_dump” is correct.

    Copying a live database's files can catch them mid-write and give a broken copy. pg_dump, run inside or against the container, produces a consistent backup you can restore anywhere.

    • Example: docker compose exec db pg_dump -U app shop > backup.sql.
    • Store backups: off the server, and test restores.

📖 Revise: Lesson 3: Volumes and data

Question ID module-69-q6 · Report a mistake in this question
7. How does the API container find the database container on the same network?

Why each option is right or wrong

  • “By using localhost, since they're on the same machine” (Incorrect): Inside a container, localhost is that container, not the database.
  • “By a fixed IP address typed into the code” (Incorrect): Container IPs change; names are stable.
  • “Containers can't talk to each other at all” (Incorrect): Containers on the same network can talk freely.
  • “By the database container's name as the host name” is correct.

    Docker networks include a built-in DNS. On a Compose network, the API can connect to db:5432, where db is the service name, without knowing its changing IP address.

    • Connection string: postgres://app:...@db:5432/shop.
    • Not localhost: inside a container, localhost means that container itself.

📖 Revise: Lesson 4: Networking

Question ID module-69-q7 · Report a mistake in this question
8. Why publish the API as 127.0.0.1:3001:3001 instead of 3001:3001?

Why each option is right or wrong

  • “127.0.0.1 is faster for visitors on mobile networks” (Incorrect): Visitors can't reach it directly at all; Nginx forwards for them.
  • “Docker requires an IP address in every port mapping” (Incorrect): It's optional; leaving it out exposes the port widely.
  • “It makes the API use port 127 instead of 3001” (Incorrect): The port stays 3001; the address limits who can connect.
  • “So it's reachable only from the host, not the internet” is correct.

    3001:3001 binds to every network interface, so anyone who can reach the server can reach the API directly, sometimes even bypassing the firewall. Binding to 127.0.0.1 means only Nginx on the host can reach it.

    • Watch out: Docker can bypass UFW rules for published ports.
    • Database: often shouldn't be published at all.

📖 Revise: Lesson 4: Networking

Question ID module-69-q8 · Report a mistake in this question
9. What does depends_on with condition: service_healthy do?

Why each option is right or wrong

  • “Restarts the database whenever the API crashes” (Incorrect): It controls start order, not restarts.
  • “Makes the two containers share one process” (Incorrect): They stay separate containers.
  • “Checks the API's health before starting the database” (Incorrect): It's the database's health the API waits for.
  • “Starts the API only after the database's health check passes” is correct.

    Plain depends_on waits only for the database container to start, not for PostgreSQL to accept connections. With a health check and this condition, Compose waits until the database reports healthy.

    • Health check: e.g. pg_isready.
    • App code: should still retry connections.

📖 Revise: Lesson 5: Docker Compose

Question ID module-69-q9 · Report a mistake in this question
10. What does docker compose down -v do that down doesn't?

Why each option is right or wrong

  • “Shows more detailed output while stopping” (Incorrect): -v here means volumes, not verbose.
  • “Keeps the containers running in the background” (Incorrect): down stops containers either way.
  • “Removes the downloaded images as well as the containers” (Incorrect): That's the --rmi option; -v removes volumes.
  • “Also deletes the volumes, including database data” is correct.

    down stops and removes containers and networks but keeps volumes. Adding -v removes the volumes too, so the database's data is erased. Use it only when you really want a fresh start.

    • Before using -v: back up anything you need.
    • Safer reset: drop and reseed the test database instead.

📖 Revise: Lesson 5: Docker Compose

Question ID module-69-q10 · Report a mistake in this question

ProLearners Assist