The Desi Architect
Notes / Docker Sandboxes / Docker Basics: Images, Containers, Ports & Volumes
Docker Sandboxes · Tier 0: Start Here · Lab 00

Docker Basics: Images, Containers, Ports & Volumes

Never used Docker? Start here. You will build a tiny app into an image, run it as a container, open a port, read its logs, step inside it, and see why data vanishes when a container is deleted and how a volume keeps it.

Time30 minutes
StackPort 18110Ports 18110
MemoryAbout 30 MB
Before thisNothingStarts from zero
Free previewVerified runWindows, Mac, LinuxBash and PowerShell
  1. 1PrepareWhat you will learn
  2. 2PredictGuess before you run
  3. 3RunStep by step
  4. 4ObserveWhat you should see
  5. 5Break itChange one thing
  6. 6Clean upLeave nothing running
On this page
  1. 00 / What You Will Learn
  2. 01 / Why It Matters
  3. 02 / What We Are Building
  4. 03 / Words You Need
  5. 04 / Predict First
  6. 05 / Step by Step
  7. 06 / What You Should See
  8. 07 / Look Inside
  9. 08 / Break It, Fix It
  10. 09 / In Real Projects
  11. 10 / Interview Corner
  12. 11 / Clean Up

00 /What You Will Learn

By the end you will be able to
  • Say in one sentence what Docker is and why teams use it.
  • Tell an image from a container, and a container from a virtual machine.
  • Build your own image from a 4 line Dockerfile and start a container from it.
  • Open a port, read logs, and step inside a running container.
  • Explain why data disappears when a container is removed, and keep it with a volume.

Before you start

You need a laptop and Docker Desktop. That is all. On Windows, Docker Desktop also needs WSL2 (a small Linux that runs inside Windows), and the installer offers to set it up for you. After installing, open Docker Desktop and wait until it says it is running.

Check that it works. Open a terminal and type:

docker version

You should see two parts, Client and Server. If the Server part says it cannot connect, Docker Desktop is not running yet. Start it, wait a minute, and try again.

Windows tip

Use PowerShell, or Git Bash. In Git Bash a path such as /app inside a docker command can get rewritten to C:/Program Files/Git/app. If you see that, put MSYS_NO_PATHCONV=1 in front of the command, or switch to PowerShell.

01 /Why It Matters

Every developer has said it: "but it works on my machine". Your laptop has Python 3.11, your friend has 3.9, the server has 3.8, and the app breaks in a different way on each one. A new joiner loses two days just installing the right versions of the right tools.

Think of the Mumbai dabbawalas. They carry thousands of tiffin boxes every day and they never open one. The box is sealed, labelled and standard, so the dal, the rice and the sabzi inside do not matter to the carrier. Docker does the same for software. You pack your app and everything it needs into one sealed box. Any machine with Docker can carry that box and open it, and the app inside behaves the same way.

In plain words

Docker lets you ship an app together with the exact things it needs to run, so it behaves the same on your laptop, your friend's laptop and the production server.

Docker is not a virtual machine

A virtual machine (VM) is a full pretend computer with its own operating system. It is heavy: gigabytes of disk, a minute to start. A container shares your computer's operating system core and carries only your app and its libraries. That is why a container is small (this one is about 90 MB) and starts in about a second.

Virtual machineContainer
What it carriesA whole operating system plus your appOnly your app and its libraries
SizeGigabytesTens of megabytes
Start timeAbout a minuteAbout a second
IsolationVery strongGood, but shares the host's core

02 /What We Are Building

One tiny web app. It says hello and counts how many times you visited. It saves the count in a file. The count is the whole point: it shows what survives when a container is deleted and what does not.

Docker Basics topology Your browser curl / browser port 18110 Container basics-web app: server.py on 8080 image: desi-basics:1 Volume: basics-data Docker Engine runs this box

The parts

  • app/server.py: the web app (about 50 lines of Python, no extra libraries).
  • Dockerfile: the recipe that turns the app into an image.
  • Container basics-web: a running copy of that image.
  • Port 18110 on your laptop is connected to port 8080 inside the container.
  • Volume basics-data: a Docker-managed folder outside the container, mounted at /data. Added in the last steps.

03 /Words You Need

Read this table once. Every word comes back in the steps, and by the end it will feel natural.

WordPlain meaningTiffin box example
ImageA frozen, ready-to-run package: your app, its libraries and settings. You cannot change it while it runs.The sealed, packed tiffin
ContainerA running copy of an image. You can start many from one image.The tiffin on your desk, open
DockerfileA short text recipe that says how to build an image.The recipe card
Registry (Docker Hub)A website that stores images, so you can download them.The central kitchen
TagA label on an image, like python:3.11.17-alpine3.24 (name, colon, version).The sticker with the date
Port mappingConnects a port on your laptop to a port inside the container.The delivery window
VolumeA folder kept outside the container, so data survives when the container goes.Home kitchen, where the food really lives
Docker EngineThe program that builds images and runs containers. Docker Desktop installs it for you.The dabbawala system
IsolationHow well one running thing is kept apart from the others. Containers are well isolated, virtual machines even more.Separate tiffins in one bag

04 /Predict Before You Run

Guess first, then open the answer. Guessing wrong is useful: it shows you what to look for.

Question 1: You start two containers from the same image. Do they share anything?

No. Each container gets its own private files and its own running process. The image is shared and read-only. Think of two cooks using the same recipe card in two kitchens.

Question 2: You visit the app 3 times, then delete the container and start a new one from the same image. What does the counter show?

It shows 1. The count was saved in a file inside the old container, and deleting a container deletes its files. Only a volume survives. You will see this happen in step 5.

Question 3: You try to start a second container on the same laptop port 18110 while the first is running. What happens?

Docker refuses with "port is already allocated". One port can have only one owner at a time. This is the most common Docker error you will ever see.

05 /Step by Step

Step 0: Get the lab

Download the zip with the button at the top of this page. Unzip it into a new folder and open a terminal inside that folder. Every command below runs from there.

Which terminal are you using?
mkdir docker-basics && cd docker-basics
unzip ~/Downloads/docker-basics.zip
mkdir docker-basics; cd docker-basics
Expand-Archive -Path "$HOME/Downloads/docker-basics.zip" -DestinationPath .

Unzip the lab into a new folder and open a terminal in it. If you only want to watch it run with checks at the end of each step, run ./test-basics.sh (Mac, Linux, Git Bash) or .\test-basics.ps1 (PowerShell). To learn, type the steps yourself.

Step 1: Build the image

docker build -t desi-basics:1 .
docker images desi-basics
docker build -t desi-basics:1 .
docker images desi-basics
What each part does

docker build

Reads the Dockerfile in this folder and makes an image from it.

-t desi-basics:1

Gives the image a name (desi-basics) and a version tag (1).

. (the dot)

Means "use the files in this folder".

You should see: the build steps finish, then docker images lists desi-basics with tag 1 and a size of about 90 MB.

Step 2: Run a container

docker run -d --name basics-web -p 127.0.0.1:18110:8080 desi-basics:1
curl http://127.0.0.1:18110
docker run -d --name basics-web -p 127.0.0.1:18110:8080 desi-basics:1
curl.exe http://127.0.0.1:18110
What each part does

docker run

Makes a container from an image and starts it.

-d

Runs it in the background (detached), so your terminal stays free.

--name basics-web

A name you can type later instead of a long random ID.

-p 127.0.0.1:18110:8080

Connects port 18110 on your laptop to port 8080 inside the container. The 127.0.0.1 means only your own laptop can reach it.

You should see: a small JSON answer with "visits": 1 and a container_id. Run curl again and it becomes 2. On Windows, type curl.exe and not curl. PowerShell has its own command called curl that behaves differently.

Step 3: Look around

docker ps
docker logs basics-web
docker exec basics-web ls /app
docker ps
docker logs basics-web
docker exec basics-web ls /app
  • docker ps lists running containers. You should see basics-web and the port mapping.
  • docker logs shows what the app printed. You should see server starting on port 8080 and a request: line for every visit.
  • docker exec runs one command inside the running container. You should see server.py.

Want to walk inside? docker exec -it basics-web sh opens a shell. Type ls, look around, and type exit to come out. You will notice it is a tiny Linux with almost nothing in it.

Step 4: Break it, part 1. Take the same port twice

docker run -d --name basics-web-2 -p 127.0.0.1:18110:8080 desi-basics:1

You should see: an error ending in port is already allocated. Clean up the failed container with docker rm -f basics-web-2.

Step 5: Break it, part 2. Delete the container, lose the data

docker rm -f basics-web
docker run -d --name basics-web -p 127.0.0.1:18110:8080 desi-basics:1
curl http://127.0.0.1:18110
docker rm -f basics-web
docker run -d --name basics-web -p 127.0.0.1:18110:8080 desi-basics:1
curl.exe http://127.0.0.1:18110

You should see: "visits": 1 again. The old count lived inside the old container, and it went when the container went.

Step 6: Fix it with a volume

docker rm -f basics-web
docker run -d --name basics-web -p 127.0.0.1:18110:8080 -v basics-data:/data desi-basics:1
curl http://127.0.0.1:18110
curl http://127.0.0.1:18110
docker rm -f basics-web
docker run -d --name basics-web -p 127.0.0.1:18110:8080 -v basics-data:/data desi-basics:1
curl.exe http://127.0.0.1:18110
curl.exe http://127.0.0.1:18110

-v basics-data:/data mounts a Docker-managed volume at /data, the folder where the app saves its count. Now delete the container again and start a new one with the same -v option. You should see: the count continues instead of starting from 1. The data lives in the volume, so it outlives any container.

Why this matters

Anything a container must remember (a database, uploads, logs you need) goes in a volume. Anything else is disposable. This one rule prevents most "we lost our data after a redeploy" stories.

06 /What You Should See

This is the real output of the automated version of the lab (test-basics), recorded on a real run. Your numbers will differ in small ways, such as the exact counter values. Every line starting with [OK] is a check that passed.

Terminal · test-basics
== Step 1: is Docker alive? client 29.5.2, server 29.5.2 [OK] Docker answered == Step 2: build the image from the Dockerfile [OK] image desi-basics:1 exists == Step 3: run a container from it, with a port [OK] container answers on http://127.0.0.1:18110 == Step 4: look inside running: basics-web (desi-basics:1) 127.0.0.1:18110->8080/tcp [OK] docker logs shows the startup line [OK] docker exec can list files inside the container [OK] container runs as non-root user (UID 10001) == Step 5: break it. Same port twice [OK] second container refused: the port is already taken == Step 6: break it. Remove the container, lose the data [OK] no volume: counter restarted at 1 after docker rm == Step 7: fix it with a volume [OK] with a volume: counter continued from 3 to 4 after docker rm == Step 8: clean up [OK] removed containers, volume and image ALL STEPS PASSED
Observed on a laptop, not a production guarantee

The numbers above come from one run on one laptop with Docker Desktop. Your machine will show different timings and counters. What must match is the shape of the result, the [OK] lines.

07 /Look Inside

Docker keeps records of everything it does. These commands let you see them. Try them while the container from step 6 is still running.

1. See every container, even stopped ones

Run: docker ps -a

You should see: a table with the container name, its image, how long it has been up, and its ports.

It means: a container that stopped still exists until you remove it. docker rm is what deletes it.

2. See the volume

Run: docker volume ls and then docker volume inspect basics-data

You should see: a volume named basics-data, with a Mountpoint on Docker's own storage.

It means: the volume is an object by itself. Containers come and go, and it stays until you run docker volume rm.

3. See the layers of an image

Run: docker history desi-basics:1

You should see: one line for each instruction of the Dockerfile, with sizes.

It means: an image is a stack of layers. Docker reuses layers it already has, which is why a second build is much faster.

08 /Break It, Then Fix It

Predict: if you change the left number in -p 127.0.0.1:18110:8080 to 18111, which URL works now, and does the app inside need any change?

Try it:

docker rm -f basics-web
docker run -d --name basics-web -p 127.0.0.1:18111:8080 desi-basics:1
curl http://127.0.0.1:18111

What happened: the app listens on 8080 inside the container, always. The left number is only the door on your laptop. You can choose any free door without touching the app. That is the point of port mapping.

Stretch: edit the greeting in app/server.py, build the image again as desi-basics:2, and run it. Does the old desi-basics:1 still exist? (Yes: images are separate versions.)

09 /What Changes in Real Projects

  • Images come from a registry. You build once in CI and push to a registry. Servers pull the same image. Nobody builds on the production machine.
  • Pin the version. python:3.11.17-alpine3.24 is good. Floating tags like latest or 3.11 change under you when base images rebuild upstream.
  • Run as a non-root user. Containers default to root. If an attacker escapes your app, they have root capabilities on the container filesystem. Use USER 10001 in your Dockerfile. To verify who your container runs as, check docker exec <container> id -u; it must not print 0.
  • Add a .dockerignore file. Without .dockerignore, docker build sends your whole folder, including .git, .env files, temporary build files and secrets, into the build context. That slows builds down and risks leaking secrets into layers.
  • Scan images for vulnerabilities. Tools like docker scout quickview <image> (an optional feature in Docker Desktop, not run in CI here) check image packages against CVE databases before shipping.
  • Secrets handling. Passwords written in Compose files are for this lab only. Real systems read secrets from a secret manager or injected files, never from the repo.
  • Data goes in volumes or managed databases. A container is cattle, not a pet. If you cannot delete and recreate it without fear, something is stored in the wrong place.
  • One job per container. One container for the web app, another for the database, as you will do in the next lab.
  • Many containers on many machines are managed by Kubernetes or a similar system. Everything you learned here still applies inside it.
The tradeoff

You gained a box that runs the same everywhere. You gave up some simplicity: one more tool to learn, images that take disk space, and a new family of errors (ports, names, paths) that did not exist before. For one app on one laptop that is a small price. It pays back the first time a teammate runs your project in two minutes instead of two days.

10 /Interview Corner

Simple questions, and what a good answer sounds like.

  1. What is the difference between an image and a container? An image is the frozen package, a container is a running copy of it. One image can start many containers, like one recipe cooked in many kitchens.
  2. Why does data disappear when I remove a container? The container's files live in a writable layer that belongs to that container. Removing the container removes the layer. To keep data, store it in a volume or outside Docker.
  3. How is a container different from a virtual machine? A VM carries a full operating system. A container shares the host's operating system core and carries only the app, so it is smaller and starts faster. The price is weaker isolation.

Follow-up questions the interviewer will ask

  • What happens to a container's files when it restarts, and when it is removed?
  • Why do we map a port, and what would happen without -p?
  • What is the danger of using the latest tag in production?

11 /Clean Up

docker rm -f basics-web
docker volume rm basics-data
docker rmi desi-basics:1
docker rm -f basics-web
docker volume rm basics-data
docker rmi desi-basics:1

The automated script cleans up after itself. Next: Lab 01, Docker Compose Basics, where one file starts two containers that talk to each other.