Containers and Docker: the same box everywhere

Why:“It works on my machine” stops being an excuse once a program travels in a box with everything it needs. Afterwards you’ll tell an image, a container and a volume apart, read and write a Dockerfile and a compose file for your project’s site, run a container in a simulator and decide honestly whether you need one at all.

30 minutes

Read by speech synthesis (Qwen3-TTS); the voice is not a person’s.

Docker packs a program and what it needs into an image and runs it as a container anywhere. A Dockerfile defines the image, compose.yaml a set of containers.

“It works on my machine”

Everyone who has ever moved a program to another computer has this story. On the laptop the site works, and on the server it doesn’t: the language version is different, a library is missing, the web server is set up another way. People used to close that gap with ten pages of instructions (“install this, then that, then fix that file”), and the instructions went stale.

The solution was borrowed from shipping. Cargo used to travel any which way: sacks, barrels, crates, and every port loaded it differently. The standard container changed everything: whatever is inside, the port, the train and the truck treat the box the same. In programming the logic is the same. A program is packed together with everything it needs, and from then on you don’t care which computer runs it.

Image, container, volume

These are three words you need to keep apart.

  • An image is a ready, unchangeable “box”: a trimmed-down system, your program, its libraries and settings. An image is made of layers, each adding something to the one before.
  • A container is a running instance of an image: a process that believes it has a file system and a network of its own. You can run as many containers as you like from one image. An image is the recipe for a cake, and a container is the cake on the table.
  • A volume is a place for data that lives apart from the container. Whatever a container wrote inside itself disappears with it. So what you’d hate to lose (requests, uploaded files, the database) is kept on a volume or in a separate database.

There is also the registry: a store of images, where they are downloaded from (Docker Hub, and the big clouds and GitHub have registries of their own). From a registry you take other people’s images (a ready-made nginx, say), and into a registry you publish your own.

You’ll remember the difference from a virtual machine in one phrase: a virtual machine carries a whole operating system with it, while a container uses the host system’s kernel and isolates only its own process. So a container takes megabytes and starts in seconds. The price: the isolation is weaker than a virtual machine’s.

Check yourself: what happens to the data a container wrote inside itself if you remove it?

It disappears with the container. For data that has to be kept you need a volume or a separate database.

The recipe for an image

An image is described in a file named Dockerfile: short lines of instructions, each making one layer.

FROM nginx:alpine
COPY dist/ /usr/share/nginx/html/
EXPOSE 80

Read it as a recipe. FROM says which ready image to start from (here the nginx web server in the light alpine build). COPY puts your site’s built files from the dist folder into the image (the build gives you that folder, as you learned in the parts on JavaScript and generators). EXPOSE warns that the thing inside listens on port 80. Everything else needed to serve files is already in nginx.

When the site has to be built first, a multi-stage build helps: in the first stage Node.js builds the site, and in the second only the finished result goes into a clean nginx, with no Node and no sources.

FROM node:lts-alpine AS build
WORKDIR /app
COPY package.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

Two features save time and nerves. First: Docker remembers layers, and if an instruction and everything before it are unchanged, it takes the layer from the cache. So you copy what rarely changes first (package.json) and what changes often after it (the code). Second, and the main one: secrets don’t go into an image. The line ENV API_KEY=... writes the key into a layer for good: images get published and copied, and the key travels with them. Secrets are passed at launch. A small thing: a .dockerignore file keeps what you don’t need (a .env, say, or the node_modules folder) out of the image.

Several containers as one project

A project usually has several parts: the site, a program that receives requests, sometimes a database. Starting each with a command of five flags is awkward, so there is Compose: one file, compose.yaml, describes all the containers, ports, volumes and the links between them.

services:
  site:
    build: .
    ports:
      - "8080:80"
    restart: unless-stopped
  receiver:
    build: ./receiver
    env_file: .env
    volumes:
      - requests:/data
    restart: unless-stopped
volumes:
  requests:

Here ports: "8080:80" joins port 8080 of your computer to port 80 inside the container (the left is “outside”, the right “inside”). env_file: .env takes secrets from a file that goes neither into the image nor into the repository. requests:/data attaches the volume requests to the receiver’s folder /data, and the volume is declared in the volumes section at the bottom. To start the whole project: docker compose up -d; its state: docker compose ps; to stop it: docker compose down (the volumes stay).

Try it in the simulator

There is no real Docker in a browser, so this is a simulator: the page reads the commands itself. But the order of things and the messages are real. Choose a Dockerfile (in the third one a key is written into the image, so see what the build says), build the image, run the container, open the site with curl, then stop and remove the container.

Docker in the browser: a Dockerfile, an image, a container
Images (layers)

There are no images. Build one: docker build -t site .

Containers

There are no containers.

This is a teaching simulator: there is no real Docker here. Type help or press a command below.

What to notice. If you run a container without -p, it works but can’t be opened from outside. If a port is already taken by another container, you get an error. A second build takes unchanged layers from the cache. And the site curl returns is signed with your project’s name.

If you want to try it for real, install Docker Desktop or its free replacement Podman and repeat the same commands in a terminal. Docker Desktop is free for companies with fewer than 250 employees and less than $10 million a year in revenue, and for non-commercial open source; Docker also lists a free Personal plan for individuals, subject to its license terms, and larger organizations need a paid subscription (Docker’s FAQ, October 2026). Docker Engine itself on Linux is open source.

Check yourself: what does -p 8080:80 mean in the run command?

Port 8080 of your computer is joined to port 80 inside the container. Without it the container works but can’t be opened from outside.

Honestly: when Docker is overkill

Containers have a price: you have to learn them, update the base images (vulnerabilities are found in those too), and watch the disk and the logs. So the honest question is: what do they solve for you?

  • A site of static files. You don’t need Docker at all: the files go on static hosting, which is cheaper and more reliable. A container with nginx for one page is a complicated way of doing something simple.
  • One machine, a fixed environment. An “identical box” gains nothing.
  • Several programs that must run the same way for you, your colleague and the server (the site, a request receiver, a database): here Docker and Compose pay off.
  • A project whose main action a ready-made service covers (receiving forms, booking, payment): there is nothing to pack.

Compare the first lesson of the part. The steps of hosting were a ladder too, and Docker is one more rung, not a necessity.

Practice

In front of you is your project’s site, and under it two files in boxes: a Dockerfile and compose.yaml. Finish them on the model in the lesson. Then open the simulator, build the image, run the container with its port, and paste the line from docker ps into the note. Say what is on the volume (through your project’s main action), and answer the last question: do you need Docker?

The check reads the texts in the boxes. Docker can’t be run in the sandbox, so running it in the simulator remains your job, and the note shows that it worked.

What was wrong before

In 2010 the unit of moving was a server: an admin set up a machine by hand, and a year later no one remembered how exactly. Such servers were called “snowflakes”: each is unique, and you can’t make a copy. A move meant a week of manual work and several “oh, we also need to install…”. A container turned the setup into a file that lies in the repository, can be read and reproduced. But, as always with convenient things, the main point remains: a container packs not the knowledge but only its record, and understanding what is inside is still your job.

Practice

Preparing your page…

Test

Question 1 of 5

Match each Docker term with what it is

Find the match for each item.

Cards

These cards go into your review once you finish the lesson.

  • How does an image differ from a container?

    Answer

    An image is an unchangeable template (layers: the system, the program, the settings). A container is a running instance of an image. You can run many containers from one image.

  • What is a volume for?

    Answer

    Whatever a container writes inside itself disappears with it. A volume keeps data apart: the container can be removed and created again, and the data stays.

  • The main Dockerfile instructions

    Answer

    FROM (the base image), WORKDIR, COPY (put files in), RUN (a command at build time), ENV, EXPOSE (which port it listens on), CMD (what to run). Each instruction makes a layer, and unchanged layers come from the cache.

  • How do you handle secrets in Docker?

    Answer

    Don’t write them into the Dockerfile (ENV, ARG) or into a compose file kept in the repository. Pass them at launch: environment variables, an env_file with a .env file outside the repository, a secrets manager.

  • When is Docker not needed?

    Answer

    For a site of static files (static hosting is enough) and when there is one environment that never changes. It is useful when several programs must run the same way in different places.

Sources

Videos

Docker in 100 Seconds (Fireship)

The video loads from youtube-nocookie.com only when you press play.

Open on the site

Docker Tutorial for Beginners, full course (TechWorld with Nana)

The video loads from youtube-nocookie.com only when you press play.

Open on the site

Next

You now know: containers and Docker, Dockerfile and Compose.